Search code examples
perlcgiurl-encoding

Why does using CGI::escape for my link URL make my browser take me to the wrong place?


I am using the CGI escape method to escape the url for the href link tag. Without the escape() call the link works fine in my browser because it is smart enough to translate the spaces as part of the URL.

My cgi script has this

print $outhtml->a({href=>$outhtml->escape($wavURL)}, $outhtml->escapeHTML($exportFilename));          

where $outhtml is a CGI object and wav URL is http://localhost/downloads/My File.mp3

With the escape, the output is:

<a href="http%3A%2F%2Flocalhost%2Fdownloads%2FMy%20File.mp3">My File</a>

This looks okay to me, but chrome treats this as a relative link, so when I click on it or copy the link address, it appends localhost/cgi-bin, giving a malformed address like so:

http://localhost/cgi-bin/http%3A%2F%2Flocalhost%2Fdownloads%2FMy%20File.mp3

I've tried this without the leading 'http://' in the raw URL as well, and it produces the same bad behavior. I also tried using an absolute URL without the hostname, like /downloads/My File.mp3, but this also has the same behavior. I've tested this on chrome and firefox and both have the same result.

I also tried URI::Escape, but it did the same thing.

What am I doing wrong?


Solution

  • You should escape only values of CGI parameters but not the whole URL. For instance:

    http://localhost/cgi-bin/get_file_by_url.pl?where=http%3A%2F%2Flocalhost%2Fdownloads%2FMy%20File.mp3
    

    The value of where has to be escaped. The URI module helps you.

    use URI;
    my $myurl = URI->new('http://localhost/downloads/My File.mp3');
    print $myurl->as_string, "\n";
    # http://localhost/downloads/My%20File.mp3