VOOZH about

URL: https://deepwiki.com/hypervel/http/3.3-streaming-and-range-requests

⇱ Streaming & Range Requests | hypervel/http | DeepWiki


Loading...
Menu

Streaming & Range Requests

This page documents the streaming response and HTTP range request capabilities provided by the Response class. These features enable efficient delivery of large content and partial content delivery for resumable downloads.

Scope: This page covers streamed responses with chunked transfer encoding, streamed file downloads, and HTTP range request handling (RFC 7233). For basic response creation methods, see Response Types. For JSON resource transformations, see JSON Resources.


Overview

The streaming and range request subsystem provides three main capabilities:

CapabilityMethodUse Case
Streamed Responsesstream()Real-time data delivery, server-sent events, progressive content
Streamed DownloadsstreamDownload()Large file downloads without loading entire file into memory
Range RequestswithRangeHeaders()Partial content delivery, resumable downloads, video seeking

Sources: src/Response.php266-442


Streamed Responses

Creating a Stream

The stream() method creates a response that uses chunked transfer encoding to deliver content progressively. This is essential for real-time data delivery or when the full content size is unknown at response creation time.


Key behaviors:

  • Default Content-Type: text/event-stream (can be overridden in headers)
  • Removed Headers: Transfer-Encoding, Accept-Encoding, Content-Length are automatically removed
  • Immediate Sending: Headers and status are sent immediately before streaming begins
  • Range Support: Range headers are automatically appended if enabled via withRangeHeaders()

Sources: src/Response.php266-314

StreamOutput Interface

The callback receives a StreamOutput instance for writing content:


The write() method returns a boolean indicating success. Content is immediately sent to the client without buffering.

Sources: src/StreamOutput.php1-21

Example Usage Pattern


Sources: src/Response.php266-314


Streamed Downloads

Creating a Streamed Download

The streamDownload() method creates a streamed response optimized for file downloads. It automatically sets appropriate headers for browser download behavior.

HeaderDefault ValuePurpose
Content-Typeapplication/octet-streamGeneric binary content type
Content-DescriptionFile TransferIndicates file transfer operation
Content-Dispositionattachment; filename="..."Triggers browser download
Pragmano-cachePrevents caching

Method Signature:


Parameters:

  • $callback: Receives StreamOutput for writing content chunks
  • $filename: Sets filename parameter in Content-Disposition (optional)
  • $headers: Additional headers (override defaults)
  • $disposition: Either 'attachment' or 'inline' (default: 'attachment')

Sources: src/Response.php316-339

Content-Disposition Generation

The Content-Disposition header is generated using HeaderUtils::makeDisposition(), which handles:

  • Unicode Filenames: Uses RFC 6266 filename* parameter with UTF-8 encoding
  • ASCII Fallback: Provides filename parameter for older clients
  • Special Character Encoding: Properly escapes and quotes filenames

Sources: src/Response.php323-338 src/HeaderUtils.php185-216


HTTP Range Request Support

Overview

Range request support enables clients to request partial content, which is essential for:

  • Resumable Downloads: Client can resume interrupted downloads
  • Video Seeking: Client can request specific segments for playback
  • Bandwidth Optimization: Client can request only needed portions

The implementation follows RFC 7233 (HTTP Range Requests).

Sources: src/Response.php344-423

Enabling Range Support


Method: withRangeHeaders(?int $fileSize = null)

  • Stores range configuration in request context using key RANGE_HEADERS_CONTEXT
  • Optional $fileSize parameter enables validation of range bounds
  • Returns $this for method chaining
  • Context is automatically cleared after headers are appended

Disabling: withoutRangeHeaders() removes range support for the current response.

Sources: src/Response.php344-361

Range Request Processing Flow


Sources: src/Response.php386-423 src/HeaderUtils.php276-328

Accept-Ranges Header

The Accept-Ranges header is automatically set based on the HTTP method:

MethodAccept-Ranges ValueRationale
GET, HEAD, OPTIONS, TRACEbytesSafe methods support ranges
POST, PUT, DELETE, PATCHnoneNon-safe methods don't support ranges

Sources: src/Response.php392-396

Content-Range Header Format

When a valid range is requested, the Content-Range header is set to indicate the byte range being delivered:

Content-Range: bytes <start>-<end>/<total>

Examples:

  • Content-Range: bytes 0-1023/2048 - First 1024 bytes of 2048 byte file
  • Content-Range: bytes 1024-2047/2048 - Last 1024 bytes
  • Content-Range: bytes 500-*/5000 - From byte 500 to end (5000 bytes total)
  • Content-Range: bytes 0-999/* - First 1000 bytes, total size unknown

Sources: src/Response.php416-421

Range Header Validation

The HeaderUtils::validateRangeHeaders() method parses and validates range requests:


Validation Rules:

  • start >= 0 (cannot be negative)
  • start <= end (start must not exceed end)
  • start < fileSize (start must be within file bounds, if fileSize known)
  • Throws RangeNotSatisfiableHttpException (416) if validation fails

Range Syntax Support:

  • bytes=100-199 - Bytes 100-199 (inclusive)
  • bytes=100- - From byte 100 to end of file
  • bytes=-500 - Last 500 bytes (suffix range)

Sources: src/HeaderUtils.php276-328

Conditional Range Requests (If-Range)

The If-Range header enables conditional range requests. The client includes either an ETag or Last-Modified timestamp:


Use Case: Client requests a range but wants the full resource if it has been modified since their cached version.

Implementation: src/Response.php425-442

  • Compares If-Range value against response's ETag header
  • Falls back to comparing against Last-Modified header (RFC 2822 format)
  • Returns true if validation passes, allowing range request to proceed

Sources: src/Response.php402-442


Integration with Hyperf Swoole

Chunked Response Requirements

The streaming functionality requires the response to implement Hyperf\HttpMessage\Server\Chunk\Chunkable:


If the response does not implement Chunkable, a RuntimeException is thrown:

"The response is not a chunkable response."

Sources: src/Response.php273-276

Manual Header Transmission

Unlike standard responses, streamed responses require manual transmission of headers before content streaming begins:


This is necessary because the Hyperf response emitter normally sends headers at the end of the request lifecycle, but streamed responses need headers sent before content delivery begins.

Sources: src/Response.php298-306


HTTP Status Codes

The streaming and range system uses specific HTTP status codes defined as class constants:

ConstantCodeUsage
HTTP_PARTIAL_CONTENT206Set when serving a range request
HTTP_REQUESTED_RANGE_NOT_SATISFIABLE416Invalid range (handled by HeaderUtils)

Sources: src/Response.php48 src/Response.php106 src/Response.php415


Context Management

Range header configuration is stored in the request context to maintain state across method calls:


Context Key: Response::RANGE_HEADERS_CONTEXT = '_response.withRangeHeaders'

Storage Structure:


The context is automatically destroyed after being read to prevent reuse across multiple responses in the same request lifecycle.

Sources: src/Response.php157 src/Response.php344-381


Error Handling

Range Request Errors

When range validation fails, HeaderUtils::validateRangeHeaders() throws RangeNotSatisfiableHttpException with appropriate headers:


This results in a 416 status code with a Content-Range header indicating the valid range.

Sources: src/HeaderUtils.php292-319

Streaming Errors

If the response does not support chunking, a RuntimeException is thrown immediately when calling stream():


Sources: src/Response.php274-276


Summary Table

FeatureMethodKey HeadersStatus Code
Basic Streamingstream()Content-Type: text/event-stream200
Download StreamingstreamDownload()Content-Disposition: attachment200
Range SupportwithRangeHeaders()Accept-Ranges: bytes200 or 206
Partial Content(automatic)Content-Range: bytes X-Y/Z206
Invalid Range(automatic)Content-Range: bytes */Z416

Sources: src/Response.php266-442 src/HeaderUtils.php276-328