Deeply evaluate session and headers #712

This commit is contained in:
Michael Snoyman 2014-04-10 20:21:49 +03:00
parent c44a48c8ae
commit 4dc7a1258c
3 changed files with 32 additions and 9 deletions

View File

@ -48,6 +48,7 @@ import Yesod.Core.Types
import Yesod.Core.Internal.Request (parseWaiRequest, import Yesod.Core.Internal.Request (parseWaiRequest,
tooLargeResponse) tooLargeResponse)
import Yesod.Routes.Class (Route, renderRoute) import Yesod.Routes.Class (Route, renderRoute)
import Control.DeepSeq (($!!))
-- | Function used internally by Yesod in the process of converting a -- | Function used internally by Yesod in the process of converting a
-- 'HandlerT' into an 'Application'. Should not be needed by users. -- 'HandlerT' into an 'Application'. Should not be needed by users.
@ -78,23 +79,38 @@ runHandler rhe@RunHandlerEnv {..} handler yreq = withInternalState $ \resState -
(\e -> return $ Left $ maybe (HCError $ toErrorHandler e) id (\e -> return $ Left $ maybe (HCError $ toErrorHandler e) id
$ fromException e) $ fromException e)
state <- liftIO $ I.readIORef istate state <- liftIO $ I.readIORef istate
let finalSession = ghsSession state
let headers = ghsHeaders state (finalSession, mcontents1) <- (do
let contents = either id (HCContent defaultStatus . toTypedContent) contents' finalSession <- return $!! ghsSession state
return (finalSession, Nothing)) `E.catch` \e -> return
(Map.empty, Just $! HCError $! InternalError $! T.pack $! show (e :: E.SomeException))
(headers, mcontents2) <- (do
headers <- return $!! appEndo (ghsHeaders state) []
return (headers, Nothing)) `E.catch` \e -> return
([], Just $! HCError $! InternalError $! T.pack $! show (e :: E.SomeException))
let contents =
case mcontents1 of
Just x -> x
Nothing ->
case mcontents2 of
Just x -> x
Nothing -> either id (HCContent defaultStatus . toTypedContent) contents'
let handleError e = flip runInternalState resState $ do let handleError e = flip runInternalState resState $ do
yar <- rheOnError e yreq yar <- rheOnError e yreq
{ reqSession = finalSession { reqSession = finalSession
} }
case yar of case yar of
YRPlain status' hs ct c sess -> YRPlain status' hs ct c sess ->
let hs' = appEndo headers hs let hs' = headers ++ hs
status status
| status' == defaultStatus = getStatus e | status' == defaultStatus = getStatus e
| otherwise = status' | otherwise = status'
in return $ YRPlain status hs' ct c sess in return $ YRPlain status hs' ct c sess
YRWai _ -> return yar YRWai _ -> return yar
let sendFile' ct fp p = let sendFile' ct fp p =
return $ YRPlain H.status200 (appEndo headers []) ct (ContentFile fp p) finalSession return $ YRPlain H.status200 headers ct (ContentFile fp p) finalSession
contents1 <- evaluate contents `E.catch` \e -> return contents1 <- evaluate contents `E.catch` \e -> return
(HCError $! InternalError $! T.pack $! show (e :: E.SomeException)) (HCError $! InternalError $! T.pack $! show (e :: E.SomeException))
case contents1 of case contents1 of
@ -102,7 +118,7 @@ runHandler rhe@RunHandlerEnv {..} handler yreq = withInternalState $ \resState -
ec' <- liftIO $ evaluateContent c ec' <- liftIO $ evaluateContent c
case ec' of case ec' of
Left e -> handleError e Left e -> handleError e
Right c' -> return $ YRPlain status (appEndo headers []) ct c' finalSession Right c' -> return $ YRPlain status headers ct c' finalSession
HCError e -> handleError e HCError e -> handleError e
HCRedirect status loc -> do HCRedirect status loc -> do
let disable_caching x = let disable_caching x =
@ -110,7 +126,7 @@ runHandler rhe@RunHandlerEnv {..} handler yreq = withInternalState $ \resState -
: Header "Expires" "Thu, 01 Jan 1970 05:05:05 GMT" : Header "Expires" "Thu, 01 Jan 1970 05:05:05 GMT"
: x : x
hs = (if status /= H.movedPermanently301 then disable_caching else id) hs = (if status /= H.movedPermanently301 then disable_caching else id)
$ Header "Location" (encodeUtf8 loc) : appEndo headers [] $ Header "Location" (encodeUtf8 loc) : headers
return $ YRPlain return $ YRPlain
status hs typePlain emptyContent status hs typePlain emptyContent
finalSession finalSession
@ -118,7 +134,7 @@ runHandler rhe@RunHandlerEnv {..} handler yreq = withInternalState $ \resState -
(sendFile' ct fp p) (sendFile' ct fp p)
(handleError . toErrorHandler) (handleError . toErrorHandler)
HCCreated loc -> do HCCreated loc -> do
let hs = Header "Location" (encodeUtf8 loc) : appEndo headers [] let hs = Header "Location" (encodeUtf8 loc) : headers
return $ YRPlain return $ YRPlain
H.status201 H.status201
hs hs

View File

@ -64,6 +64,7 @@ import Control.Monad.Trans.Class (MonadTrans (..))
import Yesod.Routes.Class (RenderRoute (..), ParseRoute (..)) import Yesod.Routes.Class (RenderRoute (..), ParseRoute (..))
import Control.Monad.Reader (MonadReader (..)) import Control.Monad.Reader (MonadReader (..))
import Prelude hiding (catch) import Prelude hiding (catch)
import Control.DeepSeq (NFData (rnf))
-- Sessions -- Sessions
type SessionMap = Map Text ByteString type SessionMap = Map Text ByteString
@ -312,6 +313,11 @@ data Header =
| Header ByteString ByteString | Header ByteString ByteString
deriving (Eq, Show) deriving (Eq, Show)
instance NFData Header where
rnf (AddCookie x) = rnf x
rnf (DeleteCookie x y) = rnf x `seq` rnf y
rnf (Header x y) = rnf x `seq` rnf y
data Location url = Local url | Remote Text data Location url = Local url | Remote Text
deriving (Show, Eq) deriving (Show, Eq)

View File

@ -47,7 +47,7 @@ library
, containers >= 0.2 , containers >= 0.2
, monad-control >= 0.3 && < 0.4 , monad-control >= 0.3 && < 0.4
, transformers-base >= 0.4 , transformers-base >= 0.4
, cookie >= 0.4 && < 0.5 , cookie >= 0.4.1 && < 0.5
, http-types >= 0.7 , http-types >= 0.7
, case-insensitive >= 0.2 , case-insensitive >= 0.2
, parsec >= 2 && < 3.2 , parsec >= 2 && < 3.2
@ -69,6 +69,7 @@ library
, unix-compat , unix-compat
, conduit-extra , conduit-extra
, exceptions , exceptions
, deepseq
exposed-modules: Yesod.Core exposed-modules: Yesod.Core
Yesod.Core.Content Yesod.Core.Content