8000 Range Requests are not correctly handled · Issue #38295 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content
Range Requests are not correctly handled #38295
Closed
@halaei

Description

@halaei

Symfony version(s) affected: dev-master

Description
According to https://tools.ietf.org/html/rfc7233, I see a few issues in implementation of range support in Symfony\Component\HttpFoundation\BinaryFileResponse. Here are some parts of rfc that I think are note implemented correctly:

  1. "The 416 (Range Not Satisfiable) status code indicates that none of the ranges in the request's Range header field overlap the current extent of the selected resource or ...".
    Current behaviour: The server respond with 416 status code when the end of selected range is greater than (or equal) the size of the file. It is problematic because because it prevents Nginx reverse proxies with slice config (used for caching large files) to correctly serve files, because the server returns 416 response for the last sliced requested by Nginx. My case is probably not a good use-case for a Symfony-based project, but I used it just for testing Nginx caching:

    location / {
        slice 1m;
        proxy_cache mycache;
        proxy_cache_key   $uri$is_args$args$slice_range;
        proxy_cache_valid 200 206 7d;
        proxy_pass http://example.com;
        proxy_set_header  Range $slice_range;
    }

    For a 1.5 MB files, the Nginx cache sends 2 requests to the upstream, one with Range: bytes=0-1048575 for the first 1-megabyte slice, and one with Range: bytes=1048576-2097151 for the rest of file. The second request is technically valid, because its range includes the rest of the file, so overlap is not empty. Based on Nginx implementation and the meaning of word "overlap" mentioned in the rfc, I thing it is not necessary for the end of the range to be smaller that the file size, however, such requests are rejected by this code:

    if ($start < 0 || $end > $fileSize - 1) {
    $this->setStatusCode(416);
    $this->headers->set( 6B18 'Content-Range', sprintf('bytes */%s', $fileSize));
    } elseif (0 !== $start || $end !== $fileSize - 1) {

  2. "An origin server MUST ignore a Range header field that contains a range unit it does not understand. A proxy MAY discard a Range header field that contains a range unit it does not understand."
    Current behaviour: 500 if length of unit isn't 5, and bytes range is assumed if length is 5.

  3. "A server MUST ignore a Range header field received with a request method other than GET."
    Current behaviour: Range header is not ignored for POST requests. I guess this is a minor/negligible issue.

  4. Multiple ranges are allowed in the rfc, but Symfony only handles the first range. This is probably fine too.

How to reproduce
Serve some random files with 2000 byte length and log the headers while sending requests to the server via curl/postman with Range header. Since I am using Laravel, here is my Laravel code:

Route::any('file', function (\Illuminate\Http\Request $request) {
    Log::info('headers', $request->header());
    file_put_contents('random.txt', \Illuminate\Support\Str::random(2000));
    return \Illuminate\Support\Facades\Response::file(
        'random.txt'
    )->setImmutable();
});
curl -X GET http://localhost:8000/file -H 'Range: bytes=1000-4000' 
curl -X POST http://localhost:8000/file -H 'Range: bytes=0-1'
curl -X POST http://localhost:8000/file -H 'Range: foo=1-1000'
curl -X POST http://localhost:8000/file -H 'Range: bytes=0-10, 1000-1010'

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0