NAME

Feersum::Connection::Handle - PSGI-style reader/writer objects.

SYNOPSIS

For read handles:

my $buf;
my $r = delete $env->{'psgi.input'};
$r->read($buf, 1, 1); # read the second byte of input without moving offset
$r->read($buf, $env->{CONTENT_LENGTH}); # append the whole input
my $line = $r->getline;  # or <$r>: one record, honouring $/
$r->close(); # discards any un-read() data

# assuming the handle is "open":
$r->seek(2,SEEK_CUR); # returns 1, discards skipped bytes
$r->seek(-1,SEEK_CUR); # returns 0, can't seek back

$r->poll_cb(sub { .... });

For write handles:

$w->write("scalar");
$w->write(\"scalar ref");
$w->write_array(\@some_stuff);
$w->poll_cb(sub {
    # use $_[0] instead of $w to avoid a closure
    $_[0]->write(\"some data");
    # can close() or unregister the poll_cb in here
    $_[0]->close();
});

For both:

$h->response_guard(guard { response_is_complete() });

DESCRIPTION

See the PSGI spec for more information on how read/write handles are used (The Delayed Response and Streaming Body section has details on the writer).

METHODS

Reader methods

The reader is obtained via $env->{'psgi.input'}.

$r->read($buf, $len)

Read up to $len more bytes of the request body and append them to $buf. Unlike Perl's read/sysread, $buf is not truncated first, so the usual drain loop must clear it (or use a fresh scalar) each time round:

my $body = '';
while ($r->read(my $chunk, 4096)) { $body .= $chunk }   # $chunk is fresh

Never read into a buffer that outlives the request - a closure variable, a package global, or a lexical hoisted out of the loop. Because the append is not reset, such a buffer accumulates: within one request the body is silently duplicated, and across requests a later handler can see an earlier client's request body still sitting in front of its own.

An optional third argument is an offset into the input to read from without advancing the current position. Returns the number of bytes read, or 0 at end of input.

The same warning applies to the reader itself, not just the buffer: a handle wraps the connection, not one request. A reader kept past the response it belongs to goes on reading whatever the connection is carrying now, so on a keep-alive connection it returns the next request's body. Let it go when the request is done.

The calls to $r->read() will never block: the entire body is buffered in memory before the Feersum request handler is called (use poll_cb for incremental delivery). psgix.input.buffered is still not set in the PSGI env hash: that flag also promises a rewindable handle, and this one is forward-only - reads consume the buffer, and seek cannot go back. Consumers that need re-readable input (Plack::Request, for example) buffer the body themselves when the flag is absent.

$r->getline()

Read one record from the input, following readline/<$fh> semantics for $/: the default "\n" and any plain-string separator return one record including the separator (the final record may lack it), local $/ = undef slurps all remaining input, \$n reads fixed-size records, and "" reads paragraphs. Returns undef at end of input. Like read(), it never blocks, and it stops at the end of the current request's body.

$r->getlines()

All remaining records as a list. Croaks in scalar context, as "getlines" in IO::Handle does.

The reader also overloads the diamond operator in both scalar and list context, so <$fh> works - including the slurp idiom shipped Plack code uses on psgi.input (local $/; <$fh> in Plack::App::WrapCGI):

my $line  = <$r>;            # one record
my @lines = <$r>;            # all remaining records (perl 5.18+)
my $body  = do { local $/; <$r> };   # slurp

Perl hands an overloaded <> the caller's list context only from 5.18 on; before that my @lines = <$r> yields a single record. Use $r->getlines if you need the list on older perls. Scalar context, including the slurp above, behaves the same everywhere.

$r->seek(...)

Seeking is partially supported. Feersum discards skipped-over bytes to conserve memory. Note: SEEK_SET is treated the same as SEEK_CUR (always relative to the current position), since the underlying buffer is consumed as it is read and absolute positioning is not supported.

$r->seek(0,SEEK_CUR);  # returns 1
$r->seek(-1,SEEK_CUR); # returns 0
$r->seek(-1,SEEK_SET); # returns 0
$r->seek(2,SEEK_CUR);  # returns 1, discards 2 bytes
$r->seek(42,SEEK_SET); # same as SEEK_CUR: discards 42 bytes
$r->seek(-8,SEEK_END); # returns 1 if room, discards skipped bytes
$r->close()

Discards the remainder of the input buffer. It does not affect connection reuse: when the request body has already been received in full (the usual case) the connection stays eligible for keep-alive and an already-pipelined next request is still served.

$r->poll_cb(sub { .... })

Register a callback to be called when more request body data is available. The callback receives the Reader object as its argument. On a normal HTTP/1.x or HTTP/2 request the handler runs only after the whole body has arrived, so the callback drains an already-complete buffer; it becomes a true incremental reader only after io()/psgix.io takes over the byte stream. See "psgi.input" in Feersum.

Writer methods.

The writer is obtained under PSGI by sending a code/headers pair to the "starter" callback. Under Feersum, calls to $req->start_streaming return one.

$w->write("scalar")

Send the scalar as a chunk of the streaming response body. For HTTP/1.1 clients this uses Transfer-Encoding: chunked framing; for HTTP/1.0 (Connection: close) streaming the data is written without chunk framing.

The calls to $w->write() will never block and data is buffered until transmitted. This behaviour is indicated by psgix.output.buffered in the PSGI env hash (Twiggy supports this too, for example).

Buffering is zero-copy: do not modify a scalar after passing it to write(). Feersum does not copy the bytes. It keeps a reference to your scalar and points the pending writev() directly at that scalar's internal string buffer, and the actual transmission happens after your handler (or callback) returns. Modifying the scalar in the meantime changes, or frees, the memory that is about to be sent:

# WRONG - all five chunks arrive as "line 5"
my $line;
for my $i (1 .. 5) {
    $line = sprintf("line %d\n", $i);
    $w->write($line);
}

# WRONG - the reassignment reallocates, and the queued chunk is
# left pointing at freed memory
$w->write($buf);
$buf = "x" x 200_000;

# RIGHT - a fresh scalar per write; the old ones stay untouched
for my $i (1 .. 5) {
    $w->write(sprintf("line %d\n", $i));
}

Passing an expression or a literal is always safe, because the temporary it produces is private to Feersum and nothing else can reach it. Only scalars you still hold a handle on are at risk. A scalar becomes yours to reuse once the data has actually gone out - that is, from $w->close() onwards, or inside a poll_cb that fires after the buffer has drained past it. If in doubt, build a new scalar instead of reusing one; in Perl that is cheap, and it is always correct.

The same applies to $r->write(\$scalar), $w->write_array and to scalar-ref bodies passed to $req->send_response below.

$w->write(\"scalar ref")

Works just like write("scalar") above, including the zero-copy contract: the referenced scalar must not be modified until the response completes. This extension is indicated by psgix.body.scalar_refs in the PSGI env hash.

$w->write_array(\@array)

Pass in an array-ref and it works much like the two write() calls above, except it's way more efficient than calling write() over and over. Undefined elements of the array are ignored. The zero-copy contract applies to every element: neither the array nor the scalars in it may be modified until the response completes.

$w->close()

Close the HTTP response (which triggers the "T-E: chunked" terminating chunk to be sent). This method is implicitly called when the last reference to the writer is dropped.

$w->poll_cb(sub { .... })

Register a callback to be called when the write buffer drains to (or below) the server's wbuf_low_water threshold (default: 0, i.e. empty). Pass in undef to unset. The sub can call close().

A reference to the writer is passed in as the first and only argument to the sub. It's recommended that you use $_[0] rather than closing-over on $w to prevent a circular reference.

That argument is good for the duration of the call only - it is neutralised when the callback returns, so keeping it and writing through it later croaks "Handle is closed". The writer start_streaming gave you stays valid; use that one if you need to write from somewhere else.

Each call is an invitation, not a busy-poll. A callback that has nothing to say yet can simply return without writing: the response is then parked and re-invited on a gentle backoff (roughly 1ms doubling to 100ms, reset by any write), instead of being called in a tight loop. Writing from any other event source - a timer, an upstream socket - resumes the stream immediately, which is the recommended shape for relays and SSE. A zero-length $w->write("") counts as engagement and requests an immediate re-invitation; use it only when more data really is imminent, since a callback that does nothing but empty writes runs at full speed. These rules apply identically to HTTP/1.x (plain and TLS) and HTTP/2. A parked response has no write deadline - like any quietly waiting stream, ending it is the application's job - but a client that disconnected is normally noticed at the next paced retry (on TLS only when the close was abrupt; a graceful close_notify is only noticed on the next write, as for any quiet stream).

Something else must then keep the writer alive. Dropping the last reference calls DESTROY, which closes the writer and so ends the response - and because that also clears the poll callback, a writer whose only reference was the lexical in the handler is closed the moment the handler returns, sending an empty response instead of a streamed one. Stash it (in a hash keyed by the connection, say) for as long as the response is meant to last.

$w->sendfile($fh [, $offset, $length])

Send file contents using zero-copy sendfile(2) system call. Linux only. The file handle should be a regular file opened for reading. After calling sendfile(), call close() on the writer.

The response must carry an explicit Content-Length, and sendfile() croaks otherwise. sendfile(2) writes the file verbatim, so it cannot chunk-frame the data: on an HTTP/1.1 streaming response with no Content-Length - which is Transfer-Encoding: chunked - the file bytes would go out unframed and desynchronise the connection. Setting Content-Length suppresses chunking, which is what makes sendfile usable.

Optional $offset (bytes to skip from start, default 0) and $length (bytes to send, default remainder of file) allow sending a portion of the file.

Note: Not supported for HTTP/2 responses. Use write() instead.

my $w = $req->start_streaming(200, [
    'Content-Type' => 'application/octet-stream',
    'Content-Length' => -s $filename,
]);
open my $fh, '<', $filename or die $!;
$w->sendfile($fh);
close $fh;
$w->close();

Common methods.

Methods in common to both types of handles.

$h->return_from_psgix_io($io)

Returns control of the socket back to Feersum after psgix.io was used. This is the PSGI-handle equivalent of $req->return_from_io($io) on the connection object. As there, the hand-back takes a private duplicate of the descriptor, so $io stays usable and is safe to release at any time. See "$req->return_from_io($io)" in Feersum::Connection.

$h->response_guard($guard)

Register a guard to be triggered when the response is completely sent and the socket is closed. A "guard" in this context is some object that will do something interesting in its DESTROY/DEMOLISH method. For example, Guard.

On a keepalive connection this is not when the response finishes. The guard is released at whichever comes first: the next response_guard() call on the same connection, which replaces it, or the connection closing. So an app that registers one on every request sees request N's guard fire during request N+1's handler, and the last one only at close. Do not use a guard to release a per-request resource (a database handle, a rate-limit slot) unless keepalive is off, or it stays held for the life of the connection.

The guard is *not* attached to this handle object; the guard is attached to the response.

psgix.output.guard is the PSGI-env extension that indicates this method.

$h->fileno

Returns the file descriptor number for this connection.

AUTHOR

Jeremy Stashewsky, stash@cpan.org

COPYRIGHT AND LICENSE

Copyright (C) 2010 by Jeremy Stashewsky & Socialtext Inc.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.14 or, at your option, any later version of Perl 5 you may have available.