Skip to content

StreamedBinaryFileResponse — Incorrect Chunking Logic #27

@s2x

Description

@s2x

StreamedBinaryFileResponse — Incorrect Chunking Logic

Problem Description

In src/Protocol/Http/Response/StreamedBinaryFileResponse.php:42-51, the inner while loop is problematic and unnecessarily complicated.

Location

src/Protocol/Http/Response/StreamedBinaryFileResponse.php, lines 36-52

Analysis

Current code:

while ($length && !$file->eof()) {
    $read = $length > $this->chunkSize || 0 > $length ? $this->chunkSize : $length;
    if (false === $data = $file->fread($read)) {
        break;
    }
    while ('' !== $data) {
        yield $data;
        if (connection_aborted() !== 0) {
            break 2;
        }
        if (0 < $length) {
            $length -= $read;
        }
        $data = substr($data, $read);
    }
}

The inner while loop is effectively a no-op in most cases:

  • fread() returns a chunk of appropriate size
  • substr($data, $read) when $read >= strlen($data) returns an empty string
  • The loop executes exactly once

Proposed Solution

Simplify to one yield per fread:

while ($length && !$file->eof()) {
    $read = ($length > $this->chunkSize || 0 > $length) ? $this->chunkSize : $length;
    $data = $file->fread($read);
    if ($data === false || $data === '') {
        break;
    }
    yield $data;
    if (connection_aborted() !== 0) {
        break;
    }
    if (0 < $length) {
        $length -= strlen($data);
    }
}

Note: $length -= strlen($data) instead of $length -= $read — because fread may return fewer bytes than requested.

Priority

🟡 MEDIUM — works in most cases, but logic is incorrect in edge cases.

Tests

Test streaming of a large file and verify that all bytes are correctly yielded.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestmediumMedium priority

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions