Merge pull request #1083 from DaveCTurner/issue-1083
Thread leak when calling neverExpires
This commit is contained in:
commit
15d7bd458b
@ -59,6 +59,8 @@ import Yesod.Core.Class.Dispatch
|
|||||||
import Yesod.Core.Internal.Run
|
import Yesod.Core.Internal.Run
|
||||||
import Safe (readMay)
|
import Safe (readMay)
|
||||||
import System.Environment (getEnvironment)
|
import System.Environment (getEnvironment)
|
||||||
|
import Control.AutoUpdate (mkAutoUpdate, defaultUpdateSettings, updateAction, updateFreq)
|
||||||
|
import Yesod.Core.Internal.Util (getCurrentMaxExpiresRFC1123)
|
||||||
|
|
||||||
import Network.Wai.Middleware.Autohead
|
import Network.Wai.Middleware.Autohead
|
||||||
import Network.Wai.Middleware.AcceptOverride
|
import Network.Wai.Middleware.AcceptOverride
|
||||||
@ -82,11 +84,13 @@ toWaiAppPlain site = do
|
|||||||
logger <- makeLogger site
|
logger <- makeLogger site
|
||||||
sb <- makeSessionBackend site
|
sb <- makeSessionBackend site
|
||||||
gen <- MWC.createSystemRandom
|
gen <- MWC.createSystemRandom
|
||||||
|
getMaxExpires <- getGetMaxExpires
|
||||||
return $ toWaiAppYre $ YesodRunnerEnv
|
return $ toWaiAppYre $ YesodRunnerEnv
|
||||||
{ yreLogger = logger
|
{ yreLogger = logger
|
||||||
, yreSite = site
|
, yreSite = site
|
||||||
, yreSessionBackend = sb
|
, yreSessionBackend = sb
|
||||||
, yreGen = gen
|
, yreGen = gen
|
||||||
|
, yreGetMaxExpires = getMaxExpires
|
||||||
}
|
}
|
||||||
|
|
||||||
toWaiAppYre :: YesodDispatch site => YesodRunnerEnv site -> W.Application
|
toWaiAppYre :: YesodDispatch site => YesodRunnerEnv site -> W.Application
|
||||||
@ -139,11 +143,13 @@ toWaiAppLogger :: YesodDispatch site => Logger -> site -> IO W.Application
|
|||||||
toWaiAppLogger logger site = do
|
toWaiAppLogger logger site = do
|
||||||
sb <- makeSessionBackend site
|
sb <- makeSessionBackend site
|
||||||
gen <- MWC.createSystemRandom
|
gen <- MWC.createSystemRandom
|
||||||
|
getMaxExpires <- getGetMaxExpires
|
||||||
let yre = YesodRunnerEnv
|
let yre = YesodRunnerEnv
|
||||||
{ yreLogger = logger
|
{ yreLogger = logger
|
||||||
, yreSite = site
|
, yreSite = site
|
||||||
, yreSessionBackend = sb
|
, yreSessionBackend = sb
|
||||||
, yreGen = gen
|
, yreGen = gen
|
||||||
|
, yreGetMaxExpires = getMaxExpires
|
||||||
}
|
}
|
||||||
messageLoggerSource
|
messageLoggerSource
|
||||||
site
|
site
|
||||||
@ -230,3 +236,9 @@ warpEnv site = do
|
|||||||
case readMay portS of
|
case readMay portS of
|
||||||
Nothing -> error $ "warpEnv: invalid PORT environment variable: " ++ show portS
|
Nothing -> error $ "warpEnv: invalid PORT environment variable: " ++ show portS
|
||||||
Just port -> warp port site
|
Just port -> warp port site
|
||||||
|
|
||||||
|
getGetMaxExpires :: IO (IO Text)
|
||||||
|
getGetMaxExpires = mkAutoUpdate defaultUpdateSettings
|
||||||
|
{ updateAction = getCurrentMaxExpiresRFC1123
|
||||||
|
, updateFreq = 24 * 60 * 60 * 1000000 -- Update once per day
|
||||||
|
}
|
||||||
|
|||||||
@ -733,7 +733,7 @@ cacheSeconds i = setHeader "Cache-Control" $ T.concat
|
|||||||
-- is never (realistically) expired.
|
-- is never (realistically) expired.
|
||||||
neverExpires :: MonadHandler m => m ()
|
neverExpires :: MonadHandler m => m ()
|
||||||
neverExpires = do
|
neverExpires = do
|
||||||
askHandlerEnv >>= liftIO . rheGetMaxExpires >>= setHeader "Expires"
|
setHeader "Expires" . rheMaxExpires =<< askHandlerEnv
|
||||||
cacheSeconds oneYear
|
cacheSeconds oneYear
|
||||||
where
|
where
|
||||||
oneYear :: Int
|
oneYear :: Int
|
||||||
|
|||||||
@ -34,7 +34,6 @@ import qualified Data.Text as T
|
|||||||
import Data.Text.Encoding (encodeUtf8)
|
import Data.Text.Encoding (encodeUtf8)
|
||||||
import Data.Text.Encoding (decodeUtf8With)
|
import Data.Text.Encoding (decodeUtf8With)
|
||||||
import Data.Text.Encoding.Error (lenientDecode)
|
import Data.Text.Encoding.Error (lenientDecode)
|
||||||
import Data.Time (getCurrentTime, addUTCTime)
|
|
||||||
import Language.Haskell.TH.Syntax (Loc, qLocation)
|
import Language.Haskell.TH.Syntax (Loc, qLocation)
|
||||||
import qualified Network.HTTP.Types as H
|
import qualified Network.HTTP.Types as H
|
||||||
import Network.Wai
|
import Network.Wai
|
||||||
@ -48,11 +47,9 @@ import Yesod.Core.Class.Yesod
|
|||||||
import Yesod.Core.Types
|
import Yesod.Core.Types
|
||||||
import Yesod.Core.Internal.Request (parseWaiRequest,
|
import Yesod.Core.Internal.Request (parseWaiRequest,
|
||||||
tooLargeResponse)
|
tooLargeResponse)
|
||||||
import Yesod.Core.Internal.Util (formatRFC1123)
|
import Yesod.Core.Internal.Util (getCurrentMaxExpiresRFC1123)
|
||||||
import Yesod.Routes.Class (Route, renderRoute)
|
import Yesod.Routes.Class (Route, renderRoute)
|
||||||
import Control.DeepSeq (($!!))
|
import Control.DeepSeq (($!!))
|
||||||
import Control.Monad (liftM)
|
|
||||||
import Control.AutoUpdate (mkAutoUpdate, defaultUpdateSettings, updateAction, updateFreq)
|
|
||||||
|
|
||||||
returnDeepSessionMap :: Monad m => SessionMap -> m SessionMap
|
returnDeepSessionMap :: Monad m => SessionMap -> m SessionMap
|
||||||
#if MIN_VERSION_bytestring(0, 10, 0)
|
#if MIN_VERSION_bytestring(0, 10, 0)
|
||||||
@ -199,7 +196,7 @@ runFakeHandler :: (Yesod site, MonadIO m) =>
|
|||||||
-> m (Either ErrorResponse a)
|
-> m (Either ErrorResponse a)
|
||||||
runFakeHandler fakeSessionMap logger site handler = liftIO $ do
|
runFakeHandler fakeSessionMap logger site handler = liftIO $ do
|
||||||
ret <- I.newIORef (Left $ InternalError "runFakeHandler: no result")
|
ret <- I.newIORef (Left $ InternalError "runFakeHandler: no result")
|
||||||
getMaxExpires <- getGetMaxExpires
|
maxExpires <- getCurrentMaxExpiresRFC1123
|
||||||
let handler' = do liftIO . I.writeIORef ret . Right =<< handler
|
let handler' = do liftIO . I.writeIORef ret . Right =<< handler
|
||||||
return ()
|
return ()
|
||||||
let yapp = runHandler
|
let yapp = runHandler
|
||||||
@ -210,7 +207,7 @@ runFakeHandler fakeSessionMap logger site handler = liftIO $ do
|
|||||||
, rheUpload = fileUpload site
|
, rheUpload = fileUpload site
|
||||||
, rheLog = messageLoggerSource site $ logger site
|
, rheLog = messageLoggerSource site $ logger site
|
||||||
, rheOnError = errHandler
|
, rheOnError = errHandler
|
||||||
, rheGetMaxExpires = getMaxExpires
|
, rheMaxExpires = maxExpires
|
||||||
}
|
}
|
||||||
handler'
|
handler'
|
||||||
errHandler err req = do
|
errHandler err req = do
|
||||||
@ -261,7 +258,7 @@ yesodRunner handler' YesodRunnerEnv {..} route req sendResponse
|
|||||||
let dontSaveSession _ = return []
|
let dontSaveSession _ = return []
|
||||||
(session, saveSession) <- liftIO $ do
|
(session, saveSession) <- liftIO $ do
|
||||||
maybe (return (Map.empty, dontSaveSession)) (\sb -> sbLoadSession sb req) yreSessionBackend
|
maybe (return (Map.empty, dontSaveSession)) (\sb -> sbLoadSession sb req) yreSessionBackend
|
||||||
getMaxExpires <- getGetMaxExpires
|
maxExpires <- yreGetMaxExpires
|
||||||
let mkYesodReq = parseWaiRequest req session (isJust yreSessionBackend) mmaxLen
|
let mkYesodReq = parseWaiRequest req session (isJust yreSessionBackend) mmaxLen
|
||||||
let yreq =
|
let yreq =
|
||||||
case mkYesodReq of
|
case mkYesodReq of
|
||||||
@ -280,7 +277,7 @@ yesodRunner handler' YesodRunnerEnv {..} route req sendResponse
|
|||||||
, rheUpload = fileUpload yreSite
|
, rheUpload = fileUpload yreSite
|
||||||
, rheLog = log'
|
, rheLog = log'
|
||||||
, rheOnError = safeEh log'
|
, rheOnError = safeEh log'
|
||||||
, rheGetMaxExpires = getMaxExpires
|
, rheMaxExpires = maxExpires
|
||||||
}
|
}
|
||||||
rhe = rheSafe
|
rhe = rheSafe
|
||||||
{ rheOnError = runHandler rheSafe . errorHandler
|
{ rheOnError = runHandler rheSafe . errorHandler
|
||||||
@ -294,12 +291,6 @@ yesodRunner handler' YesodRunnerEnv {..} route req sendResponse
|
|||||||
mmaxLen = maximumContentLength yreSite route
|
mmaxLen = maximumContentLength yreSite route
|
||||||
handler = yesodMiddleware handler'
|
handler = yesodMiddleware handler'
|
||||||
|
|
||||||
getGetMaxExpires :: MonadIO m => m (IO Text)
|
|
||||||
getGetMaxExpires = liftIO $ mkAutoUpdate defaultUpdateSettings
|
|
||||||
{ updateAction = liftM (formatRFC1123 . addUTCTime (60*60*24*365)) getCurrentTime
|
|
||||||
, updateFreq = 60 * 60 * 1000000 -- Update once per hour
|
|
||||||
}
|
|
||||||
|
|
||||||
yesodRender :: Yesod y
|
yesodRender :: Yesod y
|
||||||
=> y
|
=> y
|
||||||
-> ResolvedApproot
|
-> ResolvedApproot
|
||||||
|
|||||||
@ -5,13 +5,16 @@ module Yesod.Core.Internal.Util
|
|||||||
, formatW3
|
, formatW3
|
||||||
, formatRFC1123
|
, formatRFC1123
|
||||||
, formatRFC822
|
, formatRFC822
|
||||||
|
, getCurrentMaxExpiresRFC1123
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.Int (Int64)
|
import Data.Int (Int64)
|
||||||
import Data.Serialize (Get, Put, Serialize (..))
|
import Data.Serialize (Get, Put, Serialize (..))
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Time (Day (ModifiedJulianDay, toModifiedJulianDay),
|
import Data.Time (Day (ModifiedJulianDay, toModifiedJulianDay),
|
||||||
DiffTime, UTCTime (..), formatTime)
|
DiffTime, UTCTime (..), formatTime,
|
||||||
|
getCurrentTime, addUTCTime)
|
||||||
|
import Control.Monad (liftM)
|
||||||
|
|
||||||
#if MIN_VERSION_time(1,5,0)
|
#if MIN_VERSION_time(1,5,0)
|
||||||
import Data.Time (defaultTimeLocale)
|
import Data.Time (defaultTimeLocale)
|
||||||
@ -50,3 +53,9 @@ formatRFC1123 = T.pack . formatTime defaultTimeLocale "%a, %d %b %Y %X %Z"
|
|||||||
-- | Format as per RFC 822.
|
-- | Format as per RFC 822.
|
||||||
formatRFC822 :: UTCTime -> T.Text
|
formatRFC822 :: UTCTime -> T.Text
|
||||||
formatRFC822 = T.pack . formatTime defaultTimeLocale "%a, %d %b %Y %H:%M:%S %z"
|
formatRFC822 = T.pack . formatTime defaultTimeLocale "%a, %d %b %Y %H:%M:%S %z"
|
||||||
|
|
||||||
|
{- | Get the time 365 days from now in RFC 1123 format. For use as an expiry
|
||||||
|
date on a resource that never expires. See RFC 2616 section 14.21 for details.
|
||||||
|
-}
|
||||||
|
getCurrentMaxExpiresRFC1123 :: IO T.Text
|
||||||
|
getCurrentMaxExpiresRFC1123 = liftM (formatRFC1123 . addUTCTime (60*60*24*365)) getCurrentTime
|
||||||
|
|||||||
@ -183,10 +183,10 @@ data RunHandlerEnv site = RunHandlerEnv
|
|||||||
, rheUpload :: !(RequestBodyLength -> FileUpload)
|
, rheUpload :: !(RequestBodyLength -> FileUpload)
|
||||||
, rheLog :: !(Loc -> LogSource -> LogLevel -> LogStr -> IO ())
|
, rheLog :: !(Loc -> LogSource -> LogLevel -> LogStr -> IO ())
|
||||||
, rheOnError :: !(ErrorResponse -> YesodApp)
|
, rheOnError :: !(ErrorResponse -> YesodApp)
|
||||||
, rheGetMaxExpires :: IO Text
|
|
||||||
-- ^ How to respond when an error is thrown internally.
|
-- ^ How to respond when an error is thrown internally.
|
||||||
--
|
--
|
||||||
-- Since 1.2.0
|
-- Since 1.2.0
|
||||||
|
, rheMaxExpires :: !Text
|
||||||
}
|
}
|
||||||
|
|
||||||
data HandlerData site parentRoute = HandlerData
|
data HandlerData site parentRoute = HandlerData
|
||||||
@ -202,6 +202,7 @@ data YesodRunnerEnv site = YesodRunnerEnv
|
|||||||
, yreSite :: !site
|
, yreSite :: !site
|
||||||
, yreSessionBackend :: !(Maybe SessionBackend)
|
, yreSessionBackend :: !(Maybe SessionBackend)
|
||||||
, yreGen :: !MWC.GenIO
|
, yreGen :: !MWC.GenIO
|
||||||
|
, yreGetMaxExpires :: IO Text
|
||||||
}
|
}
|
||||||
|
|
||||||
data YesodSubRunnerEnv sub parent parentMonad = YesodSubRunnerEnv
|
data YesodSubRunnerEnv sub parent parentMonad = YesodSubRunnerEnv
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user