Skip to content

Reject forms that exceed body parsing limits with 4xx responses - #85

Merged
ysangkok merged 4 commits into
masterfrom
multipart-limit-errors
Sep 24, 2026
Merged

ysangkok merged 4 commits into
masterfrom
multipart-limit-errors

Conversation

@ysangkok

Copy link
Copy Markdown
Contributor

parseRequestBodyEx throws RequestParseException or warp's InvalidRequest
when a form exceeds a ParseRequestBodyOptions limit. These escaped the
handler, so most limits produced a 500, bypassed ErrorFormatters, and
could not be distinguished under Lenient.

They are now caught and rejected before the handler runs.
The response is built by the ErrorFormatters like other body errors,
except that size limits always respond with 413 and part header limits
with 431.

parseRequestBodyEx throws RequestParseException or warp's InvalidRequest
when a form exceeds a ParseRequestBodyOptions limit. These escaped the
handler, so most limits produced a 500, bypassed ErrorFormatters, and
could not be distinguished under Lenient.

They are now caught and rejected before the handler runs.
The response is built by the ErrorFormatters like other body errors,
except that size limits always respond with 413 and part header limits
with 431.
@ysangkok

Copy link
Copy Markdown
Contributor Author

Please take a look @fpringle

=> Proxy tag
-> MultipartOptions tag
-> DelayedIO (Either String (MultipartData tag))
-> DelayedIO (Either LimitExceeded (Either String (MultipartData tag)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could combine the LimitExceeded and String errors into one error type? e.g.

data CheckError
  = ParseError String
  | LimitExceeded { statusOverride :: Maybe (Int, String) , limitMessage :: String}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added this, but with an additional type to avoid partial record selectors.

parsed <- check pTag opts
case parsed of
Left LimitExceeded {..} ->
liftRouteResult $ FailFatal $ withStatus statusOverride (formatError request limitMessage)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if Lenient is enabled? Should this be treated in the same way as a parse error?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, with the latest commit, in lenient mode, the handler gets the Either CheckError so that it gets to handle the limit errors just like other parse errors.

Comment on lines 69 to 70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for another suggestion, but could we now add a new constructor to CheckError for utf8 errors, and only convert it to a String when we're FailFatal-ing?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, I have pushed a commit with this patch.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Co-authored-by: Frederick Pringle <frederick.pringle@fpringle.com>
@ysangkok
ysangkok merged commit 0eb038a into master Sep 24, 2026
5 checks passed
@ysangkok
ysangkok deleted the multipart-limit-errors branch September 24, 2026 16:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants