From 6b22a0b9be73698f1e6c59dcf22b9fe6c5304759 Mon Sep 17 00:00:00 2001 From: Maximilian Tagher Date: Thu, 18 Jan 2018 18:24:55 -0800 Subject: [PATCH] Give more detail in the error message for too large request bodies. * Just to be helpful to developers, give the maximum body length and their body length * Also point developers to the function to change that value (I don't think this leaks any sensitive info, because you can always binary search with different request body sizes to find the maximum allowable) --- yesod-core/ChangeLog.md | 4 ++++ yesod-core/Yesod/Core/Internal/Request.hs | 15 +++++++++++---- yesod-core/Yesod/Core/Internal/Run.hs | 2 +- yesod-core/yesod-core.cabal | 2 +- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/yesod-core/ChangeLog.md b/yesod-core/ChangeLog.md index 43266e77..b8c2af6d 100644 --- a/yesod-core/ChangeLog.md +++ b/yesod-core/ChangeLog.md @@ -1,3 +1,7 @@ +## 1.4.37.3 + +* Improve error message when request body is too large [#1477](https://github.com/yesodweb/yesod/pull/1477) + ## 1.4.37.2 * Improve error messages for the CSRF checking functions [#1455](https://github.com/yesodweb/yesod/issues/1455) diff --git a/yesod-core/Yesod/Core/Internal/Request.hs b/yesod-core/Yesod/Core/Internal/Request.hs index b7e4e3ca..b7032716 100644 --- a/yesod-core/Yesod/Core/Internal/Request.hs +++ b/yesod-core/Yesod/Core/Internal/Request.hs @@ -25,6 +25,7 @@ import qualified Network.Wai as W import Web.Cookie (parseCookiesText) import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as S8 +import qualified Data.ByteString.Lazy.Char8 as LS8 import Data.Text (Text, pack) import Network.HTTP.Types (queryToQueryText, Status (Status)) import Data.Maybe (fromMaybe, catMaybes) @@ -60,17 +61,23 @@ limitRequestBody maxLen req = do let len = fromIntegral $ S8.length bs remaining' = remaining - len if remaining < len - then throwIO $ HCWai tooLargeResponse + then throwIO $ HCWai $ tooLargeResponse maxLen len else do writeIORef ref remaining' return bs } -tooLargeResponse :: W.Response -tooLargeResponse = W.responseLBS +tooLargeResponse :: Word64 -> Word64 -> W.Response +tooLargeResponse maxLen bodyLen = W.responseLBS (Status 413 "Too Large") [("Content-Type", "text/plain")] - "Request body too large to be processed." + (L.concat + [ "Request body too large to be processed. The maximum size is " + , (LS8.pack (show maxLen)) + , " bytes; your request body was " + , (LS8.pack (show bodyLen)) + , " bytes. If you're the developer of this site, you can configure the maximum length with the `maximumContentLength` function on the Yesod typeclass." + ]) parseWaiRequest :: W.Request -> SessionMap diff --git a/yesod-core/Yesod/Core/Internal/Run.hs b/yesod-core/Yesod/Core/Internal/Run.hs index 668e8604..3235208e 100644 --- a/yesod-core/Yesod/Core/Internal/Run.hs +++ b/yesod-core/Yesod/Core/Internal/Run.hs @@ -327,7 +327,7 @@ yesodRunner :: (ToTypedContent res, Yesod site) -> Maybe (Route site) -> Application yesodRunner handler' YesodRunnerEnv {..} route req sendResponse - | Just maxLen <- mmaxLen, KnownLength len <- requestBodyLength req, maxLen < len = sendResponse tooLargeResponse + | Just maxLen <- mmaxLen, KnownLength len <- requestBodyLength req, maxLen < len = sendResponse (tooLargeResponse maxLen len) | otherwise = do let dontSaveSession _ = return [] (session, saveSession) <- liftIO $ diff --git a/yesod-core/yesod-core.cabal b/yesod-core/yesod-core.cabal index c1d6f8a8..c808eab0 100644 --- a/yesod-core/yesod-core.cabal +++ b/yesod-core/yesod-core.cabal @@ -1,5 +1,5 @@ name: yesod-core -version: 1.4.37.2 +version: 1.4.37.3 license: MIT license-file: LICENSE author: Michael Snoyman