DTA-CAB

 view release on metacpan or  search on metacpan

CAB/Server/HTTP.pm  view on Meta::CPAN

      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()
    ##/DEBUG
    $hreq = $csock->get_request();
    if (!$hreq) {
      $srv->clientError($csock, RC_BAD_REQUEST, "could not parse HTTP request: ", xml_escape($csock->reason || 'get_request() failed'));
      ++$srv->{nErrors};
      next;
    }

    ##-- log basic request, and possibly request data
    $urikey = $hreq->uri->as_string;
    $srv->vlog($srv->{logConnect}, "client $chost: ", $hreq->method, ' ', $urikey);
    $srv->vlog($srv->{logRequestData}, "client $chost: HTTP::Request={\n", $hreq->as_string, "}");

    ##-- check global content-length limit
    if (($srv->{maxRequestSize}//-1) >= 0 && ($hreq->content_length//0) > $srv->{maxRequestSize}) {
      $srv->clientError($csock, RC_REQUEST_ENTITY_TOO_LARGE, "request exceeds server limit (max=$srv->{maxRequestSize} bytes)");
      ++$srv->{nErrors};
      next;
    }

    ##-- map request to handler
    ($handler,$localPath) = $srv->getPathHandler($hreq->uri);
    if (!defined($handler)) {
      $srv->clientError($csock, RC_NOT_FOUND, "cannot resolve URI ", xml_escape($hreq->uri));
      ++$srv->{nErrors};
      next;
    }

    ##-- check whether we can fork for this request (by default only for POST)
    $forkable = ($mode eq 'fork'
		 && $srv->{"forkOn".ucfirst(lc($hreq->method))}
		 && (!$srv->{forkMax} || scalar(keys %{$srv->{children}}) < $srv->{forkMax}));

    ##-- check cache (GET requests only)
    $cacheable = ($srv->{cache}
		  && (!defined($handler->{cacheable}) || $handler->{cacheable})
		  && $hreq->method eq 'GET'
		  && ($hreq->header('Pragma')||'') !~ /\bno-cache\b/);
    if ($cacheable
	&& ($hreq->header('Cache-Control')||'') !~ /\bno-cache\b/
	&& defined($rsp = $srv->{cache}->get($urikey)))
      {
	++$srv->{nCacheHits};
	$srv->vlog($srv->{logCache}, "using cached response");
	$rsp->header('X-Cached' => 1);
	$srv->vlog($srv->{logResponse}, "cached response: ", $rsp->as_string) if ($srv->{logResponse});
	$csock->send_response($rsp);
	next;
      }

    ##-- maybe fork
    $pid = $forkable ? fork() : undef;
    if ($pid) {
      ##-- parent code
      $srv->{children}{$pid} = undef;
      $srv->vlog($srv->{logSpawn}, "spawned subprocess $pid");
      $srv->{qt0} = undef;
      next;
    }

    ##-- child|serial code: pass request to handler
    eval {
      $rsp = $handler->run($srv,$localPath,$csock,$hreq);
    };
    if ($@) {
      $srv->clientError($csock,RC_INTERNAL_SERVER_ERROR,"handler ", (ref($handler)||$handler), "::run() died:<br/><pre>", xml_escape($@), "</pre>");
      $srv->reapClient($csock,$handler,$chost);
      ++$srv->{nErrors};
    }
    elsif (!defined($rsp)) {
      $srv->clientError($csock,RC_INTERNAL_SERVER_ERROR,"handler ", (ref($handler)||$handler), "::run() failed");
      $srv->reapClient($csock,$handler,$chost);



( run in 0.967 second using v1.01-cache-2.11-cpan-98e64b0badf )