Created
January 7, 2011 01:47
-
-
Save miyagawa/768978 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package Nexus; | |
use strict; | |
use warnings; | |
use Carp; | |
use Nginx::Engine; | |
use HTTP::Parser::XS qw(parse_http_request); | |
use HTTP::Status qw(status_message); | |
use Plack::Util; | |
our $VERSION = 0.01; | |
sub new { | |
bless {}, shift; | |
} | |
sub register_service { | |
my($self, $app, $opts) = @_; | |
ngxe_init("", 512); | |
ngxe_server( | |
$opts->{host} || '*', | |
$opts->{port}, | |
sub { | |
my($conn, $remote_host) = @_; | |
ngxe_writer($conn, 0, 1000, '', sub { | |
return if $_[1];; | |
ngxe_close($_[0]); | |
}); | |
ngxe_reader($conn, NGXE_START, 5000, sub { | |
return if $_[1]; | |
my $env = { | |
REMOTE_ADDR => $remote_host, | |
REMOTE_HOST => $remote_host, | |
SERVER_NAME => $opts->{host} || '127.0.0.1', # XXX: needs to be resolved? | |
SERVER_PORT => $opts->{port}, | |
SCRIPT_NAME => '', | |
'psgi.version' => [ 1, 1 ], | |
'psgi.errors' => *STDERR, | |
'psgi.url_scheme' => 'http', | |
'psgi.nonblocking' => Plack::Util::TRUE, # but not AE compatible | |
'psgi.streaming' => Plack::Util::TRUE, | |
'psgi.run_once' => Plack::Util::FALSE, | |
'psgi.multithread' => Plack::Util::FALSE, | |
'psgi.multiprocess' => Plack::Util::FALSE, | |
'psgix.input.buffered' => Plack::Util::TRUE, | |
}; | |
my $rv = parse_http_request($_[2], $env); | |
if ($rv == -2) { | |
# request incomplete and less than 4k | |
return; | |
} elsif ($rv == -1) { | |
# request larger than 4k and incomplete or incorrect | |
my $content = "Bad Request"; | |
$_[3] = "HTTP/1.0 400 Bad Request\x0d\x0a". | |
"Connection: close\x0d\x0a". | |
"Content-Length: ".length($content)."\x0d\x0a". | |
"Content-Type: text/html\x0d\x0a". | |
"\x0d\x0a". | |
$content; | |
return; | |
} | |
# FIXME POST request doesn't work correctly | |
if ($env->{CONTENT_LENGTH}) { | |
if ($env->{CONTENT_LENGTH} > length($_[2])) { | |
# remove header from the read buffer | |
substr($_[2], 0, $rv, ''); | |
# setting minimum length of the data in the buffer to call handle with | |
$_[4] = $env->{CONTENT_LENGTH}; | |
return; | |
} | |
} | |
open my $input, "<", \$_[2]; | |
$env->{'psgi.input'} = $input; | |
my $res = $app->($env); | |
my $wbuf_r = \$_[3]; | |
if (ref $res eq 'ARRAY') { | |
$self->_handle_response($res, $conn, $wbuf_r); | |
} elsif (ref $res eq 'CODE') { | |
$res->(sub { | |
$self->_handle_response($_[0], $conn, $wbuf_r); | |
}); | |
} else { | |
die "Bad response $res"; | |
} | |
}); | |
}, | |
); | |
} | |
sub _handle_response { | |
my($self, $res, $conn, $wbuf_r) = @_; | |
my $hdrs = "HTTP/1.0 $res->[0] " . status_message($res->[0]) . "\015\012"; | |
my $headers = $res->[1]; | |
while (my($k, $v) = splice(@$headers, 0, 2)) { | |
$hdrs .= "$k: $v\015\012"; | |
} | |
$hdrs .= "\015\012"; | |
$$wbuf_r .= $hdrs; | |
my $body = $res->[2]; | |
my $cb = sub { $$wbuf_r .= $_[0] }; | |
if (defined $body) { | |
Plack::Util::foreach($body, $cb); | |
} else { | |
return Plack::Util::inline_object | |
write => sub { $$wbuf_r .= $_[0] }, | |
close => sub { ngxe_close($conn) }; | |
} | |
} | |
sub run { | |
my $self = shift; | |
$self->register_service(@_); | |
ngxe_loop(); | |
} | |
1; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment