HTTP::Supply::Request - A modern HTTP/1.x request parser
NAME
HTTP::Supply::Request - A modern HTTP/1.x request parser
SYNOPSIS
use HTTP::Supply::Request;
react { whenever IO::Socket::Async.listen('localhost', 8080) -> $conn { my $envs = HTTP::Supply::Request.parse-http($conn); whenever $envs -> %env { my $res = await app(%env); handle-response($conn, $res);
QUIT { when X::HTTP::Supply::UnsupportedProtocol { $conn.print("505 HTTP Version Not Supported HTTP/1.1\r\n"); $conn.print("Content-Length: 26\r\n"); $conn.print("Content-Type: text/plain\r\n\r\n"); $conn.print("HTTP Version Not Supported\r\n");
.note; $conn.close; }
when X::HTTP::Supply::BadMessage { $conn.print("400 Bad Request HTTP/1.1\r\n"); $conn.print("Content-Length: " ~ .message.encode.bytes ~ \r\n"); $conn.print("Content-Type: text/plain\r\n\r\n"); $conn.print(.message); $conn.print("\r\n");
.note; $conn.close; }
default { $conn.print("500 Internal Server Error HTTP/1.1\r\n"); $conn.print("Content-Length: 22\r\n"); $conn.print("Content-Type: text/plain\r\n\r\n"); $conn.print("Internal Server Error\r\n");
.note; $conn.close; } } } } }
METHODS
method parse-http
method parse-http(HTTP::Supply::Request: Supply:D() $conn, Bool :$debug = False) returns Supply:D
The given Supply, $conn
, must emit a stream of bytes. Any other data will
result in undefined behavior. The parser assumes that only binary bytes will be
sent and makes no particular effort to verify that assumption.
The returned supply will react whenever data is emitted on the input supply. The incoming bytes are collated into HTTP frames, which are parsed to determine the contents of the headers. Headers are encoded into strings via ISO-8859-1 (as per RFC7230 ยง3.2.4).
Once the headers for a given frame have been read, a partial RakuWAPI compatible environment is generated from the headers and emitted to the returned Supply. The environment will be filled as follows:
=over
If a
Content-Length
header is present, it will be set inCONTENT_LENGTH
.If a
Content-Type
header is present, it will be set inCONTENT_TYPE
.Other headers will be set in
HTTP_*
where the header name is converted to uppercase and dashes are replaced with underscores.The
REQUEST_METHOD
will be set to the method given in the request line.The
SERVER_PROTOCOL
will be set to the protocol given in the request line. (As of this writing, this will always be either HTTP/1.0 or HTTP/1.1 as these are the only protocol versions this module currently supports.)The
REQUEST_URI
will be set to the URI given in the request line.The
wapi.input
variable will be set to a sane Supply that emits chunks of the body as bytes as they arrive. No attempt is made to decode these bytes.
=back
No other keys will be set. A complete RakuWAPI environment must contain many other keys.
DIAGNOSTICS
The following exceptions are thrown by this class while processing input, which will trigger the quit handlers on the Supply.
X::HTTP::Supply::UnsupportedProtocol
This exception will be thrown if the stream does not seem to be HTTP or if the requested HTTP version is not 1.0 or 1.1.
X::HTTP::Supply::BadMessage
This exception will be thrown if the HTTP request is incorrectly framed. This
may happen when the request does not specify its content length using a
Content-Length
header or chunked Transfer-Encoding
.
CAVEATS
This code aims at providing a minimal implementation that is just enough to decode the HTTP frames and provide the information about the raw requests to the tapping code. It is not safe to assume that anything provided has been validated or processed.
HTTP is complicated and hard. This implementation is not yet complete and not battle tested yet. Please report bugs to github and patches are welcome. Even once this code matures, it will never receive the TLC that a full-blown general web server is going to get as regards hardening and maturity on the Internet. As such, the author always recommends using this code behind an existing, well-known, and well-maintained web server in production. This is only ever intended as a "bare metal" application server interface.
This interface is built with the intention of making it easier to build HTTP/1.0 and HTTP/1.1 parsers for use with RakuWAPI. As of this writing, that specification is only a proposed draft, so the output of this module is experimental and will change as that specification changes.
Finally, this module only takes responsibility for parsing the incoming HTTP frames. It does not manage the connection and it provides no tools for sending responses back to the user agent.
AUTHOR
Sterling Hanenkamp < <[email protected]> >
COPYRIGHT & LICENSE
Copyright 2016 Sterling Hanenkamp.
This software is licensed under the same terms as Raku.