Use RequestBodyLength
This commit is contained in:
parent
eda98f96db
commit
afd700753c
@ -179,7 +179,6 @@ import Control.Monad.Trans.Control
|
|||||||
import Control.Monad.Trans.Resource
|
import Control.Monad.Trans.Resource
|
||||||
import Control.Monad.Base
|
import Control.Monad.Base
|
||||||
import Yesod.Routes.Class
|
import Yesod.Routes.Class
|
||||||
import Data.Word (Word64)
|
|
||||||
import Language.Haskell.TH.Syntax (Loc)
|
import Language.Haskell.TH.Syntax (Loc)
|
||||||
|
|
||||||
class YesodSubRoute s y where
|
class YesodSubRoute s y where
|
||||||
@ -193,7 +192,7 @@ data HandlerData sub master = HandlerData
|
|||||||
, handlerRender :: Route master -> [(Text, Text)] -> Text
|
, handlerRender :: Route master -> [(Text, Text)] -> Text
|
||||||
, handlerToMaster :: Route sub -> Route master
|
, handlerToMaster :: Route sub -> Route master
|
||||||
, handlerState :: I.IORef GHState
|
, handlerState :: I.IORef GHState
|
||||||
, handlerUpload :: Word64 -> FileUpload
|
, handlerUpload :: W.RequestBodyLength -> FileUpload
|
||||||
, handlerLog :: Loc -> LogSource -> LogLevel -> LogStr -> IO ()
|
, handlerLog :: Loc -> LogSource -> LogLevel -> LogStr -> IO ()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +312,9 @@ runRequestBody :: GHandler s m RequestBodyContents
|
|||||||
runRequestBody = do
|
runRequestBody = do
|
||||||
hd <- ask
|
hd <- ask
|
||||||
let getUpload = handlerUpload hd
|
let getUpload = handlerUpload hd
|
||||||
len = reqBodySize $ handlerRequest hd
|
len = W.requestBodyLength
|
||||||
|
$ reqWaiRequest
|
||||||
|
$ handlerRequest hd
|
||||||
upload = getUpload len
|
upload = getUpload len
|
||||||
x <- get
|
x <- get
|
||||||
case ghsRBC x of
|
case ghsRBC x of
|
||||||
@ -422,9 +423,10 @@ handlerToIO =
|
|||||||
-- Let go of the request body, cache and response headers.
|
-- Let go of the request body, cache and response headers.
|
||||||
let oldReq = handlerRequest oldHandlerData
|
let oldReq = handlerRequest oldHandlerData
|
||||||
oldWaiReq = reqWaiRequest oldReq
|
oldWaiReq = reqWaiRequest oldReq
|
||||||
newWaiReq = oldWaiReq { W.requestBody = mempty }
|
newWaiReq = oldWaiReq { W.requestBody = mempty
|
||||||
newReq = oldReq { reqWaiRequest = newWaiReq
|
, W.requestBodyLength = W.KnownLength 0
|
||||||
, reqBodySize = 0 }
|
}
|
||||||
|
newReq = oldReq { reqWaiRequest = newWaiReq }
|
||||||
clearedOldHandlerData =
|
clearedOldHandlerData =
|
||||||
oldHandlerData { handlerRequest = err "handlerRequest never here"
|
oldHandlerData { handlerRequest = err "handlerRequest never here"
|
||||||
, handlerState = err "handlerState never here" }
|
, handlerState = err "handlerState never here" }
|
||||||
@ -457,7 +459,7 @@ runHandler :: HasReps c
|
|||||||
-> (Route sub -> Route master)
|
-> (Route sub -> Route master)
|
||||||
-> master
|
-> master
|
||||||
-> sub
|
-> sub
|
||||||
-> (Word64 -> FileUpload)
|
-> (W.RequestBodyLength -> FileUpload)
|
||||||
-> (Loc -> LogSource -> LogLevel -> LogStr -> IO ())
|
-> (Loc -> LogSource -> LogLevel -> LogStr -> IO ())
|
||||||
-> YesodApp
|
-> YesodApp
|
||||||
runHandler handler mrender sroute tomr master sub upload log' =
|
runHandler handler mrender sroute tomr master sub upload log' =
|
||||||
@ -872,7 +874,7 @@ getSession = liftM ghsSession get
|
|||||||
handlerToYAR :: (HasReps a, HasReps b)
|
handlerToYAR :: (HasReps a, HasReps b)
|
||||||
=> master -- ^ master site foundation
|
=> master -- ^ master site foundation
|
||||||
-> sub -- ^ sub site foundation
|
-> sub -- ^ sub site foundation
|
||||||
-> (Word64 -> FileUpload)
|
-> (W.RequestBodyLength -> FileUpload)
|
||||||
-> (Loc -> LogSource -> LogLevel -> LogStr -> IO ())
|
-> (Loc -> LogSource -> LogLevel -> LogStr -> IO ())
|
||||||
-> (Route sub -> Route master)
|
-> (Route sub -> Route master)
|
||||||
-> (Route master -> [(Text, Text)] -> Text) -- route renderer
|
-> (Route master -> [(Text, Text)] -> Text) -- route renderer
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
{-# LANGUAGE PatternGuards #-}
|
||||||
-- | The basic typeclass for a Yesod application.
|
-- | The basic typeclass for a Yesod application.
|
||||||
module Yesod.Internal.Core
|
module Yesod.Internal.Core
|
||||||
( -- * Type classes
|
( -- * Type classes
|
||||||
@ -360,13 +361,12 @@ $doctype 5
|
|||||||
-- | How to store uploaded files.
|
-- | How to store uploaded files.
|
||||||
--
|
--
|
||||||
-- Default: When the request body is greater than 50kb, store in a temp
|
-- Default: When the request body is greater than 50kb, store in a temp
|
||||||
-- file. Otherwise, store in memory.
|
-- file. For chunked request bodies, store in a temp file. Otherwise, store
|
||||||
fileUpload :: a
|
-- in memory.
|
||||||
-> Word64 -- ^ request body size
|
fileUpload :: a -> W.RequestBodyLength -> FileUpload
|
||||||
-> FileUpload
|
fileUpload _ (W.KnownLength size)
|
||||||
fileUpload _ size
|
| size <= 50000 = FileUploadMemory lbsBackEnd
|
||||||
| size > 50000 = FileUploadDisk tempFileBackEnd
|
fileUpload _ _ = FileUploadDisk tempFileBackEnd
|
||||||
| otherwise = FileUploadMemory lbsBackEnd
|
|
||||||
|
|
||||||
-- | Should we log the given log source/level combination.
|
-- | Should we log the given log source/level combination.
|
||||||
--
|
--
|
||||||
@ -433,13 +433,13 @@ defaultYesodRunner :: Yesod master
|
|||||||
-> Maybe (SessionBackend master)
|
-> Maybe (SessionBackend master)
|
||||||
-> W.Application
|
-> W.Application
|
||||||
defaultYesodRunner logger handler' master sub murl toMasterRoute msb req
|
defaultYesodRunner logger handler' master sub murl toMasterRoute msb req
|
||||||
| maxLen < len = return tooLargeResponse
|
| W.KnownLength len <- W.requestBodyLength req, maxLen < len = return tooLargeResponse
|
||||||
| otherwise = do
|
| otherwise = do
|
||||||
let dontSaveSession _ _ = return []
|
let dontSaveSession _ _ = return []
|
||||||
now <- liftIO getCurrentTime -- FIXME remove in next major version bump
|
now <- liftIO getCurrentTime -- FIXME remove in next major version bump
|
||||||
(session, saveSession) <- liftIO $ do
|
(session, saveSession) <- liftIO $ do
|
||||||
maybe (return ([], dontSaveSession)) (\sb -> sbLoadSession sb master req now) msb
|
maybe (return ([], dontSaveSession)) (\sb -> sbLoadSession sb master req now) msb
|
||||||
rr <- liftIO $ parseWaiRequest req session (isJust msb) len maxLen
|
rr <- liftIO $ parseWaiRequest req session (isJust msb) maxLen
|
||||||
let h = {-# SCC "h" #-} do
|
let h = {-# SCC "h" #-} do
|
||||||
case murl of
|
case murl of
|
||||||
Nothing -> handler
|
Nothing -> handler
|
||||||
@ -474,11 +474,6 @@ defaultYesodRunner logger handler' master sub murl toMasterRoute msb req
|
|||||||
return $ yarToResponse yar extraHeaders
|
return $ yarToResponse yar extraHeaders
|
||||||
where
|
where
|
||||||
maxLen = maximumContentLength master $ fmap toMasterRoute murl
|
maxLen = maximumContentLength master $ fmap toMasterRoute murl
|
||||||
len = fromMaybe 0 $ lookup "content-length" (W.requestHeaders req) >>= readMay
|
|
||||||
readMay s =
|
|
||||||
case reads $ S8.unpack s of
|
|
||||||
[] -> Nothing
|
|
||||||
(x, _):_ -> Just x
|
|
||||||
handler = yesodMiddleware handler'
|
handler = yesodMiddleware handler'
|
||||||
|
|
||||||
data AuthResult = Authorized | AuthenticationRequired | Unauthorized Text
|
data AuthResult = Authorized | AuthenticationRequired | Unauthorized Text
|
||||||
@ -920,7 +915,6 @@ runFakeHandler fakeSessionMap logger master handler = liftIO $ do
|
|||||||
, reqWaiRequest = fakeWaiRequest
|
, reqWaiRequest = fakeWaiRequest
|
||||||
, reqLangs = []
|
, reqLangs = []
|
||||||
, reqToken = Just "NaN" -- not a nonce =)
|
, reqToken = Just "NaN" -- not a nonce =)
|
||||||
, reqBodySize = 0
|
|
||||||
}
|
}
|
||||||
fakeContentType = []
|
fakeContentType = []
|
||||||
_ <- runResourceT $ yapp errHandler fakeRequest fakeContentType fakeSessionMap
|
_ <- runResourceT $ yapp errHandler fakeRequest fakeContentType fakeSessionMap
|
||||||
|
|||||||
@ -53,21 +53,15 @@ data Request = Request
|
|||||||
, reqLangs :: [Text]
|
, reqLangs :: [Text]
|
||||||
-- | A random, session-specific token used to prevent CSRF attacks.
|
-- | A random, session-specific token used to prevent CSRF attacks.
|
||||||
, reqToken :: Maybe Text
|
, reqToken :: Maybe Text
|
||||||
-- | Size of the request body.
|
|
||||||
--
|
|
||||||
-- Note: in the presence of chunked request bodies, this value will be 0,
|
|
||||||
-- even though data is available.
|
|
||||||
, reqBodySize :: Word64 -- FIXME Consider in the future using a Maybe to represent chunked bodies
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parseWaiRequest :: W.Request
|
parseWaiRequest :: W.Request
|
||||||
-> [(Text, ByteString)] -- ^ session
|
-> [(Text, ByteString)] -- ^ session
|
||||||
-> Bool
|
-> Bool
|
||||||
-> Word64 -- ^ actual length... might be meaningless, see 'reqBodySize'
|
|
||||||
-> Word64 -- ^ maximum allowed body size
|
-> Word64 -- ^ maximum allowed body size
|
||||||
-> IO Request
|
-> IO Request
|
||||||
parseWaiRequest env session' useToken bodySize maxBodySize =
|
parseWaiRequest env session' useToken maxBodySize =
|
||||||
parseWaiRequest' env session' useToken bodySize maxBodySize <$> newStdGen
|
parseWaiRequest' env session' useToken maxBodySize <$> newStdGen
|
||||||
|
|
||||||
-- | Impose a limit on the size of the request body.
|
-- | Impose a limit on the size of the request body.
|
||||||
limitRequestBody :: Word64 -> W.Request -> W.Request
|
limitRequestBody :: Word64 -> W.Request -> W.Request
|
||||||
@ -98,12 +92,11 @@ parseWaiRequest' :: RandomGen g
|
|||||||
=> W.Request
|
=> W.Request
|
||||||
-> [(Text, ByteString)] -- ^ session
|
-> [(Text, ByteString)] -- ^ session
|
||||||
-> Bool
|
-> Bool
|
||||||
-> Word64
|
|
||||||
-> Word64 -- ^ max body size
|
-> Word64 -- ^ max body size
|
||||||
-> g
|
-> g
|
||||||
-> Request
|
-> Request
|
||||||
parseWaiRequest' env session' useToken bodySize maxBodySize gen =
|
parseWaiRequest' env session' useToken maxBodySize gen =
|
||||||
Request gets'' cookies' (limitRequestBody maxBodySize env) langs'' token bodySize
|
Request gets'' cookies' (limitRequestBody maxBodySize env) langs'' token
|
||||||
where
|
where
|
||||||
gets' = queryToQueryText $ W.queryString env
|
gets' = queryToQueryText $ W.queryString env
|
||||||
gets'' = map (second $ fromMaybe "") gets'
|
gets'' = map (second $ fromMaybe "") gets'
|
||||||
|
|||||||
@ -38,19 +38,19 @@ tokenSpecs = describe "Yesod.Internal.Request.parseWaiRequest (reqToken)" $ do
|
|||||||
|
|
||||||
noDisabledToken :: Bool
|
noDisabledToken :: Bool
|
||||||
noDisabledToken = reqToken r == Nothing where
|
noDisabledToken = reqToken r == Nothing where
|
||||||
r = parseWaiRequest' defaultRequest [] False 0 1000 g
|
r = parseWaiRequest' defaultRequest [] False 1000 g
|
||||||
|
|
||||||
ignoreDisabledToken :: Bool
|
ignoreDisabledToken :: Bool
|
||||||
ignoreDisabledToken = reqToken r == Nothing where
|
ignoreDisabledToken = reqToken r == Nothing where
|
||||||
r = parseWaiRequest' defaultRequest [("_TOKEN", "old")] False 0 1000 g
|
r = parseWaiRequest' defaultRequest [("_TOKEN", "old")] False 1000 g
|
||||||
|
|
||||||
useOldToken :: Bool
|
useOldToken :: Bool
|
||||||
useOldToken = reqToken r == Just "old" where
|
useOldToken = reqToken r == Just "old" where
|
||||||
r = parseWaiRequest' defaultRequest [("_TOKEN", "old")] True 0 1000 g
|
r = parseWaiRequest' defaultRequest [("_TOKEN", "old")] True 1000 g
|
||||||
|
|
||||||
generateToken :: Bool
|
generateToken :: Bool
|
||||||
generateToken = reqToken r /= Nothing where
|
generateToken = reqToken r /= Nothing where
|
||||||
r = parseWaiRequest' defaultRequest [("_TOKEN", "old")] True 0 1000 g
|
r = parseWaiRequest' defaultRequest [("_TOKEN", "old")] True 1000 g
|
||||||
|
|
||||||
|
|
||||||
langSpecs :: Spec
|
langSpecs :: Spec
|
||||||
@ -64,21 +64,21 @@ langSpecs = describe "Yesod.Internal.Request.parseWaiRequest (reqLangs)" $ do
|
|||||||
respectAcceptLangs :: Bool
|
respectAcceptLangs :: Bool
|
||||||
respectAcceptLangs = reqLangs r == ["en-US", "es", "en"] where
|
respectAcceptLangs = reqLangs r == ["en-US", "es", "en"] where
|
||||||
r = parseWaiRequest' defaultRequest
|
r = parseWaiRequest' defaultRequest
|
||||||
{ requestHeaders = [("Accept-Language", "en-US, es")] } [] False 0 1000 g
|
{ requestHeaders = [("Accept-Language", "en-US, es")] } [] False 1000 g
|
||||||
|
|
||||||
respectSessionLang :: Bool
|
respectSessionLang :: Bool
|
||||||
respectSessionLang = reqLangs r == ["en"] where
|
respectSessionLang = reqLangs r == ["en"] where
|
||||||
r = parseWaiRequest' defaultRequest [("_LANG", "en")] False 0 1000 g
|
r = parseWaiRequest' defaultRequest [("_LANG", "en")] False 1000 g
|
||||||
|
|
||||||
respectCookieLang :: Bool
|
respectCookieLang :: Bool
|
||||||
respectCookieLang = reqLangs r == ["en"] where
|
respectCookieLang = reqLangs r == ["en"] where
|
||||||
r = parseWaiRequest' defaultRequest
|
r = parseWaiRequest' defaultRequest
|
||||||
{ requestHeaders = [("Cookie", "_LANG=en")]
|
{ requestHeaders = [("Cookie", "_LANG=en")]
|
||||||
} [] False 0 1000 g
|
} [] False 1000 g
|
||||||
|
|
||||||
respectQueryLang :: Bool
|
respectQueryLang :: Bool
|
||||||
respectQueryLang = reqLangs r == ["en-US", "en"] where
|
respectQueryLang = reqLangs r == ["en-US", "en"] where
|
||||||
r = parseWaiRequest' defaultRequest { queryString = [("_LANG", Just "en-US")] } [] False 0 1000 g
|
r = parseWaiRequest' defaultRequest { queryString = [("_LANG", Just "en-US")] } [] False 1000 g
|
||||||
|
|
||||||
prioritizeLangs :: Bool
|
prioritizeLangs :: Bool
|
||||||
prioritizeLangs = reqLangs r == ["en-QUERY", "en-COOKIE", "en-SESSION", "en", "es"] where
|
prioritizeLangs = reqLangs r == ["en-QUERY", "en-COOKIE", "en-SESSION", "en", "es"] where
|
||||||
@ -87,7 +87,7 @@ prioritizeLangs = reqLangs r == ["en-QUERY", "en-COOKIE", "en-SESSION", "en", "e
|
|||||||
, ("Cookie", "_LANG=en-COOKIE")
|
, ("Cookie", "_LANG=en-COOKIE")
|
||||||
]
|
]
|
||||||
, queryString = [("_LANG", Just "en-QUERY")]
|
, queryString = [("_LANG", Just "en-QUERY")]
|
||||||
} [("_LANG", "en-SESSION")] False 0 10000 g
|
} [("_LANG", "en-SESSION")] False 10000 g
|
||||||
|
|
||||||
|
|
||||||
internalRequestTest :: Spec
|
internalRequestTest :: Spec
|
||||||
|
|||||||
@ -75,6 +75,10 @@ caseHelper name path body statusChunked statusNonChunked = describe name $ do
|
|||||||
then [("content-length", S8.pack $ show $ S.length body)]
|
then [("content-length", S8.pack $ show $ S.length body)]
|
||||||
else []
|
else []
|
||||||
, requestMethod = "POST"
|
, requestMethod = "POST"
|
||||||
|
, requestBodyLength =
|
||||||
|
if includeLength
|
||||||
|
then KnownLength $ fromIntegral $ S.length body
|
||||||
|
else ChunkedBody
|
||||||
} $ L.fromChunks $ map S.singleton $ S.unpack body
|
} $ L.fromChunks $ map S.singleton $ S.unpack body
|
||||||
|
|
||||||
specs :: Spec
|
specs :: Spec
|
||||||
|
|||||||
@ -50,7 +50,7 @@ library
|
|||||||
build-depends: base >= 4.3 && < 5
|
build-depends: base >= 4.3 && < 5
|
||||||
, time >= 1.1.4
|
, time >= 1.1.4
|
||||||
, yesod-routes >= 1.1 && < 1.2
|
, yesod-routes >= 1.1 && < 1.2
|
||||||
, wai >= 1.3 && < 1.5
|
, wai >= 1.4 && < 1.5
|
||||||
, wai-extra >= 1.3 && < 1.4
|
, wai-extra >= 1.3 && < 1.4
|
||||||
, bytestring >= 0.9.1.4
|
, bytestring >= 0.9.1.4
|
||||||
, text >= 0.7 && < 0.12
|
, text >= 0.7 && < 0.12
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user