DTA-CAB
view release on metacpan or search on metacpan
CAB/Server/HTTP.pm view on Meta::CPAN
## Methods: Generic Server API
##==============================================================================
## $rc = $srv->prepareLocal()
## + subclass-local initialization
sub prepareLocal {
my $srv = shift;
##-- setup HTTP::Daemon object
$srv->{daemonArgs}{Listen} ||= SOMAXCONN;
if (!($srv->{daemon}=$srv->daemonClass->new(%{$srv->{daemonArgs}}))) {
$srv->logconfess("could not create ", $srv->daemonClass, " daemon object: $!");
}
my $daemon = $srv->{daemon};
##-- register path handlers
my ($path,$ph);
while (($path,$ph)=each %{$srv->{paths}}) {
$ph = $srv->registerPathHandler($path,$ph)
or $srv->logconfess("registerPathHandler() failed for path '$path': $!");
$srv->vlog($srv->{logRegisterPath}, "registered path handler: '$path' => ".(ref($ph)||$ph));
}
##-- compile allow/deny regexes
foreach my $policy (qw(allow deny)) {
my $re = $srv->{$policy} && @{$srv->{$policy}} ? join('|', map {"(?:$_)"} @{$srv->{$policy}}) : '^$';
$srv->{"_".$policy} = qr/$re/;
}
##-- setup cache
$srv->{cache} = DTA::CAB::Cache::LRU->new(max_size=>$srv->{cacheSize}) if (!$srv->{cache} && $srv->{cacheSize}>0);
##-- setup mode-specific options
$srv->{daemonMode} //= 'serial';
$srv->{pid} //= $$;
if ($srv->{daemonMode} eq 'fork') {
$srv->{children} //= {};
$SIG{CHLD} = $srv->reaper();
}
return 1;
}
## $rc = $srv->run()
## + run the server
sub run {
my $srv = shift;
$srv->prepare() if (!$srv->{daemon}); ##-- sanity check
$srv->logcroak("run(): no underlying daemon object!") if (!$srv->{daemon});
my $daemon = $srv->{daemon};
my $mode = $srv->{daemonMode} || 'serial';
my $cclass = $srv->clientClass;
my $bgConnectTimeout = $srv->{bgConnectTimeout} || 0;
$srv->info("server starting in $mode mode on ", $srv->daemonLabel, "\n");
##-- setup SIGPIPE handler (avoid heinous death)
## + following suggestion on http://www.perlmonks.org/?node_id=580411
$SIG{PIPE} = sub { ++$srv->{nErrors}; $srv->vlog('warn',"got SIGPIPE (ignoring)"); };
##-- HACK: set HTTP::Daemon protocol to HTTP 1.0 (avoid keepalive)
$HTTP::Daemon::PROTO = "HTTP/1.0";
my ($csock,$chost,$hreq,$urikey,$forkable,$cacheable,$handler,$localPath,$pid,$rsp);
my ($fdset);
while (1) {
##-- track total processing time for *last* query
$srv->qtfinish();
##-- call accept() within the loop to avoid breaking out in fork mode
if (!defined($csock=$daemon->accept())) {
#sleep(1);
next;
}
##-- query processing starts
$srv->{qt0} = [gettimeofday];
##-- re-bless client socket (for UNIX-domain server)
bless($csock,$cclass) if ($cclass);
##-- got client $csock (HTTP::Daemon::ClientConn object; see HTTP::Daemon(3pm))
$chost = $csock->peerhost();
##-- avoid blocking on weird EOF sockets sent e.g. by chromium: no joy
if ($bgConnectTimeout > 0) {
vec(($fdset=""), $csock->fileno, 1) = 1;
if (!select($fdset,undef,undef,$bgConnectTimeout)) {
$srv->vlog($srv->{logAttempt}, "ignoring background connection from client $chost");
#++$srv->{nErrors};
next;
}
}
##-- access control
$srv->vlog($srv->{logAttempt}, "attempted connect from client $chost");
if (!$srv->clientAllowed($csock,$chost)) {
$srv->denyClient($csock);
next;
}
##-- track number of requests
++$srv->{nRequests};
##-- serve client: parse HTTP request
##
## Strangeness Fri, 17 May 2013 14:14:56 +0200
## + returning true from demo.js cabUpload() causes weird 'Client closed' errors on post-upload 'Back' clicks from chromium
## + problem maybe related to bizarre closed-client crashes for HTTP::Daemon::ClientConn observed elsewhere: persists even within eval BLOCK
## + symptom(s):
## - get_request() fails after ca. 10sec
## - HTTP::Daemon::DEBUG output shows "Need more data for complete header\nsysread()\n"
## - no data is actually read into $csock buffer (checked with debugger)
## - $csock invalidates with $csock->reason='Client closed', but $csock->opened()==1
## - attempting to write to $csock in this state (e.g. by clientError()) causes immediate termination of the running server!
##
##DEBUG
#$srv->vlog($srv->{logAttempt}, "get_request() for client $chost");
#$HTTP::Daemon::DEBUG=1;
${*$csock}{'io_socket_timeout'} = 5;
${*$csock}{'httpd_client_proto'} = HTTP::Daemon::ClientConn::_http_version("HTTP/1.0"); ##-- HACK: force status line on send_error() from $csock->get_request()
( run in 3.632 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )