Fixed issue where development server running in fork mode did not properly exit after...
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Engine / HTTP.pm
index e1682af..f4fef51 100644 (file)
@@ -5,6 +5,7 @@ use base 'Catalyst::Engine::CGI';
 use Data::Dump qw(dump);
 use Errno 'EWOULDBLOCK';
 use HTTP::Date ();
+use HTTP::Headers;
 use HTTP::Status;
 use NEXT;
 use Socket;
@@ -15,9 +16,8 @@ use IO::Select       ();
 require Catalyst::Engine::HTTP::Restarter;
 require Catalyst::Engine::HTTP::Restarter::Watcher;
 
-sub CHUNKSIZE () { 64 * 1024 }
-
-sub DEBUG () { $ENV{CATALYST_HTTP_DEBUG} || 0 }
+use constant CHUNKSIZE => 64 * 1024;
+use constant DEBUG     => $ENV{CATALYST_HTTP_DEBUG} || 0;
 
 =head1 NAME
 
@@ -53,17 +53,30 @@ sub finalize_headers {
     my $status   = $c->response->status;
     my $message  = status_message($status);
     
-    print "$protocol $status $message\015\012";
+    my @headers;
+    push @headers, "$protocol $status $message";
     
     $c->response->headers->header( Date => HTTP::Date::time2str(time) );
-    $c->response->headers->header(
-        Connection => $self->_keep_alive ? 'keep-alive' : 'close' );
-        
     $c->response->headers->header( Status => $status );
-        
-    # Avoid 'print() on closed filehandle Remote' warnings when using IE
-    print $c->response->headers->as_string("\015\012") if *STDOUT->opened();
-    print "\015\012" if *STDOUT->opened();
+    
+    # Should we keep the connection open?
+    my $connection = $c->request->header('Connection');
+    if (   $self->{options}->{keepalive} 
+        && $connection 
+        && $connection =~ /^keep-alive$/i
+    ) {
+        $c->response->headers->header( Connection => 'keep-alive' );
+        $self->{_keepalive} = 1;
+    }
+    else {
+        $c->response->headers->header( Connection => 'close' );
+    }
+    
+    push @headers, $c->response->headers->as_string("\x0D\x0A");
+    
+    # Buffer the headers so they are sent with the first write() call
+    # This reduces the number of TCP packets we are sending
+    $self->{_header_buf} = join("\x0D\x0A", @headers, '');
 }
 
 =head2 $self->finalize_read($c)
@@ -231,6 +244,12 @@ sub run {
     # Ignore broken pipes as an HTTP server should
     local $SIG{PIPE} = 'IGNORE';
     
+    # Restart on HUP
+    local $SIG{HUP} = sub { 
+        $restart = 1;
+        warn "Restarting server on SIGHUP...\n";
+    };
+    
     LISTEN:
     while ( !$restart ) {
         while ( accept( Remote, $daemon ) ) {        
@@ -257,17 +276,30 @@ sub run {
             unless ( uc($method) eq 'RESTART' ) {
 
                 # Fork
-                if ( $options->{fork} ) { next if $pid = fork }
+                if ( $options->{fork} ) { 
+                    if ( $pid = fork ) {
+                        DEBUG && warn "Forked child $pid\n";
+                        next;
+                    }
+                }
 
                 $self->_handler( $class, $port, $method, $uri, $protocol );
             
                 if ( my $error = delete $self->{_write_error} ) {
                     DEBUG && warn "Write error: $error\n";
                     close Remote;
-                    next LISTEN;
+                    
+                    if ( !defined $pid ) {
+                        next LISTEN;
+                    }
                 }
 
-                $daemon->close if defined $pid;
+                if ( defined $pid ) {
+                    # Child process, close connection and exit
+                    DEBUG && warn "Child process exiting\n";
+                    $daemon->close;
+                    exit;
+                }
             }
             else {
                 my $sockdata = $self->_socket_data( \*Remote );
@@ -283,8 +315,6 @@ sub run {
                     last;
                 }
             }
-
-            exit if defined $pid;
         }
         continue {
             close Remote;
@@ -329,7 +359,7 @@ sub _handler {
     REQUEST:
     while (1) {
         my ( $path, $query_string ) = split /\?/, $uri, 2;
-
+        
         # Initialize CGI environment
         local %ENV = (
             PATH_INFO       => $path         || '',