phasync
Request handlers / RequestBody

Class

RequestBody

A request's body as a PSR-7 stream, read from the ClientRequest as the application reads it.

Introduction#

Nothing is buffered and nothing is read ahead: read() waits in phasync's event loop for the next bytes of the body, and returns '' only at its end. The body is therefore only as large in memory as the application makes it, and Expect: 100-continue is answered when the application first reads. The stream is not seekable, and cannot be read once the exchange is over.

close() does nothing: the exchange owns the connection, and a framework that tidies up by closing the request's body must not end the response with it.

A framework adapter (swerve-psr15, Symfony, Tether) builds one of these for a ClientRequest's body, the same way for every framework: FormBody is its form data, parsed the same way too.

Class synopsis#

final class RequestBody implements StreamInterface, \Stringable {
    /* Methods */
    public RequestBody::__construct(ClientRequest $request, ?int $size)
    public RequestBody::__toString(): string
    public RequestBody::close(): void
    public RequestBody::detach()
    public RequestBody::getSize(): ?int
    public RequestBody::tell(): int
    public RequestBody::eof(): bool
    public RequestBody::isSeekable(): bool
    public RequestBody::seek($offset, $whence = SEEK_SET): void
    public RequestBody::rewind(): void
    public RequestBody::isWritable(): bool
    public RequestBody::write($string): int
    public RequestBody::isReadable(): bool
    public RequestBody::read($length): string
    public RequestBody::getContents(): string
    public RequestBody::getMetadata($key = null)
}

Methods#

MethodDescription
__constructWrap the body of $request; nothing is read until the application reads.
__toStringThe rest of the body, read to its end: getContents().
closeCloses the stream and any underlying resources.
detachSeparates any underlying resources from the stream.
getSizeGet the size of the stream if known.
tellReturns the current position of the file read/write pointer
eofReturns true if the stream is at the end of the stream.
isSeekableReturns whether or not the stream is seekable.
seekSeek to a position in the stream.
rewindSeek to the beginning of the stream.
isWritableReturns whether or not the stream is writable.
writeWrite data to the stream.
isReadableReturns whether or not the stream is readable.
readRead data from the stream.
getContentsReturns the remaining contents in a string
getMetadataGet stream metadata as an associative array or retrieve a specific key.

Examples#

Example 1Read a body as it arrives
use Swerve\ClientRequest;
use Swerve\Psr\RequestBody;
use Swerve\RequestHandler;

$app = new RequestHandler(function (ClientRequest $request) {
    $length = $request->getRequestHeaders()['content-length'][0] ?? null;
    $body   = new RequestBody($request, null === $length ? null : (int) $length);   // a PSR-7 stream

    $lines = 0;
    while ('' !== ($bytes = $body->read(8192))) {   // waits for the next bytes; '' only at the end
        $lines += substr_count($bytes, "\n");
    }
    $request->write("received {$body->getSize()} bytes, $lines lines\n");
});

if (debug_backtrace()) {
    return $app;   // swerve loads this file: it is the application's swerve.php
}

// Run directly: serve the application with swerve, and send it requests
require __DIR__ . '/../serve.php';
$csv = "id,name\n1,ann\n2,bob\n3,cy\n";
serve(__FILE__, ["POST /import HTTP/1.1\r\nHost: example\r\nContent-Length: " . strlen($csv) . "\r\n\r\n$csv"]);
Output
HTTP/1.1 200 OK
Server: Swerve
Transfer-Encoding: chunked
Connection: close

1b
received 25 bytes, 4 lines

0