[Catalyst] Patch for Catalyst::Engine::Apache

Bill Moseley moseley at hank.org
Thu Jun 22 02:57:25 CEST 2006


This is to follow up on a patch I posted on April 28 that was
ever applied.  Andy asked if the SSL detection should be factored out
to work with other engines (CGI/FastCGI), which it should, but in the
mean time the patch got lost again.


I noticed ningu made a patch that attempts to do something similar.

    http://dev.catalyst.perl.org/changeset/4407

The problem is that in a front/back server setup mod_ssl will likely
not be running on the same server as Catalyst.

So, I want to provide a patch that includes ningu's and my original
patch.

My change was:

    1) test for a request header that might flag SSL.  This would
    allow setting a header in the front end server with mod_headers,
    for example.

    2) test for connecting port to =~ /443/ instead of == 443.  This
    give a way to detect SSL connections from the front end.  For
    example, I set my server up to listen to 3443 for SSL connections
    from the front-end.  The front end reverse proxies from 443 to
    3443 and then catalyst can detect it's an ssl connection.
    Need to know that so redirects can work correctly.

Changing the check from $ENV{HTTPS} to $self->apache->subprocess_env('HTTPS')
probably makes sense.  I can't remember if checking $ENV is required for
registry scripts, but I can't imagine anyone running Catalyst under
Registry.

I also check that $buffer is defined in write() to avoid:

   Use of uninitialized value in subroutine entry at .../Catalyst/Engine/Apache.pm


I think there's some duplication in the SSL detection between
prepare_connection and prepare_path.  I'll look again when I have
more time.

Patch attached...again.



-- 
Bill Moseley
moseley at hank.org

-------------- next part --------------
Index: lib/Catalyst/Engine/Apache.pm
===================================================================
--- lib/Catalyst/Engine/Apache.pm	(revision 4437)
+++ lib/Catalyst/Engine/Apache.pm	(working copy)
@@ -18,9 +18,9 @@
 
 sub prepare_connection {
     my ( $self, $c ) = @_;
-    
+
     $c->request->address( $self->apache->connection->remote_ip );
-    
+
     PROXY_CHECK:
     {
         my $headers = $self->apache->headers_in;
@@ -29,27 +29,29 @@
             last PROXY_CHECK if $c->config->{ignore_frontend_proxy};
         }
         last PROXY_CHECK unless $headers->{'X-Forwarded-For'};
-        
+
         # If we are running as a backend server, the user will always appear
         # as 127.0.0.1. Select the most recent upstream IP (last in the list)
         my ($ip) = $headers->{'X-Forwarded-For'} =~ /([^,\s]+)$/;
         $c->request->address( $ip );
     }
-    
+
     $c->request->hostname( $self->apache->connection->remote_host );
     $c->request->protocol( $self->apache->protocol );
     $c->request->user( $self->apache->user );
 
+
     if ($INC{'Apache2/ModSSL.pm'}) {
         $c->request->secure(1) if $self->apache->connection->is_https;
+
+    } elsif ( $self->apache->get_server_port =~ /443/ ) {
+        $c->request->secure(1);
+
+    } else {
+        my $https = $self->apache->subprocess_env('HTTPS'); 
+        $c->request->secure(1) if defined $https and uc $https eq 'ON';
     }
-    else {
-        my $https = $self->apache->subprocess_env('HTTPS');
-        $c->request->secure(1) if defined $https and uc $https eq 'ON';        
-#        if ( $self->apache->get_server_port == 443 ) {
-#            $c->request->secure(1);
-#        }
-    }
+
 }
 
 sub prepare_query_parameters {
@@ -72,11 +74,10 @@
 
 sub prepare_path {
     my ( $self, $c ) = @_;
-    
-    my $scheme = $c->request->secure ? 'https' : 'http';
+
     my $host   = $self->apache->hostname || 'localhost';
     my $port   = $self->apache->get_server_port;
-    
+
     # If we are running as a backend proxy, get the true hostname
     PROXY_CHECK:
     {
@@ -87,11 +88,22 @@
         last PROXY_CHECK unless $c->request->header( 'X-Forwarded-Host' );
 
         $host = $c->request->header( 'X-Forwarded-Host' );
-        # backend could be on any port, so
-        # assume frontend is on the default port
-        $port = $c->request->secure ? 443 : 80;
+
+        if ( $c->request->header('X-Is-SSL') ) {
+            $c->request->secure(1);
+
+        } elsif ( $host =~ /^(.+):(\d+)$/ ) {
+            $host = $1;
+            $port = $2;
+            $c->request->secure(1) if $port =~ /443/;
+        } else {
+            # backend could be on any port, so
+            # assume frontend is on the default port
+            $port = $c->request->secure ? 443 : 80;
+        }
     }
 
+
     my $base_path = q{};
 
     # Are we running in a non-root Location block?
@@ -99,15 +111,16 @@
     if ( $location && $location ne '/' ) {
         $base_path = $location;
     }
-    
+
     # Are we an Apache::Registry script? Why anyone would ever want to run
     # this way is beyond me, but we'll support it!
     if ( $self->apache->filename && -f $self->apache->filename && -x _ ) {
         $base_path .= $ENV{SCRIPT_NAME};
     }
-    
+
+
     my $uri = URI->new;
-    $uri->scheme($scheme);
+    $uri->scheme( $c->request->secure ? 'https' : 'http' );
     $uri->host($host);
     $uri->port($port);
     $uri->path( $self->apache->uri );
@@ -183,8 +196,8 @@
 
 sub write {
     my ( $self, $c, $buffer ) = @_;
-    
-    if ( ! $self->apache->connection->aborted ) {
+
+    if ( ! $self->apache->connection->aborted && defined $buffer) {
         return $self->apache->print( $buffer );
     }
     return;
Index: Changes
===================================================================
--- Changes	(revision 4437)
+++ Changes	(working copy)
@@ -1,5 +1,18 @@
 This file documents the revision history for Catalyst::Engine::Apache.
 
+1.08
+        - Changed to extract port from X-Forwarded-Host.  And if extracted
+        port =~ /443/ then is considered a secure connection.  That allows
+        for using, say, 8443 in a front-end.  This is only helpful for testing
+        since a SSL connection on the standard port will not normally include
+        the port number in the X-Forwarded-Host header.
+
+        - Changed test for connecting port == 443 to port =~ /443/.
+        This allows setting up the Catalyst server to listen to two ports
+        (e.g. 3080 and 3444) for the front end server to connect to.
+        Catalyst can determine if it's a SSL connection by which port the
+        front end server connected to.
+
 1.07    2006-02-17 17:00:00
         - Fixed bug: Can't locate object method "FIRSTKEY" via package
           "APR::Table" when running under mod_perl 2.0.2.


More information about the Catalyst mailing list