#!perl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";
use Test::More tests => 6;
use TestApp;
use HTTP::Request::AsCGI;
=cut
This test exposes a problem in the handling of PATH_INFO in C::Engine::CGI (and
other engines) where Catalyst does not un-escape the request correctly.
If a request is URL-encoded then Catalyst fails to decode the request
and thus will try and match actions using the URL-encoded value.
Can NOT use Catalyst::Test as it uses HTTP::Request::AsCGI which does
correctly unescape the path (by calling $uri = $uri->canonical).
$ prove -vl t/live_engine_request_escaped_path.t
t/live_engine_request_escaped_path......
1..6
got path [args/params/one/two]
ok 1
ok 2 - Response Successful 2xx
ok 3
got path [args/param%73/one/two]
ok 4
not ok 5 - Response Successful 2xx
# Failed test 'Response Successful 2xx'
# at t/live_engine_request_escaped_path.t line 53.
not ok 6
# Failed test at t/live_engine_request_escaped_path.t line 54.
# got: 'FATAL ERROR: Unknown resource "args/param%73/one/two"'
# expected: 'onetwo'
# Looks like you failed 2 tests of 6.
#
As can be seen, Catalyst tried to match "args/param%73/one/two"
This will fix the problem for the CGI engine, but is probably the
wrong place. And also does not fix $uri->base, either.
Plus, the same issue is in Engine::Apache* and other engines.
Index: lib/Catalyst/Engine/CGI.pm
===================================================================
--- lib/Catalyst/Engine/CGI.pm (revision 7821)
+++ lib/Catalyst/Engine/CGI.pm (working copy)
@@ -157,6 +157,8 @@
my $query = $ENV{QUERY_STRING} ? '?' . $ENV{QUERY_STRING} : '';
my $uri = $scheme . '://' . $host . '/' . $path . $query;
+ $uri = URI->new( $uri )->canonical;
+
$c->request->uri( bless \$uri, $uri_class );
# set the base URI
=cut
# test that un-escaped can be feteched.
{
my $request = Catalyst::Utils::request( '
http://localhost/args/params/one/two' );
my $cgi = HTTP::Request::AsCGI->new( $request, %ENV )->setup;
TestApp->handle_request;
ok( my $response = $cgi->restore->response );
ok( $response->is_success, 'Response Successful 2xx' );
is( $response->content, 'onetwo' );
}
# test that request with URL-escaped code works.
{
my $request = Catalyst::Utils::request( '
http://localhost/args/para%73/one/two' );
my $cgi = HTTP::Request::AsCGI->new( $request, %ENV )->setup;
# Reset PATH_INFO because AsCGI calls $uri = $uri->canonical which
# will unencode the path and hide the problem from the test.
$ENV{PATH_INFO} = '/args/param%73/one/two';
TestApp->handle_request;
ok( my $response = $cgi->restore->response );
ok( $response->is_success, 'Response Successful 2xx' );
is( $response->content, 'onetwo' );
}