Skip to content

fix: reject multipart ranges before validation - #661

Open
shblue21 wants to merge 3 commits into
tower-rs:mainfrom
shblue21:reject-multipart-ranges-before-validation
Open

fix: reject multipart ranges before validation#661
shblue21 wants to merge 3 commits into
tower-rs:mainfrom
shblue21:reject-multipart-ranges-before-validation

Conversation

@shblue21

@shblue21 shblue21 commented Apr 20, 2026

Copy link
Copy Markdown

Motivation

ServeDir / ServeFile do not support multipart range responses, but they validate multi-range Range headers before later rejecting them with 416 Range Not Satisfiable.

This means requests that are guaranteed to be rejected still pay the cost of validate(file_size), including its pairwise overlap checks.

Solution

Reject multiple ranges before calling validate(file_size):

  • parse the range header as before
  • return a local MultipleRangesNotSupported error when more than one range is present
  • only call validate(file_size) for single-range requests
  • preserve the multipart-specific 416 response body for valid multi-range requests

This also adds regression coverage for the multipart-specific response body.

Note: syntactically parsed multi-range requests that would previously fail semantic validation, such as overlapping or reversed ranges, are now rejected as unsupported multiple ranges before validation. The status and Content-Range remain unchanged, but the 416 body becomes the multipart-specific message.

Refs: #660

@jplatte

jplatte commented Apr 21, 2026

Copy link
Copy Markdown
Member

Note: this changes the 416 response body for valid multipart range requests from Cannot serve multipart range requests to empty, since they now fall through the existing generic Err(_) -> 416 path in future.rs.

I think it would make sense to keep the specific error message body. Can you bring it back?

@shblue21

Copy link
Copy Markdown
Author

Thanks. I’ll keep the multipart-specific body so the response stays behavior-preserving. That will require a small future.rs update, and I’ll keep the patch as minimal as possible.

@shblue21
shblue21 force-pushed the reject-multipart-ranges-before-validation branch from ca0e6ea to 4448c39 Compare April 24, 2026 10:27
@shblue21

Copy link
Copy Markdown
Author

Added the small future.rs change. Multi-range requests still skip validate(file_size), and the regression test now checks the multipart-specific 416 body.

@jlizen jlizen left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@shblue21 do you see a reason not to support the behavior of flattening to single-part GET instead? Even if opt-in due to DOS risk (in which case your approach seems fine for rejection, though I have a small nit on internal error modeling).

IETF seems to prefer that,the RFC states:

A server MAY ignore the Range header field. However, origin servers
and intermediate caches ought to support byte ranges when possible,
since Range supports efficient recovery from partially failed
transfers and partial retrieval of large representations. A server
MUST ignore a Range header field received with a request method other
than GET.

Range requests are an OPTIONAL feature of HTTP, designed so that recipients not implementing this feature (or not supporting it for the target resource) can respond as if it is a normal GET request without impacting interoperability.

if parsed.ranges.len() > 1 {
// ServeDir/ServeFile do not support multipart responses, so reject
// multi-range requests before validate() runs overlap checks.
return Err(RangeUnsatisfiableError::OverlappingRanges);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't seem like quite the right error, this refers to overlapping ranges within a multipart request. Meanwhile we don't support them at all.

Can we have a local error type instead that more clearly denotes what's happening, if we preserve this behavior?

@jlizen

jlizen commented Jul 5, 2026

Copy link
Copy Markdown
Member

@shblue21 are you still interested in pursuing this PR?

@shblue21

shblue21 commented Jul 6, 2026

Copy link
Copy Markdown
Author

@jlizen Sorry, I missed this. I’ll take another look at the comments now.

@shblue21
shblue21 force-pushed the reject-multipart-ranges-before-validation branch from bcf90c6 to 136b535 Compare July 29, 2026 06:41
@shblue21

Copy link
Copy Markdown
Author

@jlizen For this PR, I’d prefer to keep returning 416 and only skip the unnecessary validation. We can discuss ignoring the Range header separately.

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.

3 participants