Large-scale switch from String and Ascii to Text

This commit is contained in:
Michael Snoyman 2011-04-01 12:43:13 +03:00
parent 571ec80d16
commit b1abfd1a6a
9 changed files with 130 additions and 117 deletions

View File

@ -46,7 +46,6 @@ import Text.Hamlet
import Text.Cassius
import Text.Julius
import Text.Blaze (preEscapedLazyText, (!), customAttribute, textTag, toValue)
import qualified Data.Text as T
import qualified Text.Blaze.Html5 as TBH
import Data.Text.Lazy.Builder (toLazyText)
import Data.Text.Lazy.Encoding (encodeUtf8)
@ -56,11 +55,11 @@ import Web.Cookie (parseCookies)
import qualified Data.Map as Map
import Data.Time
import Network.HTTP.Types (encodePath)
import qualified Network.HTTP.Types as H
import qualified Data.Text as TS
import Data.Text (Text)
import qualified Data.Text.Encoding as TE
import Blaze.ByteString.Builder (Builder, fromByteString, toByteString)
import Blaze.ByteString.Builder (Builder, toByteString)
import Blaze.ByteString.Builder.Char.Utf8 (fromText)
import Data.List (foldl')
#if GHC7
@ -104,7 +103,7 @@ class RenderRoute (Route a) => Yesod a where
--
-- * You do not use any features that require absolute URLs, such as Atom
-- feeds and XML sitemaps.
approot :: a -> H.Ascii
approot :: a -> Text
-- | The encryption key to be used for encrypting client sessions.
-- Returning 'Nothing' disables sessions.
@ -215,10 +214,10 @@ class RenderRoute (Route a) => Yesod a where
-- file, whereas a 'Just' 'Right' gives the type-safe URL. The former is
-- necessary when you are serving the content outside the context of a
-- Yesod application, such as via memcached.
addStaticContent :: String -- ^ filename extension
-> String -- ^ mime-type
addStaticContent :: Text -- ^ filename extension
-> Text -- ^ mime-type
-> L.ByteString -- ^ content
-> GHandler sub a (Maybe (Either String (Route a, [(String, String)])))
-> GHandler sub a (Maybe (Either Text (Route a, [(Text, Text)])))
addStaticContent _ _ _ = return Nothing
-- | Whether or not to tie a session to a specific IP address. Defaults to
@ -292,7 +291,7 @@ defaultYesodRunner s master toMasterRoute mkey murl handler req = do
hs'' = map (headerToPair getExpires) hs'
hs''' = ("Content-Type", ct) : hs''
data AuthResult = Authorized | AuthenticationRequired | Unauthorized String
data AuthResult = Authorized | AuthenticationRequired | Unauthorized Text
deriving (Eq, Show, Read)
-- | A type-safe, concise method of creating breadcrumbs for pages. For each
@ -408,6 +407,7 @@ widgetToPageContent (GWidget w) = do
let title = maybe mempty unTitle mTitle
let scripts = runUniqueList scripts'
let stylesheets = runUniqueList stylesheets'
-- FIXME check size of cassius/julius template
let cssToHtml = preEscapedLazyText . renderCss
celper :: Cassius url -> Hamlet url
celper = fmap cssToHtml
@ -415,8 +415,7 @@ widgetToPageContent (GWidget w) = do
jelper :: Julius url -> Hamlet url
jelper = fmap jsToHtml
renderFIXME <- getUrlRenderParams
let render a b = renderFIXME a $ map (TS.pack *** TS.pack) b
render <- getUrlRenderParams
let renderLoc x =
case x of
Nothing -> Nothing
@ -441,9 +440,13 @@ widgetToPageContent (GWidget w) = do
let renderLoc' render' (Local url) = render' url []
renderLoc' _ (Remote s) = s
let mkScriptTag (Script loc attrs) render' =
foldl' addAttr TBH.script (("src", T.pack $ renderLoc' render' loc) : attrs) $ return ()
foldl' addAttr TBH.script (("src", renderLoc' render' loc) : attrs) $ return ()
let mkLinkTag (Stylesheet loc attrs) render' =
foldl' addAttr TBH.link (("rel", "stylesheet") : ("href", T.pack $ renderLoc' render' loc) : attrs)
foldl' addAttr TBH.link
( ("rel", "stylesheet")
: ("href", renderLoc' render' loc)
: attrs
)
let head'' =
#if GHC7
[hamlet|
@ -475,11 +478,11 @@ yesodRender :: Yesod y
=> y
-> Route y
-> [(Text, Text)]
-> String -- FIXME
-> Text
yesodRender y u qs =
S8.unpack $ toByteString $
TE.decodeUtf8 $ toByteString $
fromMaybe
(joinPath y (fromByteString $ approot y) ps
(joinPath y (fromText $ approot y) ps
$ qs ++ qs')
(urlRenderOverride y u)
where

View File

@ -41,6 +41,7 @@ module Yesod.Handler
, redirect
, redirectParams
, redirectString
, redirectText
, redirectToPost
-- ** Errors
, notFound
@ -124,6 +125,12 @@ import qualified Network.HTTP.Types as H
import Control.Failure (Failure (failure))
import Text.Hamlet
import Text.Blaze (preEscapedText)
import qualified Text.Blaze.Renderer.Text
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8, decodeUtf8With)
import Data.Text.Encoding.Error (lenientDecode)
import qualified Data.Text.Lazy as TL
import Control.Monad.IO.Control (MonadControlIO)
import Control.Monad.Trans.Control (MonadTransControl, liftControl, control)
@ -144,7 +151,6 @@ import qualified Data.ByteString.Char8 as S8
import Data.CaseInsensitive (CI)
import Blaze.ByteString.Builder (toByteString)
import Data.Text (Text)
import qualified Data.Text as TS
-- | The type-safe URLs associated with a site argument.
type family Route a
@ -157,7 +163,7 @@ data HandlerData sub master = HandlerData
, handlerSub :: sub
, handlerMaster :: master
, handlerRoute :: Maybe (Route sub)
, handlerRender :: (Route master -> [(Text, Text)] -> String) -- FIXME replace output String with Ascii
, handlerRender :: (Route master -> [(Text, Text)] -> Text)
, handlerToMaster :: Route sub -> Route master
}
@ -251,7 +257,7 @@ type GHInner s m monad = -- FIXME collapse the stack
monad
))))
type SessionMap = Map.Map String String
type SessionMap = Map.Map Text Text
type Endo a = a -> a
@ -274,13 +280,13 @@ data YesodAppResult
data HandlerContents =
HCContent H.Status ChooseRep
| HCError ErrorResponse
| HCSendFile ContentType FilePath
| HCRedirect RedirectType H.Ascii
| HCCreated H.Ascii
| HCSendFile ContentType FilePath -- FIXME replace FilePath with opaque type from system-filepath?
| HCRedirect RedirectType Text
| HCCreated Text
| HCWai W.Response
instance Error HandlerContents where
strMsg = HCError . InternalError
strMsg = HCError . InternalError . T.pack
instance Monad monad => Failure ErrorResponse (GGHandler sub master monad) where
failure = GHandler . lift . throwError . HCError
@ -301,9 +307,10 @@ rbHelper req =
(map fix1 *** map fix2) <$> iter
where
iter = NWP.parseRequestBody NWP.lbsSink req
fix1 = bsToChars *** bsToChars
fix1 = go *** go
fix2 (x, NWP.FileInfo a b c) =
(bsToChars x, FileInfo (bsToChars a) (bsToChars b) c)
(go x, FileInfo (go a) (go b) c)
go = decodeUtf8With lenientDecode
-- | Get the sub application argument.
getYesodSub :: Monad m => GGHandler sub master m sub
@ -314,7 +321,7 @@ getYesod :: Monad m => GGHandler sub master m master
getYesod = handlerMaster `liftM` GHandler ask
-- | Get the URL rendering function.
getUrlRender :: Monad m => GGHandler sub master m (Route master -> String)
getUrlRender :: Monad m => GGHandler sub master m (Route master -> Text)
getUrlRender = do
x <- handlerRender `liftM` GHandler ask
return $ flip x []
@ -322,7 +329,7 @@ getUrlRender = do
-- | The URL rendering function with query-string parameters.
getUrlRenderParams
:: Monad m
=> GGHandler sub master m (Route master -> [(Text, Text)] -> String)
=> GGHandler sub master m (Route master -> [(Text, Text)] -> Text)
getUrlRenderParams = handlerRender `liftM` GHandler ask
-- | Get the route requested by the user. If this is a 404 response- where the
@ -339,7 +346,7 @@ getRouteToMaster = handlerToMaster `liftM` GHandler ask
-- 'GHandler' into an 'W.Application'. Should not be needed by users.
runHandler :: HasReps c
=> GHandler sub master c
-> (Route master -> [(Text, Text)] -> String)
-> (Route master -> [(Text, Text)] -> Text)
-> Maybe (Route sub)
-> (Route sub -> Route master)
-> master
@ -350,7 +357,7 @@ runHandler handler mrender sroute tomr ma sa =
let toErrorHandler e =
case fromException e of
Just x -> x
Nothing -> InternalError $ show e
Nothing -> InternalError $ T.pack $ show e
let hd = HandlerData
{ handlerRequest = rr
, handlerSub = sa
@ -384,7 +391,7 @@ runHandler handler mrender sroute tomr ma sa =
return $ YARPlain status (headers []) ct c finalSession
HCError e -> handleError e
HCRedirect rt loc -> do
let hs = Header "Location" loc : headers []
let hs = Header "Location" (encodeUtf8 loc) : headers []
return $ YARPlain
(getRedirectStatus rt) hs typePlain emptyContent
finalSession
@ -392,7 +399,7 @@ runHandler handler mrender sroute tomr ma sa =
(sendFile' ct fp)
(handleError . toErrorHandler)
HCCreated loc -> do
let hs = Header "Location" loc : headers []
let hs = Header "Location" (encodeUtf8 loc) : headers []
return $ YARPlain
H.status201
hs
@ -427,13 +434,15 @@ redirectParams :: Monad mo
-> GGHandler sub master mo a
redirectParams rt url params = do
r <- getUrlRenderParams
redirectString rt $ S8.pack $ r url params
redirectString rt $ r url params
-- | Redirect to the given URL.
redirectString :: Monad mo => RedirectType -> H.Ascii -> GGHandler sub master mo a
redirectString rt = GHandler . lift . throwError . HCRedirect rt
redirectString, redirectText :: Monad mo => RedirectType -> Text -> GGHandler sub master mo a
redirectText rt = GHandler . lift . throwError . HCRedirect rt
redirectString = redirectText
{-# DEPRECATED redirectString "Use redirectText instead" #-}
ultDestKey :: String
ultDestKey :: Text
ultDestKey = "_ULT"
-- | Sets the ultimate destination variable to the given route.
@ -446,7 +455,7 @@ setUltDest dest = do
setUltDestString $ render dest
-- | Same as 'setUltDest', but use the given string.
setUltDestString :: Monad mo => String -> GGHandler sub master mo ()
setUltDestString :: Monad mo => Text -> GGHandler sub master mo ()
setUltDestString = setSession ultDestKey
-- | Same as 'setUltDest', but uses the current page.
@ -462,8 +471,7 @@ setUltDest' = do
tm <- getRouteToMaster
gets' <- reqGetParams `liftM` handlerRequest `liftM` GHandler ask
render <- getUrlRenderParams
let renderFIXME a b = render a $ map (TS.pack *** TS.pack) b
setUltDestString $ renderFIXME (tm r) gets'
setUltDestString $ render (tm r) gets'
-- | Redirect to the ultimate destination in the user's session. Clear the
-- value from the session.
@ -476,16 +484,16 @@ redirectUltDest :: Monad mo
redirectUltDest rt def = do
mdest <- lookupSession ultDestKey
deleteSession ultDestKey
maybe (redirect rt def) (redirectString rt . S8.pack) mdest
maybe (redirect rt def) (redirectText rt) mdest
msgKey :: String
msgKey :: Text
msgKey = "_MSG"
-- | Sets a message in the user's session.
--
-- See 'getMessage'.
setMessage :: Monad mo => Html -> GGHandler sub master mo ()
setMessage = setSession msgKey . lbsToChars . renderHtml
setMessage = setSession msgKey . T.concat . TL.toChunks . Text.Blaze.Renderer.Text.renderHtml
-- | Gets the message in the user's session, if available, and then clears the
-- variable.
@ -493,7 +501,7 @@ setMessage = setSession msgKey . lbsToChars . renderHtml
-- See 'setMessage'.
getMessage :: Monad mo => GGHandler sub master mo (Maybe Html)
getMessage = do
mmsg <- liftM (fmap preEscapedString) $ lookupSession msgKey
mmsg <- liftM (fmap preEscapedText) $ lookupSession msgKey
deleteSession msgKey
return mmsg
@ -521,7 +529,7 @@ sendResponseStatus s = GHandler . lift . throwError . HCContent s
sendResponseCreated :: Monad mo => Route m -> GGHandler s m mo a
sendResponseCreated url = do
r <- getUrlRender
GHandler $ lift $ throwError $ HCCreated $ S8.pack $ r url
GHandler $ lift $ throwError $ HCCreated $ r url
-- | Send a 'W.Response'. Please note: this function is rarely
-- necessary, and will /disregard/ any changes to response headers and session
@ -542,11 +550,11 @@ badMethod = do
failure $ BadMethod $ W.requestMethod w
-- | Return a 403 permission denied page.
permissionDenied :: Failure ErrorResponse m => String -> m a
permissionDenied :: Failure ErrorResponse m => Text -> m a
permissionDenied = failure . PermissionDenied
-- | Return a 400 invalid arguments page.
invalidArgs :: Failure ErrorResponse m => [String] -> m a
invalidArgs :: Failure ErrorResponse m => [Text] -> m a
invalidArgs = failure . InvalidArgs
------- Headers
@ -564,8 +572,8 @@ deleteCookie = addHeader . DeleteCookie
-- | Set the language in the user session. Will show up in 'languages' on the
-- next request.
setLanguage :: Monad mo => String -> GGHandler sub master mo ()
setLanguage = setSession $ S8.unpack langKey
setLanguage :: Monad mo => Text -> GGHandler sub master mo ()
setLanguage = setSession langKey
-- | Set an arbitrary response header.
setHeader :: Monad mo
@ -601,13 +609,13 @@ expiresAt = setHeader "Expires" . S8.pack . formatRFC1123
-- and hashed cookie on the client. This ensures that all data is secure and
-- not tampered with.
setSession :: Monad mo
=> String -- ^ key
-> String -- ^ value
=> Text -- ^ key
-> Text -- ^ value
-> GGHandler sub master mo ()
setSession k = GHandler . lift . lift . lift . modify . modSession . Map.insert k
-- | Unsets a session variable. See 'setSession'.
deleteSession :: Monad mo => String -> GGHandler sub master mo ()
deleteSession :: Monad mo => Text -> GGHandler sub master mo ()
deleteSession = GHandler . lift . lift . lift . modify . modSession . Map.delete
modSession :: (SessionMap -> SessionMap) -> GHState -> GHState
@ -640,7 +648,7 @@ localNoCurrent =
GHandler . local (\hd -> hd { handlerRoute = Nothing }) . unGHandler
-- | Lookup for session data.
lookupSession :: Monad mo => ParamName -> GGHandler s m mo (Maybe ParamValue)
lookupSession :: Monad mo => Text -> GGHandler s m mo (Maybe Text)
lookupSession n = GHandler $ do
m <- liftM ghsSession $ lift $ lift $ lift get
return $ Map.lookup n m
@ -653,7 +661,7 @@ handlerToYAR :: (HasReps a, HasReps b)
=> m -- ^ master site foundation
-> s -- ^ sub site foundation
-> (Route s -> Route m)
-> (Route m -> [(Text, Text)] -> String) -- ^ url render FIXME
-> (Route m -> [(Text, Text)] -> Text)
-> (ErrorResponse -> GHandler s m a)
-> Request
-> Maybe (Route s)
@ -782,8 +790,7 @@ hamletToContent :: Monad mo
=> Hamlet (Route master) -> GGHandler sub master mo Content
hamletToContent h = do
render <- getUrlRenderParams
let renderFIXME a b = render a $ map (TS.pack *** TS.pack) b
return $ toContent $ h renderFIXME
return $ toContent $ h render
-- | Wraps the 'Content' generated by 'hamletToContent' in a 'RepHtml'.
hamletToRepHtml :: Monad mo

View File

@ -41,6 +41,7 @@ import Data.List (nub)
import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy as L
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.Text.Encoding.Error as T
@ -54,6 +55,7 @@ import Control.Exception (Exception)
import qualified Network.HTTP.Types as H
import qualified Network.HTTP.Types as A
import Data.CaseInsensitive (CI)
import Data.String (IsString)
#if GHC7
#define HAMLET hamlet
@ -65,9 +67,9 @@ import Data.CaseInsensitive (CI)
-- from 'SpecialResponse' in that they allow for custom error pages.
data ErrorResponse =
NotFound
| InternalError String
| InvalidArgs [String]
| PermissionDenied String
| InternalError Text
| InvalidArgs [Text]
| PermissionDenied Text
| BadMethod H.Method
deriving (Show, Eq, Typeable)
instance Exception ErrorResponse
@ -80,10 +82,10 @@ data Header =
| Header (CI A.Ascii) A.Ascii
deriving (Eq, Show)
langKey :: A.Ascii
langKey :: IsString a => a
langKey = "_LANG"
data Location url = Local url | Remote String -- FIXME Text
data Location url = Local url | Remote Text
deriving (Show, Eq)
locationToHamlet :: Location url -> Hamlet url
locationToHamlet (Local url) = [HAMLET|\@{url}
@ -111,6 +113,7 @@ newtype Head url = Head (Hamlet url)
newtype Body url = Body (Hamlet url)
deriving Monoid
-- FIXME remove these functions
lbsToChars :: L.ByteString -> String
lbsToChars = LT.unpack . LT.decodeUtf8With T.lenientDecode
@ -120,10 +123,10 @@ bsToChars = T.unpack . T.decodeUtf8With T.lenientDecode
charsToBs :: String -> S.ByteString
charsToBs = T.encodeUtf8 . T.pack
nonceKey :: String
nonceKey :: IsString a => a
nonceKey = "_NONCE"
sessionName :: A.Ascii
sessionName :: IsString a => a
sessionName = "_SESSION"
data GWData a = GWData

View File

@ -24,6 +24,7 @@ import Data.Text (Text)
import Data.Monoid (mappend)
import qualified Blaze.ByteString.Builder
import qualified Blaze.ByteString.Builder.Char8
import Blaze.ByteString.Builder.Char.Utf8 (fromText)
import qualified Data.ByteString.Char8 as S8
{-|
@ -86,7 +87,7 @@ sendRedirect y segments' env =
, ("Location", Blaze.ByteString.Builder.toByteString dest')
] "Redirecting"
where
dest = joinPath y (Blaze.ByteString.Builder.fromByteString $ approot y) segments' []
dest = joinPath y (fromText $ approot y) segments' []
dest' =
if S.null (W.rawQueryString env)
then dest

View File

@ -4,34 +4,37 @@ module Yesod.Internal.Request
) where
import Yesod.Request
import Control.Arrow (first, (***))
import Control.Arrow (first, second)
import qualified Network.Wai.Parse as NWP
import Yesod.Internal
import qualified Network.Wai as W
import System.Random (randomR, newStdGen)
import Web.Cookie (parseCookies)
import Web.Cookie (parseCookiesText)
import Data.Monoid (mempty)
import qualified Data.ByteString.Char8 as S8
import Data.Text (Text, pack)
import Network.HTTP.Types (queryToQueryText)
import Control.Monad (join)
import Data.Maybe (fromMaybe)
parseWaiRequest :: W.Request
-> [(String, String)] -- ^ session
-> [(Text, Text)] -- ^ session
-> Maybe a
-> IO Request
parseWaiRequest env session' key' = do
let gets' = map (bsToChars *** maybe "" bsToChars)
$ W.queryString env
let gets' = queryToQueryText $ W.queryString env
let reqCookie = maybe mempty id $ lookup "Cookie"
$ W.requestHeaders env
cookies' = parseCookies reqCookie
cookies' = parseCookiesText reqCookie
acceptLang = lookup "Accept-Language" $ W.requestHeaders env
langs = map S8.unpack $ maybe [] NWP.parseHttpAccept acceptLang
langs' = case lookup (S8.unpack langKey) session' of
langs = map (pack . S8.unpack) $ maybe [] NWP.parseHttpAccept acceptLang
langs' = case lookup langKey session' of
Nothing -> langs
Just x -> x : langs
langs'' = case lookup langKey cookies' of
Nothing -> langs'
Just x -> S8.unpack x : langs'
langs''' = case lookup (S8.unpack langKey) gets' of
Just x -> x : langs'
langs''' = case join $ lookup langKey gets' of
Nothing -> langs''
Just x -> x : langs''
nonce <- case (key', lookup nonceKey session') of
@ -39,8 +42,9 @@ parseWaiRequest env session' key' = do
(_, Just x) -> return $ Just x
(_, Nothing) -> do
g <- newStdGen
return $ Just $ fst $ randomString 10 g
return $ Request gets' cookies' env langs''' nonce
return $ Just $ pack $ fst $ randomString 10 g
let gets'' = map (second $ fromMaybe "") gets'
return $ Request gets'' cookies' env langs''' nonce
where
randomString len =
first (map toChar) . sequence' (replicate len (randomR (0, 61)))

View File

@ -8,11 +8,13 @@ import Data.Serialize
import Data.Time
import Data.ByteString (ByteString)
import Control.Monad (guard)
import Data.Text (Text, pack, unpack)
import Control.Arrow ((***))
encodeSession :: CS.Key
-> UTCTime -- ^ expire time
-> ByteString -- ^ remote host
-> [(String, String)] -- ^ session
-> [(Text, Text)] -- ^ session
-> ByteString -- ^ cookie value
encodeSession key expire rhost session' =
CS.encrypt key $ encode $ SessionCookie expire rhost session'
@ -21,7 +23,7 @@ decodeSession :: CS.Key
-> UTCTime -- ^ current time
-> ByteString -- ^ remote host field
-> ByteString -- ^ cookie value
-> Maybe [(String, String)]
-> Maybe [(Text, Text)]
decodeSession key now rhost encrypted = do
decrypted <- CS.decrypt key encrypted
SessionCookie expire rhost' session' <-
@ -30,14 +32,14 @@ decodeSession key now rhost encrypted = do
guard $ rhost' == rhost
return session'
data SessionCookie = SessionCookie UTCTime ByteString [(String, String)]
data SessionCookie = SessionCookie UTCTime ByteString [(Text, Text)]
deriving (Show, Read)
instance Serialize SessionCookie where
put (SessionCookie a b c) = putTime a >> put b >> put c
put (SessionCookie a b c) = putTime a >> put b >> put (map (unpack *** unpack) c)
get = do
a <- getTime
b <- get
c <- get
c <- map (pack *** pack) `fmap` get
return $ SessionCookie a b c
putTime :: Putter UTCTime

View File

@ -31,10 +31,6 @@ module Yesod.Request
, lookupPostParams
, lookupCookies
, lookupFiles
-- * Parameter type synonyms
, ParamName
, ParamValue
, ParamError
) where
import qualified Network.Wai as W
@ -43,11 +39,7 @@ import Control.Monad.IO.Class
import Control.Monad (liftM)
import Control.Monad.Instances () -- I'm missing the instance Monad ((->) r
import Data.Maybe (listToMaybe)
import qualified Network.HTTP.Types as A
type ParamName = String
type ParamValue = String
type ParamError = String
import Data.Text (Text)
-- FIXME perhaps remove RequestReader typeclass, include Request datatype in Handler
@ -70,7 +62,7 @@ class Monad m => RequestReader m where
-- * Accept-Language HTTP header.
--
-- This is handled by parseWaiRequest (not exposed).
languages :: RequestReader m => m [String]
languages :: RequestReader m => m [Text]
languages = reqLangs `liftM` getRequest
-- | Get the request\'s 'W.Request' value.
@ -79,74 +71,74 @@ waiRequest = reqWaiRequest `liftM` getRequest
-- | A tuple containing both the POST parameters and submitted files.
type RequestBodyContents =
( [(ParamName, ParamValue)]
, [(ParamName, FileInfo)]
( [(Text, Text)]
, [(Text, FileInfo)]
)
data FileInfo = FileInfo
{ fileName :: String
, fileContentType :: String
{ fileName :: Text
, fileContentType :: Text
, fileContent :: BL.ByteString
}
deriving (Eq, Show)
-- | The parsed request information.
data Request = Request
{ reqGetParams :: [(ParamName, ParamValue)]
, reqCookies :: [(A.Ascii, A.Ascii)]
{ reqGetParams :: [(Text, Text)]
, reqCookies :: [(Text, Text)]
, reqWaiRequest :: W.Request
-- | Languages which the client supports.
, reqLangs :: [String]
, reqLangs :: [Text]
-- | A random, session-specific nonce used to prevent CSRF attacks.
, reqNonce :: Maybe String
, reqNonce :: Maybe Text
}
lookup' :: Eq a => a -> [(a, b)] -> [b]
lookup' a = map snd . filter (\x -> a == fst x)
-- | Lookup for GET parameters.
lookupGetParams :: RequestReader m => ParamName -> m [ParamValue]
lookupGetParams :: RequestReader m => Text -> m [Text]
lookupGetParams pn = do
rr <- getRequest
return $ lookup' pn $ reqGetParams rr
-- | Lookup for GET parameters.
lookupGetParam :: RequestReader m => ParamName -> m (Maybe ParamValue)
lookupGetParam :: RequestReader m => Text -> m (Maybe Text)
lookupGetParam = liftM listToMaybe . lookupGetParams
-- | Lookup for POST parameters.
lookupPostParams :: RequestReader m
=> ParamName
-> m [ParamValue]
=> Text
-> m [Text]
lookupPostParams pn = do
(pp, _) <- runRequestBody
return $ lookup' pn pp
lookupPostParam :: (MonadIO m, RequestReader m)
=> ParamName
-> m (Maybe ParamValue)
=> Text
-> m (Maybe Text)
lookupPostParam = liftM listToMaybe . lookupPostParams
-- | Lookup for POSTed files.
lookupFile :: (MonadIO m, RequestReader m)
=> ParamName
=> Text
-> m (Maybe FileInfo)
lookupFile = liftM listToMaybe . lookupFiles
-- | Lookup for POSTed files.
lookupFiles :: RequestReader m
=> ParamName
=> Text
-> m [FileInfo]
lookupFiles pn = do
(_, files) <- runRequestBody
return $ lookup' pn files
-- | Lookup for cookie data.
lookupCookie :: RequestReader m => A.Ascii -> m (Maybe A.Ascii)
lookupCookie :: RequestReader m => Text -> m (Maybe Text)
lookupCookie = liftM listToMaybe . lookupCookies
-- | Lookup for cookie data.
lookupCookies :: RequestReader m => A.Ascii -> m [A.Ascii]
lookupCookies :: RequestReader m => Text -> m [Text]
lookupCookies pn = do
rr <- getRequest
return $ lookup' pn $ reqCookies rr

View File

@ -38,6 +38,7 @@ module Yesod.Widget
import Data.Monoid
import Control.Monad.Trans.RWS
import Text.Blaze (preEscapedText)
import Text.Hamlet
import Text.Cassius
import Text.Julius
@ -75,7 +76,7 @@ instance (Monad monad, a ~ ()) => HamletValue (GGWidget s m monad a) where
toHamletValue = runGWidget'
htmlToHamletMonad = GWidget' . addHtml
urlToHamletMonad url params = GWidget' $
addHamlet $ \r -> preEscapedString (r url params)
addHamlet $ \r -> preEscapedText (r url params)
fromHamletValue = GWidget'
instance (Monad monad, a ~ ()) => Monad (HamletMonad (GGWidget s m monad a)) where
return = GWidget' . return
@ -130,17 +131,17 @@ addStylesheetAttrs :: Monad m => Route master -> [(Text, Text)] -> GGWidget sub
addStylesheetAttrs x y = GWidget $ tell $ GWData mempty mempty mempty (toUnique $ Stylesheet (Local x) y) mempty mempty mempty
-- | Link to the specified remote stylesheet.
addStylesheetRemote :: Monad m => String -> GGWidget sub master m ()
addStylesheetRemote :: Monad m => Text -> GGWidget sub master m ()
addStylesheetRemote = flip addStylesheetRemoteAttrs []
-- | Link to the specified remote stylesheet.
addStylesheetRemoteAttrs :: Monad m => String -> [(Text, Text)] -> GGWidget sub master m ()
addStylesheetRemoteAttrs :: Monad m => Text -> [(Text, Text)] -> GGWidget sub master m ()
addStylesheetRemoteAttrs x y = GWidget $ tell $ GWData mempty mempty mempty (toUnique $ Stylesheet (Remote x) y) mempty mempty mempty
addStylesheetEither :: Monad m => Either (Route master) String -> GGWidget sub master m ()
addStylesheetEither :: Monad m => Either (Route master) Text -> GGWidget sub master m ()
addStylesheetEither = either addStylesheet addStylesheetRemote
addScriptEither :: Monad m => Either (Route master) String -> GGWidget sub master m ()
addScriptEither :: Monad m => Either (Route master) Text -> GGWidget sub master m ()
addScriptEither = either addScript addScriptRemote
-- | Link to the specified local script.
@ -152,11 +153,11 @@ addScriptAttrs :: Monad m => Route master -> [(Text, Text)] -> GGWidget sub mast
addScriptAttrs x y = GWidget $ tell $ GWData mempty mempty (toUnique $ Script (Local x) y) mempty mempty mempty mempty
-- | Link to the specified remote script.
addScriptRemote :: Monad m => String -> GGWidget sub master m ()
addScriptRemote :: Monad m => Text -> GGWidget sub master m ()
addScriptRemote = flip addScriptRemoteAttrs []
-- | Link to the specified remote script.
addScriptRemoteAttrs :: Monad m => String -> [(Text, Text)] -> GGWidget sub master m ()
addScriptRemoteAttrs :: Monad m => Text -> [(Text, Text)] -> GGWidget sub master m ()
addScriptRemoteAttrs x y = GWidget $ tell $ GWData mempty mempty (toUnique $ Script (Remote x) y) mempty mempty mempty mempty
-- | Include raw Javascript in the page's script tag.

View File

@ -8,12 +8,12 @@ synopsis: Creation of type-safe, RESTful web applications.
description:
Yesod is a framework designed to foster creation of RESTful web application that have strong compile-time guarantees of correctness. It also affords space efficient code and portability to many deployment backends, from CGI to stand-alone serving.
.
The Yesod documentation site <http://docs.yesodweb.com/> has much more information, tutorials and information on some of the supporting packages, like Hamlet and web-routes-quasi.
The Yesod documentation site <http://www.yesodweb.com/> has much more information, tutorials and information on some of the supporting packages, like Hamlet and web-routes-quasi.
category: Web, Yesod
stability: Stable
cabal-version: >= 1.6
build-type: Simple
homepage: http://docs.yesodweb.com/
homepage: http://www.yesodweb.com/
flag test
description: Build the executable to run unit tests
@ -34,7 +34,7 @@ library
, text >= 0.5 && < 0.12
, template-haskell
, web-routes-quasi >= 0.7 && < 0.8
, hamlet >= 0.7.3 && < 0.8
, hamlet >= 0.8 && < 0.9
, blaze-builder >= 0.2.1 && < 0.4
, transformers >= 0.2 && < 0.3
, clientsession >= 0.6 && < 0.7
@ -45,7 +45,7 @@ library
, containers >= 0.2 && < 0.5
, monad-control >= 0.2 && < 0.3
, enumerator >= 0.4.7 && < 0.5
, cookie >= 0.2 && < 0.3
, cookie >= 0.2.1 && < 0.3
, blaze-html >= 0.4 && < 0.5
, http-types >= 0.6 && < 0.7
, case-insensitive >= 0.2 && < 0.3