Browse files

fix URI construction when PATH_INFO contains URI reserved characters …

…such as ? or #. Fixes gh-118
  • Loading branch information...
1 parent 45c4479 commit a01c607cb6d0b6470308987cb94aa4b011c2d7ff @miyagawa miyagawa committed Jul 2, 2010
Showing with 40 additions and 1 deletion.
  1. +10 −1 lib/Plack/Request.pm
  2. +30 −0 t/Plack-Request/path_info_escaped.t
View
11 lib/Plack/Request.pm
@@ -208,7 +208,16 @@ sub uri {
my $base = $self->_uri_base;
- my $path = $self->env->{PATH_INFO} || '';
+ # We have to escape back PATH_INFO in case they include stuff like
+ # ? or # so that the URI parser won't be tricked. However we should
+ # preserve '/' since encoding them into %2f doesn't make sense.
+ # This means when a request like /foo%2fbar comes in, we recognize
+ # it as /foo/bar which is not ideal, but that's how the PSGI PATH_INFO
+ # spec goes and we can't do anything about it. See PSGI::FAQ for details.
+ # http://github.com/miyagawa/Plack/issues#issue/118
+ my $path_escape_class = '^A-Za-z0-9\-\._~/';
+
+ my $path = URI::Escape::uri_escape($self->env->{PATH_INFO} || '', $path_escape_class);
$path .= '?' . $self->env->{QUERY_STRING}
if defined $self->env->{QUERY_STRING} && $self->env->{QUERY_STRING} ne '';
View
30 t/Plack-Request/path_info_escaped.t
@@ -0,0 +1,30 @@
+use strict;
+use Test::More;
+use Plack::Test;
+use Plack::Request;
+use HTTP::Request::Common;
+use Data::Dumper;
+
+my $path_app = sub {
+ my $req = Plack::Request->new(shift);
+ my $res = $req->new_response(200);
+ $res->content_type('text/plain');
+ $res->content('my ' . Dumper([ $req->uri, $req->parameters ]));
+ return $res->finalize;
+};
+
+test_psgi $path_app, sub {
+ my $cb = shift;
+
+ my $res = $cb->(GET "http://localhost/foo.bar-baz?a=b");
+ is_deeply eval($res->content), [ URI->new("http://localhost/foo.bar-baz?a=b"), { a => 'b' } ];
+
+ $res = $cb->(GET "http://localhost/foo%2fbar#ab");
+ is_deeply eval($res->content), [ URI->new("http://localhost/foo/bar"), {} ],
+ "%2f vs / can't be distinguished - that's alright";
+
+ $res = $cb->(GET "http://localhost/%23foo?a=b");
+ is_deeply eval($res->content), [ URI->new("http://localhost/%23foo?a=b"), { a => 'b' } ];
+};
+
+done_testing;

0 comments on commit a01c607

Please sign in to comment.