Skip to content

Instantly share code, notes, and snippets.

@typester
Created September 14, 2009 01:57
Show Gist options
  • Save typester/186434 to your computer and use it in GitHub Desktop.
Save typester/186434 to your computer and use it in GitHub Desktop.
use strict;
use warnings;
use Getopt::Long;
use AnyEvent::Socket;
use AnyEvent::Handle;
use HTTP::Parser::XS qw(parse_http_request);
GetOptions(
\my %option,
qw/port=i/
);
$option{port} ||= 12345;
my $max_req_size = 131072;
sub handle_request {
my ($handle, $env) = @_;
if ($env->{REQUEST_METHOD} ne 'GET') {
# todo return 403
return;
}
my $content = "hello world!\n";
my $keep_alive = ($env->{HTTP_CONNECTION} || '') =~ /keep-alive/i;
my $res = join(
"\r\n",
'HTTP/1.0 200 OK',
'Content-Type: text/plain',
'Content-Length: ' . length($content),
($keep_alive ? 'Connection: keep-alive' : ()),
'',
$content,
);
$handle->push_write($res);
$keep_alive;
}
tcp_server undef, $option{port}, sub {
my ($fh) = @_ or die $!;
my $handle; $handle = AnyEvent::Handle->new(
fh => $fh,
on_error => sub {
undef $handle;
},
);
$handle->on_read(sub {
my ($h) = @_;
my $reqlen = parse_http_request($h->{rbuf}, \my %env);
if ($reqlen >= 0) {
$h->{rbuf} = substr $h->{rbuf}, $reqlen;
if (! handle_request($h, \%env)) {
$h->destroy;
}
}
elsif ($reqlen == -2) {
}
elsif ($reqlen == -1) {
$h->destroy;
}
});
};
AnyEvent->condvar->recv;
use strict;
use warnings;
use Getopt::Long;
use HTTP::Parser::XS qw(parse_http_request);
use Danga::Socket;
use Danga::Socket::Callback;
use IO::Handle;
use IO::Socket::INET;
use Socket qw/IPPROTO_TCP TCP_NODELAY/;
GetOptions(
\my %option,
qw/port=i/
);
$option{port} ||= 12345;
my $max_req_size = 131072;
sub handle_request {
my ($socket, $env) = @_;
if ($env->{REQUEST_METHOD} ne 'GET') {
# todo return 403
return;
}
my $content = "hello world!\n";
my $keep_alive = ($env->{HTTP_CONNECTION} || '') =~ /keep-alive/i;
my $res = join(
"\r\n",
'HTTP/1.0 200 OK',
'Content-Type: text/plain',
'Content-Length: ' . length($content),
($keep_alive ? 'Connection: keep-alive' : ()),
'',
$content,
);
$socket->write(\$res);
$keep_alive;
}
my $ss = IO::Socket::INET->new(
LocalPort => $option{port},
Proto => 'tcp',
Listen => SOMAXCONN,
ReuseAddr => 1,
Blocking => 0,
) or die $!;
IO::Handle::blocking($ss, 0);
Danga::Socket->AddOtherFds(
fileno($ss) => sub {
my $cs = $ss->accept or return;
IO::Handle::blocking($cs, 0);
setsockopt($cs, IPPROTO_TCP, TCP_NODELAY, pack('l', 1)) or die $!;
my $rbuf = '';
Danga::Socket::Callback->new(
handle => $cs,
on_read_ready => sub {
my $socket = shift;
my $bref = $socket->read($max_req_size);
unless (defined $bref) {
$socket->close;
return;
}
$rbuf .= $$bref;
my $reqlen = parse_http_request($rbuf, \my %env);
if ($reqlen >= 0) {
$rbuf = substr $rbuf, $reqlen;
if (! handle_request($socket, \%env)) {
$socket->close;
}
}
elsif ($reqlen == -2) {
# request is incomplete
}
elsif ($reqlen == -1) {
# error, close conn (TODO send 400)
$socket->close;
}
},
);
},
);
Danga::Socket->AddTimer(0, sub {
my $poll
= $Danga::Socket::HaveKQueue ? 'kqueue'
: $Danga::Socket::HaveEpoll ? 'epoll'
: 'poll';
print "Server started ($poll), http://localhost:$option{port}\n";
});
Danga::Socket->EventLoop;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment