Subject: | CGI->url(-absolute => 1) doesn't work correctly if PATH_INFO contains escaped characters |
If PATH_INFO contains URI-escaped characters, e.g.
REQUEST_URI="http://server/wiki/back=Foo+Bar/Zippo"
PATH_INFO="/back=Foo+Bar/Zippo"
(with "+" being an escaped space character), then CGI->url(-absolute => 1) returns "/wiki/back=Foo+Bar/Zippo" instead of "/wiki". I have verified this at least with CGI.pm 2.81, 2.98, and 3.00.
Reading the code of CGI::url(), this seems obvious to me, since it tries to remove an *escaped* PATH_INFO from an *unescaped* REQUEST_URI, which is bound to fail as soon as PATH_INFO contains special characters.
I attached a patch which fixes the problem.
Besides, the original code (correctly) uses quotemeta() to quote regex meta-characters in PATH_INFO before using it in the s/// statement. The problem with this is that it probably makes developers (like it did for me) confuse quotemeta() with escape() or unescape(), so one might think the algorithm was indeed correct. I replaced the quotemeta() call with the use of \Q...\E in the s///, so the missing of the unescape() call kind of became obvious. :-)
--- CGI.pm 2003-12-18 17:01:53.000000000 +0100
+++ /usr/share/perl/5.8.2/CGI.pm 2003-12-18 17:03:01.000000000 +0100
@@ -2494,8 +2494,8 @@
$script_name =~ s/\?.+$//; # strip query string
# and path
if (exists($ENV{PATH_INFO})) {
- my $encoded_path = quotemeta($ENV{PATH_INFO});
- $script_name =~ s/$encoded_path$//i;
+ my $encoded_path = unescape($ENV{PATH_INFO});
+ $script_name =~ s/\Q$encoded_path\E$//i;
}
}