Skip to content

static.php: RFC 7233 suffix-range bug and built-in server compatibility issues #10143

@JohnRDOrazio

Description

@JohnRDOrazio

Summary

static.php has several bugs in its range request handling and file serving logic that cause incorrect responses and potential corruption on the PHP built-in server.

Bugs

1. Suffix-range requests return wrong bytes (RFC 7233 violation)

Per RFC 7233 Section 2.1, bytes=-500 means "the last 500 bytes". The current code splits on - to get ["", "500"], then sets the empty first element to 0:

if ($range[0] === '') {
    $range[0] = 0;
}

This turns bytes=-500 into bytes=0-500, serving the first 501 bytes instead of the last 500 bytes. The Content-Range header is also wrong (bytes 0-500/1058 instead of bytes 558-1057/1058).

2. Suffix-range larger than file returns 416 instead of 206

Per RFC 7233: "If the selected representation is shorter than the specified suffix-length, the entire representation is used."

bytes=-9999 on a 1058-byte file is interpreted as bytes=0-9999. The bounds check $range[1] <= $size - 1 fails (9999 > 1057), returning 416 "Range Not Satisfiable" instead of serving the full file.

3. Headers sent before file handle validation

http_response_code(206) and response headers are sent before fopen() is called. If fopen() fails, the 500 error code cannot take effect because headers were already sent. The client receives a 206 with the promised Content-Length but an empty body.

4. Output buffer corruption on PHP built-in server

When output buffering is active (e.g., php.ini output_buffering=On), buffer content is prepended to the file output. Content-Length is calculated from filesize() and doesn't account for the buffer, so HTTP clients read Content-Length bytes starting with the buffer junk, truncating the end of the actual file. This causes broken CSS/JS delivery.

Steps to reproduce

Suffix-range bug (using any HTTP client):

curl -H "Range: bytes=-500" http://localhost/static.php/program/resources/dummy.pdf -o /dev/null -D -

The Content-Range header will show bytes 0-500/1058 instead of the expected bytes 558-1057/1058.

Environment

  • Roundcube: master branch (1.7-beta / 1.7-rc)
  • PHP: 8.1+

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions