X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FEngine%2FCGI.pm;h=c57c8a5ba25bfb230b57577cbc49bac2d9a9a8f9;hb=ca78941c9da0a5d9ff5a400f5a8e5ef7f9308cd8;hp=ef8aa2a59e355342110452f0a8fea5b48a6bd697;hpb=64d1c3cd4b64ae7018ec3b555cc1a97b589a83ca;p=catagits%2FCatalyst-Runtime.git diff --git a/lib/Catalyst/Engine/CGI.pm b/lib/Catalyst/Engine/CGI.pm index ef8aa2a..c57c8a5 100644 --- a/lib/Catalyst/Engine/CGI.pm +++ b/lib/Catalyst/Engine/CGI.pm @@ -57,9 +57,9 @@ sub prepare_connection { PROXY_CHECK: { - unless ( $c->config->{using_frontend_proxy} ) { + unless ( ref($c)->config->{using_frontend_proxy} ) { last PROXY_CHECK if $ENV{REMOTE_ADDR} ne '127.0.0.1'; - last PROXY_CHECK if $c->config->{ignore_frontend_proxy}; + last PROXY_CHECK if ref($c)->config->{ignore_frontend_proxy}; } last PROXY_CHECK unless $ENV{HTTP_X_FORWARDED_FOR}; @@ -85,6 +85,7 @@ sub prepare_connection { if ( $ENV{SERVER_PORT} == 443 ) { $request->secure(1); } + binmode(STDOUT); # Ensure we are sending bytes. } =head2 $self->prepare_headers($c) @@ -107,6 +108,8 @@ sub prepare_headers { =cut +# Please don't touch this method without adding tests in +# t/aggregate/unit_core_engine_cgi-prepare_path.t sub prepare_path { my ( $self, $c ) = @_; local (*ENV) = $self->env || \%ENV; @@ -114,21 +117,24 @@ sub prepare_path { my $scheme = $c->request->secure ? 'https' : 'http'; my $host = $ENV{HTTP_HOST} || $ENV{SERVER_NAME}; my $port = $ENV{SERVER_PORT} || 80; + my $script_name = $ENV{SCRIPT_NAME}; + $script_name =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go if $script_name; + my $base_path; if ( exists $ENV{REDIRECT_URL} ) { $base_path = $ENV{REDIRECT_URL}; $base_path =~ s/$ENV{PATH_INFO}$//; } else { - $base_path = $ENV{SCRIPT_NAME} || '/'; + $base_path = $script_name || '/'; } # If we are running as a backend proxy, get the true hostname PROXY_CHECK: { - unless ( $c->config->{using_frontend_proxy} ) { + unless ( ref($c)->config->{using_frontend_proxy} ) { last PROXY_CHECK if $host !~ /localhost|127.0.0.1/; - last PROXY_CHECK if $c->config->{ignore_frontend_proxy}; + last PROXY_CHECK if ref($c)->config->{ignore_frontend_proxy}; } last PROXY_CHECK unless $ENV{HTTP_X_FORWARDED_HOST}; @@ -142,8 +148,34 @@ sub prepare_path { } } + # RFC 3875: "Unlike a URI path, the PATH_INFO is not URL-encoded, + # and cannot contain path-segment parameters." This means PATH_INFO + # is always decoded, and the script can't distinguish / vs %2F. + # See https://issues.apache.org/bugzilla/show_bug.cgi?id=35256 + # Here we try to resurrect the original encoded URI from REQUEST_URI. + my $path_info = $ENV{PATH_INFO}; + if (my $req_uri = $ENV{REQUEST_URI}) { + $req_uri =~ s/^\Q$base_path\E//; + $req_uri =~ s/\?.*$//; + if ($req_uri) { + # Note that if REQUEST_URI doesn't start with a /, then the user + # is probably using mod_rewrite or something to rewrite requests + # into a sub-path of their application.. + # This means that REQUEST_URI needs information from PATH_INFO + # prepending to it to be useful, otherwise the sub path which is + # being redirected to becomes the app base address which is + # incorrect. + if (substr($req_uri, 0, 1) ne '/') { + my ($match) = $req_uri =~ m|^([^/]+)|; + my ($path_info_part) = $path_info =~ m|^(.*?\Q$match\E)|; + substr($req_uri, 0, length($match), $path_info_part); + } + $path_info = $req_uri; + } + } + # set the request URI - my $path = $base_path . ( $ENV{PATH_INFO} || '' ); + my $path = $base_path . ( $path_info || '' ); $path =~ s{^/+}{}; # Using URI directly is way too slow, so we construct the URLs manually @@ -163,7 +195,7 @@ sub prepare_path { my $query = $ENV{QUERY_STRING} ? '?' . $ENV{QUERY_STRING} : ''; my $uri = $scheme . '://' . $host . '/' . $path . $query; - $c->request->uri( bless \$uri, $uri_class ); + $c->request->uri( bless(\$uri, $uri_class)->canonical ); # set the base URI # base must end in a slash @@ -171,7 +203,7 @@ sub prepare_path { my $base_uri = $scheme . '://' . $host . $base_path; - $c->request->base( bless \$base_uri, $uri_class ); + $c->request->base( bless(\$base_uri, $uri_class)->canonical ); } =head2 $self->prepare_query_parameters($c)