Skip to content

Instantly share code, notes, and snippets.

@diakopter
Created September 16, 2011 00:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save diakopter/1220847 to your computer and use it in GitHub Desktop.
Save diakopter/1220847 to your computer and use it in GitHub Desktop.
role HTTP::Easy {
has Int $.port = 8080;
has Str $.host = 'localhost';
has $!listener = IO::Socket::INET.new(:localhost($.host), :localport($.port), :listen(1));
has $!connection is rw; ## To be populated by accept().
has %!env; ## The environment, generated by run().
has $!body is rw; ## Any request body, populated by run().
method run {
$*ERR.say: "{time} Started HTTP server.";
self.pre-connection;
while $!connection = $!listener.accept {
self.on-connection;
my $received = $!connection.recv();
my @request = split("\x0D\x0A", $received);
my $request = shift @request;
my ($method, $uri, $protocol) = $request.split(/\s/);
unless $method eq any(<GET POST HEAD PUT DELETE>) { die "unknown HTTP method"; }
my ($path, $query) = $uri.split('?', 2);
$query //= '';
## First, let's add our "known" headers.
%!env<REQUEST_METHOD> = $method;
%!env<PROTOCOL> = $protocol;
%!env<QUERY_STRING> = $query;
%!env<PATH_INFO> = $path;
%!env<REQUEST_URI> = $uri;
%!env<SERVER_NAME> = $.host;
%!env<SERVER_PORT> = $.port;
## Next, let's add HTTP request headers.
while my $header = shift @request { ## Will end at the first empty line.
my ($key, $value) = $header.split(': ');
if defined $key and defined $value {
$key ~~ s:g/\-/_/;
$key .= uc;
$key = 'HTTP_' ~ $key unless $key eq any(<CONTENT_LENGTH CONTENT_TYPE>);
if %!env.exists($key) {
%!env{$key} ~= ", $value";
}
else {
%!env{$key} = $value;
}
}
}
## Anything left in @request is now the body.
$!body = @request.join("\x0D\x0A"); ## Put it back together with CRLF.
my $res = self.handler; ## Call our handler. It can return an HTTP response, or handle it itself.
if defined $res {
$!connection.send($res);
}
$!connection.close;
}
}
## Stub methods. Replace with your own.
method pre-connection {};
method on-connection {};
method handler {}; ## This MUST be implemented.
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment