Rewrite handlerToIO so that it works with Yesod 1.2.
Since the new YesodRequest has strict fields, handlerToIO didn't work at all. Even if it did, it had a reference to its parent's ResourceT's internal state, so its chances of blowing up were quite high. The new implementation takes a whitelist approach of taking what we want instead of clearing what we do not want. Also, it takes care of using a new runResourceT.
This commit is contained in:
parent
c19501b1d8
commit
5c434b089a
@ -143,6 +143,7 @@ import Yesod.Core.Internal.Request (langKey, mkFileInfoFile,
|
|||||||
mkFileInfoLBS, mkFileInfoSource)
|
mkFileInfoLBS, mkFileInfoSource)
|
||||||
|
|
||||||
import Control.Applicative ((<$>), (<|>))
|
import Control.Applicative ((<$>), (<|>))
|
||||||
|
import Control.Exception (evaluate)
|
||||||
|
|
||||||
import Control.Monad (liftM)
|
import Control.Monad (liftM)
|
||||||
import qualified Control.Monad.Trans.Writer as Writer
|
import qualified Control.Monad.Trans.Writer as Writer
|
||||||
@ -179,7 +180,7 @@ import Yesod.Core.Content (ToTypedContent (..), simpleConte
|
|||||||
import Yesod.Core.Internal.Util (formatRFC1123)
|
import Yesod.Core.Internal.Util (formatRFC1123)
|
||||||
import Text.Blaze.Html (preEscapedToMarkup, toHtml)
|
import Text.Blaze.Html (preEscapedToMarkup, toHtml)
|
||||||
|
|
||||||
import Control.Monad.Trans.Resource (ResourceT)
|
import Control.Monad.Trans.Resource (ResourceT, runResourceT, withInternalState)
|
||||||
import Data.Dynamic (fromDynamic, toDyn)
|
import Data.Dynamic (fromDynamic, toDyn)
|
||||||
import qualified Data.IORef.Lifted as I
|
import qualified Data.IORef.Lifted as I
|
||||||
import Data.Maybe (listToMaybe)
|
import Data.Maybe (listToMaybe)
|
||||||
@ -318,20 +319,15 @@ getCurrentRoute = rheRoute `liftM` askHandlerEnv
|
|||||||
handlerToIO :: (MonadIO m1, MonadIO m2) => HandlerT site m1 (HandlerT site IO a -> m2 a)
|
handlerToIO :: (MonadIO m1, MonadIO m2) => HandlerT site m1 (HandlerT site IO a -> m2 a)
|
||||||
handlerToIO =
|
handlerToIO =
|
||||||
HandlerT $ \oldHandlerData -> do
|
HandlerT $ \oldHandlerData -> do
|
||||||
-- Let go of the request body, cache and response headers.
|
-- Take just the bits we need from oldHandlerData.
|
||||||
let oldReq = handlerRequest oldHandlerData
|
let newReq = oldReq { reqWaiRequest = newWaiReq }
|
||||||
oldWaiReq = reqWaiRequest oldReq
|
where
|
||||||
newWaiReq = oldWaiReq { W.requestBody = mempty
|
oldReq = handlerRequest oldHandlerData
|
||||||
, W.requestBodyLength = W.KnownLength 0
|
oldWaiReq = reqWaiRequest oldReq
|
||||||
}
|
newWaiReq = oldWaiReq { W.requestBody = mempty
|
||||||
newReq = oldReq { reqWaiRequest = newWaiReq }
|
, W.requestBodyLength = W.KnownLength 0
|
||||||
clearedOldHandlerData =
|
}
|
||||||
oldHandlerData { handlerRequest = err "handlerRequest never here"
|
oldEnv = handlerEnv oldHandlerData
|
||||||
, handlerState = err "handlerState never here"
|
|
||||||
, handlerToParent = const () }
|
|
||||||
where
|
|
||||||
err :: String -> a
|
|
||||||
err = error . ("handlerToIO: clearedOldHandlerData/" ++)
|
|
||||||
newState <- liftIO $ do
|
newState <- liftIO $ do
|
||||||
oldState <- I.readIORef (handlerState oldHandlerData)
|
oldState <- I.readIORef (handlerState oldHandlerData)
|
||||||
return $ oldState { ghsRBC = Nothing
|
return $ oldState { ghsRBC = Nothing
|
||||||
@ -339,16 +335,25 @@ handlerToIO =
|
|||||||
, ghsCache = mempty
|
, ghsCache = mempty
|
||||||
, ghsHeaders = mempty }
|
, ghsHeaders = mempty }
|
||||||
|
|
||||||
|
-- xx From this point onwards, no references to oldHandlerData xx
|
||||||
|
liftIO $ evaluate (newReq `seq` oldEnv `seq` newState `seq` ())
|
||||||
|
|
||||||
-- Return GHandler running function.
|
-- Return GHandler running function.
|
||||||
return $ \(HandlerT f) -> liftIO $ do
|
return $ \(HandlerT f) ->
|
||||||
-- The state IORef needs to be created here, otherwise it
|
liftIO $
|
||||||
-- will be shared by different invocations of this function.
|
runResourceT $ withInternalState $ \resState -> do
|
||||||
newStateIORef <- I.newIORef newState
|
-- The state IORef needs to be created here, otherwise it
|
||||||
-- FIXME previously runResourceT was used here, but that could mean resources might vanish...
|
-- will be shared by different invocations of this function.
|
||||||
-- Check if this new behavior is correct.
|
newStateIORef <- liftIO (I.newIORef newState)
|
||||||
f clearedOldHandlerData
|
let newHandlerData =
|
||||||
{ handlerRequest = newReq
|
HandlerData
|
||||||
, handlerState = newStateIORef }
|
{ handlerRequest = newReq
|
||||||
|
, handlerEnv = oldEnv
|
||||||
|
, handlerState = newStateIORef
|
||||||
|
, handlerToParent = const ()
|
||||||
|
, handlerResource = resState
|
||||||
|
}
|
||||||
|
liftIO (f newHandlerData)
|
||||||
|
|
||||||
|
|
||||||
-- | Redirect to the given route.
|
-- | Redirect to the given route.
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: yesod-core
|
name: yesod-core
|
||||||
version: 1.2.0.3
|
version: 1.2.0.4
|
||||||
license: MIT
|
license: MIT
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
author: Michael Snoyman <michael@snoyman.com>
|
author: Michael Snoyman <michael@snoyman.com>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user