Fix Apache, added C::E::Apache::MP1 and C::E::Apache::MP2, added $c->finialize_cookies
Christian Hansen [Sat, 2 Apr 2005 04:44:17 +0000 (04:44 +0000)]
lib/Catalyst.pm
lib/Catalyst/Engine.pm
lib/Catalyst/Engine/Apache.pm
lib/Catalyst/Engine/CGI.pm
lib/Catalyst/Engine/HTTP.pm
lib/Catalyst/Engine/Test.pm

index 90d158a..e7cf1d5 100644 (file)
@@ -144,11 +144,19 @@ sub import {
         $caller->log->debug('Debug messages enabled');
     }
 
-    # Options
-    my $engine =
-      $ENV{MOD_PERL}
-      ? 'Catalyst::Engine::Apache'
-      : 'Catalyst::Engine::CGI';
+    my $engine ='Catalyst::Engine::CGI';
+
+    if ( $ENV{MOD_PERL} ) {
+
+        require mod_perl;
+
+        if ( $mod_perl::VERSION >= 1.99 ) {
+            $engine ='Catalyst::Engine::Apache::MP2';
+        }
+        else {
+            $engine ='Catalyst::Engine::Apache::MP1';
+        }
+    }
 
     my @plugins;
     foreach (@options) {
index 012038c..4b7fad7 100644 (file)
@@ -3,6 +3,7 @@ package Catalyst::Engine;
 use strict;
 use base qw/Class::Data::Inheritable Class::Accessor::Fast/;
 use UNIVERSAL::require;
+use CGI::Cookie;
 use Data::Dumper;
 use HTML::Entities;
 use HTTP::Headers;
@@ -115,6 +116,40 @@ sub error {
     return $c->{error};
 }
 
+=item $c->execute($class, $coderef)
+
+Execute a coderef in given class and catch exceptions.
+Errors are available via $c->error.
+
+=cut
+
+sub execute {
+    my ( $c, $class, $code ) = @_;
+    $class = $c->comp($class) || $class;
+    $c->state(0);
+    eval {
+        if ( $c->debug )
+        {
+            my $action = $c->actions->{reverse}->{"$code"};
+            $action = "/$action" unless $action =~ /\-\>/;
+            my ( $elapsed, @state ) =
+              $c->benchmark( $code, $class, $c, @{ $c->req->args } );
+            push @{ $c->{stats} },
+              _prettify( $action, sprintf( '%fs', $elapsed ), '' );
+            $c->state(@state);
+        }
+        else { $c->state( &$code( $class, $c, @{ $c->req->args } ) ) }
+    };
+    if ( my $error = $@ ) {
+        chomp $error;
+        $error = qq/Caught exception "$error"/;
+        $c->log->error($error);
+        $c->error($error) if $c->debug;
+        $c->state(0);
+    }
+    return $c->state;
+}
+
 =item $c->finalize
 
 Finalize request.
@@ -124,11 +159,16 @@ Finalize request.
 sub finalize {
     my $c = shift;
 
+    $c->finalize_cookies;
+
     if ( my $location = $c->res->redirect ) {
         $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
-        $c->res->headers->header( Location => $location );
-        $c->res->headers->remove_content_headers;
-        $c->res->status(302);
+        $c->response->header( Location => $location );
+        $c->response->status(302);
+    }
+
+    if ( $c->res->status =~ /^(1\d\d|[23]04)$/ ) {
+        $c->response->headers->remove_content_headers;
         return $c->finalize_headers;
     }
 
@@ -231,6 +271,29 @@ sub finalize {
     return $status;
 }
 
+=item $c->finalize_cookies
+
+Finalize cookies.
+
+=cut
+
+sub finalize_cookies {
+    my $c = shift;
+
+    while ( my ( $name, $cookie ) = each %{ $c->response->cookies } ) {
+        my $cookie = CGI::Cookie->new(
+            -name    => $name,
+            -value   => $cookie->{value},
+            -expires => $cookie->{expires},
+            -domain  => $cookie->{domain},
+            -path    => $cookie->{path},
+            -secure  => $cookie->{secure} || 0
+        );
+
+        $c->res->headers->push_header( 'Set-Cookie' => $cookie->as_string );
+    }
+}
+
 =item $c->finalize_headers
 
 Finalize headers.
@@ -351,15 +414,15 @@ Handles the request.
 
 =cut
 
-sub handler ($$) {
-    my ( $class, $r ) = @_;
+sub handler {
+    my ( $class, $engine ) = @_;
 
     # Always expect worst case!
     my $status = -1;
     eval {
         my @stats = ();
         my $handler = sub {
-            my $c = $class->prepare($r);
+            my $c = $class->prepare($engine);
             $c->{stats} = \@stats;
             my $action    = $c->req->action;
             my $namespace = '';
@@ -532,7 +595,13 @@ Prepare cookies.
 
 =cut
 
-sub prepare_cookies { }
+sub prepare_cookies {
+    my $c = shift;
+
+    if ( my $header = $c->request->header('Cookie') ) {
+        $c->req->cookies( { CGI::Cookie->parse($header) } );
+    }
+}
 
 =item $c->prepare_headers
 
@@ -574,40 +643,6 @@ Prepare uploads.
 
 sub prepare_uploads { }
 
-=item $c->execute($class, $coderef)
-
-Execute a coderef in given class and catch exceptions.
-Errors are available via $c->error.
-
-=cut
-
-sub execute {
-    my ( $c, $class, $code ) = @_;
-    $class = $c->comp($class) || $class;
-    $c->state(0);
-    eval {
-        if ( $c->debug )
-        {
-            my $action = $c->actions->{reverse}->{"$code"};
-            $action = "/$action" unless $action =~ /\-\>/;
-            my ( $elapsed, @state ) =
-              $c->benchmark( $code, $class, $c, @{ $c->req->args } );
-            push @{ $c->{stats} },
-              _prettify( $action, sprintf( '%fs', $elapsed ), '' );
-            $c->state(@state);
-        }
-        else { $c->state( &$code( $class, $c, @{ $c->req->args } ) ) }
-    };
-    if ( my $error = $@ ) {
-        chomp $error;
-        $error = qq/Caught exception "$error"/;
-        $c->log->error($error);
-        $c->error($error) if $c->debug;
-        $c->state(0);
-    }
-    return $c->state;
-}
-
 =item $c->run
 
 Starts the engine.
index f6c0b5f..f715456 100644 (file)
@@ -6,25 +6,7 @@ use constant MP2 => $mod_perl::VERSION >= 1.99;
 use base 'Catalyst::Engine';
 use URI;
 
-# mod_perl
-if (MP2) {
-    require Apache2;
-    require Apache::Connection;
-    require Apache::RequestIO;
-    require Apache::RequestRec;
-    require Apache::SubRequest;
-    require Apache::RequestUtil;
-    require APR::URI;
-    require Apache::URI;
-}
-else { require Apache }
-
-# libapreq
-require Apache::Request;
-require Apache::Cookie;
-require Apache::Upload if MP2;
-
-__PACKAGE__->mk_accessors(qw/apache_request original_request/);
+__PACKAGE__->mk_accessors(qw/apache/);
 
 =head1 NAME
 
@@ -42,14 +24,10 @@ This is the Catalyst engine specialized for Apache (i.e. for mod_perl).
 
 =over 4
 
-=item $c->apache_request
+=item $c->apache
 
 Returns an C<Apache::Request> object.
 
-=item $c->original_request
-
-Returns the original Apache request object.
-
 =back
 
 =head1 OVERLOADED METHODS
@@ -64,27 +42,25 @@ This class overloads some methods from C<Catalyst::Engine>.
 
 sub finalize_headers {
     my $c = shift;
+
     for my $name ( $c->response->headers->header_field_names ) {
         next if $name =~ /Content-Type/i;
-        $c->original_request->headers_out->set(
-            $name => $c->response->headers->header($name) );
+        my @values = $c->response->header($name);
+        $c->apache->headers_out->add( $name => $_ ) for @values;
     }
-    while ( my ( $name, $cookie ) = each %{ $c->response->cookies } ) {
-        my %crunchy = ( -name => $name, -value => $cookie->{value} );
-        $crunchy{-expires} = $cookie->{expires} if $cookie->{expires};
-        $crunchy{-domain}  = $cookie->{domain}  if $cookie->{domain};
-        $crunchy{-path}    = $cookie->{path}    if $cookie->{path};
-        $crunchy{-secure}  = $cookie->{secure}  if $cookie->{secure};
-        my $cookie = Apache::Cookie->new( $c->original_request, %crunchy );
-        MP2
-          ? $c->apache_request->err_headers_out->add(
-            'Set-Cookie' => $cookie->as_string )
-          : $cookie->bake;
+
+    if ( $c->response->header('Set-Cookie') && $c->response->status >= 300 ) {
+        my @values = $c->response->header('Set-Cookie');
+        $c->apache->err_headers_out->add( 'Set-Cookie' => $_ ) for @values;
     }
-    $c->original_request->status( $c->response->status );
-    $c->original_request->content_type( $c->response->headers->content_type
-          || 'text/plain' );
-    MP2 || $c->apache_request->send_http_header;
+
+    $c->apache->status( $c->response->status );
+    $c->apache->content_type( $c->response->header('Content-Type') );
+
+    unless ( MP2 ) {
+        $c->apache->send_http_header;
+    }
+
     return 0;
 }
 
@@ -94,7 +70,7 @@ sub finalize_headers {
 
 sub finalize_output {
     my $c = shift;
-    $c->original_request->print( $c->response->{output} );
+    $c->apache->print( $c->response->{output} );
 }
 
 =item $c->prepare_connection
@@ -103,20 +79,8 @@ sub finalize_output {
 
 sub prepare_connection {
     my $c = shift;
-    $c->req->hostname( $c->apache_request->connection->remote_host );
-    $c->req->address( $c->apache_request->connection->remote_ip );
-}
-
-=item $c->prepare_cookies
-
-=cut
-
-sub prepare_cookies {
-    my $c = shift;
-    MP2
-      ? $c->req->cookies( { Apache::Cookie->fetch } )
-      : $c->req->cookies(
-        { Apache::Cookie->new( $c->apache_request )->fetch } );
+    $c->request->hostname( $c->apache->connection->remote_host );
+    $c->request->address( $c->apache->connection->remote_ip );
 }
 
 =item $c->prepare_headers
@@ -125,8 +89,8 @@ sub prepare_cookies {
 
 sub prepare_headers {
     my $c = shift;
-    $c->req->method( $c->apache_request->method );
-    $c->req->headers->header( %{ $c->apache_request->headers_in } );
+    $c->request->method( $c->apache->method );
+    $c->request->header( %{ $c->apache->headers_in } );
 }
 
 =item $c->prepare_parameters
@@ -136,30 +100,32 @@ sub prepare_headers {
 sub prepare_parameters {
     my $c = shift;
     my %args;
-    foreach my $key ( $c->apache_request->param ) {
-        my @values = $c->apache_request->param($key);
+    foreach my $key ( $c->apache->param ) {
+        my @values = $c->apache->param($key);
         $args{$key} = @values == 1 ? $values[0] : \@values;
     }
-    $c->req->parameters( \%args );
+    $c->request->parameters( \%args );
 }
 
 =item $c->prepare_path
 
 =cut
 
+# XXX needs fixing, only work with <Location> directive, 
+# not <Directory> directive
 sub prepare_path {
     my $c = shift;
-    $c->req->path( $c->apache_request->uri );
-    my $loc = $c->apache_request->location;
+    $c->request->path( $c->apache->uri );
+    my $loc = $c->apache->location;
     no warnings 'uninitialized';
     $c->req->{path} =~ s/^($loc)?\///;
     my $base = URI->new;
     $base->scheme( $ENV{HTTPS} ? 'https' : 'http' );
-    $base->host( $c->apache_request->hostname );
-    $base->port( $c->apache_request->get_server_port );
-    my $path = $c->apache_request->location;
+    $base->host( $c->apache->hostname );
+    $base->port( $c->apache->get_server_port );
+    my $path = $c->apache->location;
     $base->path( $path =~ /\/$/ ? $path : "$path/" );
-    $c->req->base( $base->as_string );
+    $c->request->base( $base->as_string );
 }
 
 =item $c->prepare_request($r)
@@ -168,8 +134,7 @@ sub prepare_path {
 
 sub prepare_request {
     my ( $c, $r ) = @_;
-    $c->apache_request( Apache::Request->new($r) );
-    $c->original_request($r);
+    $c->apache( Apache::Request->new($r) );
 }
 
 =item $c->prepare_uploads
@@ -178,9 +143,9 @@ sub prepare_request {
 
 sub prepare_uploads {
     my $c = shift;
-    for my $upload ( $c->apache_request->upload ) {
-        $upload = $c->apache_request->upload($upload) if MP2;
-        $c->req->uploads->{ $upload->filename } = {
+    for my $upload ( $c->apache->upload ) {
+        $upload = $c->apache->upload($upload) if MP2;
+        $c->request->uploads->{ $upload->filename } = {
             fh   => $upload->fh,
             size => $upload->size,
             type => $upload->type
index ef29357..29b8421 100644 (file)
@@ -5,7 +5,6 @@ use base 'Catalyst::Engine';
 use URI;
 
 require CGI::Simple;
-require CGI::Cookie;
 
 $CGI::Simple::POST_MAX        = 1048576;
 $CGI::Simple::DISABLE_UPLOADS = 0;
@@ -41,11 +40,6 @@ application module:
 
     use Catalyst qw(-Engine=CGI);
 
-Catalyst::Engine::CGI generates a full set of HTTP headers, which means that
-applications using the engine must be be configured as "Non-parsed Headers"
-scripts (at least when running under Apache).  To configure this under Apache
-name the starting with C<nph->.
-
 The performance of this way of using Catalyst is not expected to be
 useful in production applications, but it may be helpful for development.
 
@@ -72,22 +66,13 @@ This class overloads some methods from C<Catalyst::Engine>.
 sub finalize_headers {
     my $c = shift;
     my %headers;
+
     $headers{-status} = $c->response->status if $c->response->status;
+
     for my $name ( $c->response->headers->header_field_names ) {
-        $headers{"-$name"} = $c->response->headers->header($name);
+        $headers{"-$name"} = $c->response->header($name);
     }
-    my @cookies;
-    while ( my ( $name, $cookie ) = each %{ $c->response->cookies } ) {
-        push @cookies, $c->cgi->cookie(
-            -name    => $name,
-            -value   => $cookie->{value},
-            -expires => $cookie->{expires},
-            -domain  => $cookie->{domain},
-            -path    => $cookie->{path},
-            -secure  => $cookie->{secure} || 0
-        );
-    }
-    $headers{-cookie} = \@cookies if @cookies;
+
     print $c->cgi->header(%headers);
 }
 
@@ -112,14 +97,6 @@ sub prepare_connection {
     $c->req->address( $c->cgi->remote_addr );
 }
 
-=item $c->prepare_cookies
-
-Sets up cookies.
-
-=cut
-
-sub prepare_cookies { shift->req->cookies( { CGI::Cookie->fetch } ) }
-
 =item $c->prepare_headers
 
 =cut
@@ -176,6 +153,7 @@ sub prepare_path {
     }
 
     my $path = $ENV{PATH_INFO} || '/';
+    $path =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
     $path =~  s/^\///;
 
     $c->req->base($base);
index 17187d8..0d73456 100644 (file)
@@ -68,15 +68,15 @@ sub run {
             $request->uri->host( $request->header('Host') || $base->host );
             $request->uri->port( $base->port );
 
-            my $lwp = Catalyst::Engine::Test::LWP->new(
+            my $http = Catalyst::Engine::Test::HTTP->new(
                 address  => $connection->peerhost,
                 hostname => gethostbyaddr( $connection->peeraddr, AF_INET ),
                 request  => $request,
                 response => HTTP::Response->new
             );
 
-            $class->handler($lwp);
-            $connection->send_response( $lwp->response );
+            $class->handler($http);
+            $connection->send_response( $http->response );
 
         }
 
index 2436b7b..fb6f26e 100644 (file)
@@ -3,7 +3,6 @@ package Catalyst::Engine::Test;
 use strict;
 use base 'Catalyst::Engine';
 
-use CGI::Cookie;
 use Class::Struct ();
 use HTTP::Headers::Util 'split_header_words';
 use HTTP::Request;
@@ -11,9 +10,9 @@ use HTTP::Response;
 use IO::File;
 use URI;
 
-__PACKAGE__->mk_accessors(qw/lwp/);
+__PACKAGE__->mk_accessors(qw/http/);
 
-Class::Struct::struct 'Catalyst::Engine::Test::LWP' => {
+Class::Struct::struct 'Catalyst::Engine::Test::HTTP' => {
     request  => 'HTTP::Request',
     response => 'HTTP::Response',
     hostname => '$',
@@ -57,23 +56,10 @@ This class overloads some methods from C<Catalyst::Engine>.
 sub finalize_headers {
     my $c = shift;
 
-    $c->lwp->response->code( $c->response->status || 200 );
+    $c->http->response->code( $c->response->status );
 
     for my $name ( $c->response->headers->header_field_names ) {
-        $c->lwp->response->push_header( $name => [ $c->response->header($name) ] );
-    }
-
-    while ( my ( $name, $cookie ) = each %{ $c->response->cookies } ) {
-        my $cookie = CGI::Cookie->new(
-            -name    => $name,
-            -value   => $cookie->{value},
-            -expires => $cookie->{expires},
-            -domain  => $cookie->{domain},
-            -path    => $cookie->{path},
-            -secure  => $cookie->{secure} || 0
-        );
-
-        $c->lwp->response->headers->push_header( 'Set-Cookie' => $cookie->as_string );
+        $c->http->response->push_header( $name => [ $c->response->header($name) ] );
     }
 }
 
@@ -83,7 +69,7 @@ sub finalize_headers {
 
 sub finalize_output {
     my $c = shift;
-    $c->lwp->response->content_ref( \$c->response->{output} );
+    $c->http->response->content_ref( \$c->response->{output} );
 }
 
 =item $c->prepare_connection
@@ -92,20 +78,8 @@ sub finalize_output {
 
 sub prepare_connection {
     my $c = shift;
-    $c->req->hostname( $c->lwp->hostname );
-    $c->req->address( $c->lwp->address );
-}
-
-=item $c->prepare_cookies
-
-=cut
-
-sub prepare_cookies {
-    my $c = shift;
-
-    if ( my $header = $c->request->header('Cookie') ) {
-        $c->req->cookies( { CGI::Cookie->parse($header) } );
-    }
+    $c->req->hostname( $c->http->hostname );
+    $c->req->address( $c->http->address );
 }
 
 =item $c->prepare_headers
@@ -114,8 +88,8 @@ sub prepare_cookies {
 
 sub prepare_headers {
     my $c = shift;
-    $c->req->method( $c->lwp->request->method );
-    $c->req->headers( $c->lwp->request->headers );
+    $c->req->method( $c->http->request->method );
+    $c->req->headers( $c->http->request->headers );
 }
 
 =item $c->prepare_parameters
@@ -126,7 +100,7 @@ sub prepare_parameters {
     my $c = shift;
 
     my @params  = ();
-    my $request = $c->lwp->request;
+    my $request = $c->http->request;
 
     push( @params, $request->uri->query_form );
 
@@ -188,9 +162,9 @@ sub prepare_path {
 
     my $base;
     {
-        my $scheme = $c->lwp->request->uri->scheme;
-        my $host   = $c->lwp->request->uri->host;
-        my $port   = $c->lwp->request->uri->port;
+        my $scheme = $c->http->request->uri->scheme;
+        my $host   = $c->http->request->uri->host;
+        my $port   = $c->http->request->uri->port;
 
         $base = URI->new;
         $base->scheme($scheme);
@@ -200,7 +174,7 @@ sub prepare_path {
         $base = $base->canonical->as_string;
     }
 
-    my $path = $c->lwp->request->uri->path || '/';
+    my $path = $c->http->request->uri->path || '/';
     $path =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
     $path =~ s/^\///;
 
@@ -213,8 +187,8 @@ sub prepare_path {
 =cut
 
 sub prepare_request {
-    my ( $c, $lwp ) = @_;
-    $c->lwp($lwp);
+    my ( $c, $http ) = @_;
+    $c->http($http);
 }
 
 =item $c->prepare_uploads
@@ -249,18 +223,18 @@ sub run {
     my $host = sprintf( '%s:%d', $request->uri->host, $request->uri->port );
     $request->header( 'Host' => $host );
 
-    my $lwp = Catalyst::Engine::Test::LWP->new(
+    my $http = Catalyst::Engine::Test::HTTP->new(
         address  => '127.0.0.1',
         hostname => 'localhost',
         request  => $request,
         response => HTTP::Response->new
     );
 
-    $lwp->response->date(time);
+    $http->response->date(time);
 
-    $class->handler($lwp);
+    $class->handler($http);
 
-    return $lwp->response;
+    return $http->response;
 }
 
 =back