NAME
Feersum::Connection - HTTP connection encapsulation
SYNOPSIS
For a streaming response:
Feersum->endjinn->request_handler(sub {
my $req = shift; # this is a Feersum::Connection object
my $env = $req->env();
my $w = $req->start_streaming(200, ['Content-Type' => 'text/plain']);
# then immediately or after some time:
$w->write("Ergrates ");
$w->write(\"FTW.");
$w->close();
});
For a response with a Content-Length header:
Feersum->endjinn->request_handler(sub {
my $req = shift; # this is a Feersum::Connection object
my $env = $req->env();
$req->send_response(200, ['Content-Type' => 'text/plain'], \"Ergrates FTW.");
});
DESCRIPTION
Encapsulates an HTTP connection to Feersum. It's roughly analogous to an Apache::Request or Apache2::Connection object, but differs significantly in functionality.
With HTTP/1.1 Keep-Alive support, multiple requests can be served over the same connection.
See Feersum for more examples on usage.
METHODS
my $env = $req->env()-
Obtain an environment hash. This hash contains the same entries as for a PSGI handler environment hash, except
psgix.io(only added for PSGI handlers; use$req->io()instead). See Feersum for details on the contents. my $w = $req->start_streaming($code, \@headers)-
A full HTTP header section is sent with "Transfer-Encoding: chunked" (or "Connection: close" for HTTP/1.0 clients). For responses that MUST NOT have a body (1xx, 204, 205, 304), no Transfer-Encoding header is added regardless of HTTP version.
Returns a
Feersum::Connection::Writerhandle which should be used to complete the response. See Feersum::Connection::Handle for methods. $req->send_response($code, \@headers, $body)$req->send_response($code, \@headers, \@body)-
Respond with a full HTTP header (including
Content-Length) and body.Returns the number of bytes calculated for the body.
Zero-copy: a scalar-ref body (or the scalars inside an array-ref body) may be queued by reference rather than copied, and the response is transmitted after the handler returns. Do not modify a scalar after handing it to
send_response; see "Writer methods." in Feersum::Connection::Handle for the full contract and examples. Building a fresh scalar per response, which is what most code does anyway, is always safe.Header validation: response header names containing CR, LF or colon, and header values or status messages containing CR or LF, are rejected to prevent HTTP response splitting (CWE-113). In the PSGI dispatch path a 500 is sent; in the native interface the call croaks (propagates via "DIED" in Feersum).
$req->force_http10$req->force_http11-
Force the response to use HTTP/1.0 or HTTP/1.1, respectively, instead of matching the request version. Streaming uses
Transfer-Encoding: chunkedunder HTTP/1.1 and aConnection: closestream under HTTP/1.0; use these to override for user-agents that cannot handle one of them. $req->is_http11-
Returns true if the request was made using HTTP/1.1, false otherwise. Useful for determining protocol capabilities before sending a response. Also returns true for HTTP/2 streams (internally they reuse the HTTP/1.1 header semantics); check
SERVER_PROTOCOLin the env hash to distinguish HTTP/2. $req->is_keepalive-
Returns true if the connection has keep-alive enabled for this request. This takes into account the HTTP version, Connection header, and server configuration.
$req->fileno-
The socket file-descriptor number for this connection.
$req->io-
Returns an IO::Handle for the underlying connection. For plain (non-TLS) connections this wraps the raw socket file descriptor (an IO::Socket::INET, whether the underlying connection is TCP or Unix domain). For TLS and HTTP/2 Extended CONNECT connections, this returns one end of a Unix socketpair; Feersum relays data between the other end and the TLS or H2 layer transparently. The handle is bidirectional and suitable for WebSocket or other tunnel protocols.
This is the native interface equivalent of
psgix.ioin the PSGI environment. Any buffered request data will be pushed back into the handle's read buffer.WARNING: Once you call this method, Feersum relinquishes control of the socket. You are responsible for all I/O and must not use other Feersum response methods on this connection. On HTTP/2,
io()is supported only for Extended CONNECT tunnel streams (RFC 8441); calling it on a regular (non-tunnel) HTTP/2 stream croaks, since handing out the shared TCP socket would corrupt the other multiplexed streams. $req->return_from_io($io)-
Returns control of the socket to Feersum after
io()was called, so keep-alive can continue if the connection was not upgraded (a failed WebSocket handshake, say). Any data buffered in the IO handle is pulled back into Feersum's read buffer; returns the number of bytes pulled back.The hand-back ends the original request:
env()andmethod()croak afterwards, and a response sent from here is not shaped by the request (aHEADanswered after the hand-back gets a body), so decide before callingio().The hand-back takes a private duplicate of the descriptor, so
$iostays usable and may be released at any time; the socket stays open until it is.Croaks on TLS tunnel connections and HTTP/2 streams: neither can be handed back.
$req->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 unless keepalive is off. my $method = $req->method-
req method (GET/POST..) (psgi REQUEST_METHOD)
my $uri = $req->uri-
full request uri (psgi REQUEST_URI)
my $protocol = $req->protocol-
The HTTP version from the request line:
HTTP/1.1orHTTP/1.0.Note: unlike
$env->{SERVER_PROTOCOL}, this returnsHTTP/1.1for an HTTP/2 stream - it reports the request-line version, which HTTP/2 does not have. Check the env hash if you need to distinguish HTTP/2. my $path = $req->path-
percent decoded request path (psgi PATH_INFO)
my $query = $req->query-
request query (psgi QUERY_STRING)
my $len = $req->content_length-
body content length (psgi CONTENT_LENGTH)
my $input = $req->input-
Input body handler (psgi.input). Returns
undefwhen there is no body to read -- i.e. the (decoded) body length is zero, as for GET/HEAD or a zero-length POST. Note a chunked request with a non-empty body has no Content-Length yet still yields a handle. Check withdefinedbefore use. It is advised to close it after read is done. my $headers = $req->headers([normalization_style])-
Returns a hash reference of headers in form of { name => value, ... }.
normalization_style is one of (always use named constants, not numeric values):
HEADER_NORM_SKIP (0) - skip normalization (default) HEADER_NORM_UPCASE_DASH (1) - "CONTENT_TYPE" (like PSGI, but without "HTTP_" prefix) HEADER_NORM_LOCASE_DASH (2) - "content_type" HEADER_NORM_UPCASE (3) - "CONTENT-TYPE" HEADER_NORM_LOCASE (4) - "content-type"
One can export these constants via
use Feersum 'HEADER_NORM_LOCASE' my $value = $req->header(name)-
Lookup a single header value by name (case-insensitive). When multiple headers share the same name, values are joined with
", "(or"; "for cookies per RFC 9113 section 8.2.3). Returnsundefif the header is absent. my $addr = $req->remote_address-
Remote address of the connection (psgi REMOTE_ADDR). When PROXY protocol is active, returns the client address from the PROXY header; otherwise returns the socket peer address.
my $port = $req->remote_port-
Remote port of the connection (psgi REMOTE_PORT). When PROXY protocol is active, returns the client port from the PROXY header.
my $addr = $req->client_address-
Client address, respecting reverse proxy mode. When
reverse_proxyis enabled and the leftmost entry of X-Forwarded-For is a valid IPv4 or IPv6 address, returns that address. If the header is absent or its first value is not a valid IP (e.g. a hostname or spoofed string), returns the same asremote_address. my $scheme = $req->url_scheme-
URL scheme (http or https). Resolution order: (1) "https" if the connection uses TLS or HTTP/2, (2) "https" if PROXY protocol indicates SSL (PP2_TYPE_SSL TLV) or original destination port 443, (3) X-Forwarded-Proto header value when
reverse_proxyis enabled, (4) "http" otherwise. my $tlvs = $req->proxy_tlvs-
Returns a hash reference of PROXY protocol v2 TLV (Type-Length-Value) extensions, or
undefif no TLVs were received. Keys are TLV type numbers (as integers), values are raw TLV data bytes. Only populated whenproxy_protocolis enabled and the client sends a v2 header with TLV extensions (e.g. PP2_TYPE_SSL, PP2_TYPE_AUTHORITY). my $trailers = $req->trailers-
Returns an array reference of request trailers in form of [ name => value, ... ], or
undefif no trailers were received. Only supported for HTTP/2 requests currently.
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.