Skip to content

fix: reject multipart ranges before validation#661

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

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

Conversation

@shblue21
Copy link
Copy Markdown

@shblue21 shblue21 commented Apr 20, 2026

Motivation

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

That means requests that are guaranteed to be rejected still pay the cost of validate(file_size) first. In practice, this includes the pairwise overlap checks done during range validation.

Solution

Reject multipart ranges before calling validate(file_size).

This change keeps the fix small by only updating serve_dir/open_file.rs:

  • parse the range header as before
  • if more than one range is present, immediately return an error
  • only call validate(file_size) for single-range requests

This reuses the existing Err(_) -> 416 response path and adds a regression test covering a valid multipart range request.

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.

Refs: #660

@jplatte
Copy link
Copy Markdown
Member

jplatte commented Apr 21, 2026

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.

Copy link
Copy Markdown
Member

@jlizen jlizen left a comment

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?

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