How can I limit size of request body and headers in WAI?
Asked Answered
C

3

6

I am developing an application using Scotty and of course WAI. I would like to be able to limit the size of requests, both for body length and for headers. How can I do that? Is it possible to do it using a plain WAI middleware ?

Coo answered 15/4, 2015 at 7:25 Comment(0)
R
5

I don't know details of Scotty, but it's certainly possible to set up a WAI middleware that will look at the requestBodyLength and, if it's too large, return an appropriate 413 status code page. One thing you'd need to deal with is if the upload body is sent with chunked encoding, in which case no content-length is present. but that's uncommon. You have the option of either rejecting those requests, or adding code to wrap the request body and return an error if it turns out to be too large (that's what Yesod does).

Rufous answered 15/4, 2015 at 9:58 Comment(2)
Thanks Michael. I found other answers on SO about the body. My use case is about file upload which I think is using chunked encoding (not sure). but what about the headers? Is there a limit baked in WAI/Warp?Coo
requestBodyLength is populated via the content-length and transfer-encoding headers. There is no baked in limit. Have you tried testing any of this?Rufous
S
1

The marked solution points in the correct direction, but if you're like me you might still struggle to explicitely derive the full code needed. Here is an implementation (thanks to the help of an experienced Haskell friend):

import qualified Network.HTTP.Types as Http
import qualified Network.Wai as Wai

limitRequestSize :: Wai.Middleware
limitRequestSize app req respond = do
    case Wai.requestBodyLength req of
        Wai.KnownLength len -> do
            if len > maxLen
                then respond $ Wai.responseBuilder Http.status413 [] mempty
                else app req respond

        Wai.ChunkedBody ->
            respond $ Wai.responseBuilder Http.status411 [] mempty
    where
        maxLen = 50*1000 -- 50kB

The middleware then just runs in scotty's do block like this

import Network.Wai.Middleware.RequestLogger (logStdout)

main :: IO ()
main = do
    scotty 3000 $ do
        middleware logStdout
        middleware limitRequestSize

        get "/alive" $ do
            status Http.status200

        -- ...

If you're curious as to how to derive it (or why I found this not overly trivial), consider that Middleware is an alias for

Application -> Application

where Application itself is an alias for

Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived

Hence there are quite a bunch of arguments to (mentally) unpack, even if the solution is pretty terse.

Sash answered 9/9, 2019 at 11:35 Comment(0)
G
1

As of wai-extra-3.1.1 the code described above has been added to the Network.Wai.Middleware.RequestSizeLimit module, so it can just be pulled in as a dependency.

Gong answered 19/10, 2021 at 13:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.