{"thread":{"id":"5668","subject":"[PATCH] gitweb: Consolidate escaping/validation of query string","startedAt":"2006-09-23T22:18:41Z","lastAt":"2006-09-24T12:31:08Z","messageCount":7,"participants":["Petr Baudis","Jakub Narebski"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"27518","messageId":"20060923221841.18063.56589.stgit@rover","threadId":"5668","inReplyTo":null,"subject":"[PATCH] gitweb: Consolidate escaping/validation of query string","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-09-23T22:18:41Z","receivedAt":"2006-09-23T22:18:41Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Consider:\n\n\thttp://repo.or.cz/?p=glibc-cvs.git;a=tree;h=2609cb0411389325f4ee2854cc7159756eb0671e;hb=2609cb0411389325f4ee2854cc7159756eb0671e\n\n(click on the funny =__ify file)\n\nWe ought to handle anything in filenames and I actually see no reason why\nwe don't, modulo very little missing escaping that this patch hopefully\nalso fixes.\n\nI have also made esc_param() escape [?=&;]. Not escaping [&;] was downright\nbuggy and [?=] just feels better escaped. ;-) YMMV.\n\nSigned-off-by: Petr Baudis <pasky@suse.cz>\n---\n\n gitweb/gitweb.perl |   32 +++++++++++---------------------\n 1 files changed, 11 insertions(+), 21 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 2c6b197..bd47985 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -212,19 +212,9 @@ if (defined $project) {\n \t}\n }\n \n+# We have to handle those containing any characters:\n our $file_name = $cgi->param('f');\n-if (defined $file_name) {\n-\tif (!validate_input($file_name)) {\n-\t\tdie_error(undef, \"Invalid file parameter\");\n-\t}\n-}\n-\n our $file_parent = $cgi->param('fp');\n-if (defined $file_parent) {\n-\tif (!validate_input($file_parent)) {\n-\t\tdie_error(undef, \"Invalid file parent parameter\");\n-\t}\n-}\n \n our $hash = $cgi->param('h');\n if (defined $hash) {\n@@ -305,7 +295,7 @@ sub evaluate_path_info {\n \t\t\t$action  ||= \"blob_plain\";\n \t\t}\n \t\t$hash_base ||= validate_input($refname);\n-\t\t$file_name ||= validate_input($pathname);\n+\t\t$file_name ||= $pathname;\n \t} elsif (defined $refname) {\n \t\t# we got \"project.git/branch\"\n \t\t$action ||= \"shortlog\";\n@@ -416,7 +406,7 @@ # quote unsafe chars, but keep the slash\n # correct, but quoted slashes look too horrible in bookmarks\n sub esc_param {\n \tmy $str = shift;\n-\t$str =~ s/([^A-Za-z0-9\\-_.~();\\/;?:@&=])/sprintf(\"%%%02X\", ord($1))/eg;\n+\t$str =~ s/([^A-Za-z0-9\\-_.~()\\/:@])/sprintf(\"%%%02X\", ord($1))/eg;\n \t$str =~ s/\\+/%2B/g;\n \t$str =~ s/ /\\+/g;\n \treturn $str;\n@@ -1289,7 +1279,7 @@ sub git_header_html {\n \t\tif (defined $action) {\n \t\t\t$title .= \"/$action\";\n \t\t\tif (defined $file_name) {\n-\t\t\t\t$title .= \" - $file_name\";\n+\t\t\t\t$title .= \" - \" . esc_html($file_name);\n \t\t\t\tif ($action eq \"tree\" && $file_name !~ m|/$|) {\n \t\t\t\t\t$title .= \"/\";\n \t\t\t\t}\n@@ -2439,7 +2429,7 @@ sub git_blame2 {\n \tif ($ftype !~ \"blob\") {\n \t\tdie_error(\"400 Bad Request\", \"Object is not a blob\");\n \t}\n-\topen ($fd, \"-|\", git_cmd(), \"blame\", '-l', $file_name, $hash_base)\n+\topen ($fd, \"-|\", git_cmd(), \"blame\", '-l', '--', $file_name, $hash_base)\n \t\tor die_error(undef, \"Open git-blame failed\");\n \tgit_header_html();\n \tmy $formats_nav =\n@@ -3081,12 +3071,12 @@ sub git_blobdiff {\n \t\tif (defined $file_name) {\n \t\t\tif (defined $file_parent) {\n \t\t\t\t$diffinfo{'status'} = '2';\n-\t\t\t\t$diffinfo{'from_file'} = $file_parent;\n-\t\t\t\t$diffinfo{'to_file'}   = $file_name;\n+\t\t\t\t$diffinfo{'from_file'} = esc_html($file_parent);\n+\t\t\t\t$diffinfo{'to_file'}   = esc_html($file_name);\n \t\t\t} else { # assume not renamed\n \t\t\t\t$diffinfo{'status'} = '1';\n-\t\t\t\t$diffinfo{'from_file'} = $file_name;\n-\t\t\t\t$diffinfo{'to_file'}   = $file_name;\n+\t\t\t\t$diffinfo{'from_file'} = esc_html($file_name);\n+\t\t\t\t$diffinfo{'to_file'}   = esc_html($file_name);\n \t\t\t}\n \t\t} else { # no filename given\n \t\t\t$diffinfo{'status'} = '2';\n@@ -3135,7 +3125,7 @@ sub git_blobdiff {\n \t\t\t-type => 'text/plain',\n \t\t\t-charset => 'utf-8',\n \t\t\t-expires => $expires,\n-\t\t\t-content_disposition => qq(inline; filename=\"${file_name}.patch\"));\n+\t\t\t-content_disposition => qq(inline; filename=\") . quotemeta($file_name) . qq(.patch\"));\n \n \t\tprint \"X-Git-Url: \" . $cgi->self_url() . \"\\n\\n\";\n \n@@ -3585,7 +3575,7 @@ XML\n \t\t\tif (!($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\\t(.*)$/)) {\n \t\t\t\tnext;\n \t\t\t}\n-\t\t\tmy $file = validate_input(unquote($7));\n+\t\t\tmy $file = esc_html(unquote($7));\n \t\t\t$file = decode(\"utf8\", $file, Encode::FB_DEFAULT);\n \t\t\tprint \"$file<br/>\\n\";\n \t\t}\n"},{"id":"27520","messageId":"ef4csl$7vk$1@sea.gmane.org","threadId":"5668","inReplyTo":"20060923221841.18063.56589.stgit@rover","subject":"Re: [PATCH] gitweb: Consolidate escaping/validation of query string","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-09-23T22:36:13Z","receivedAt":"2006-09-23T22:36:13Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Petr Baudis wrote:\n\n> Consider:\n> \n>         http://repo.or.cz/?p=glibc-cvs.git;a=tree;h=2609cb0411389325f4ee2854cc7159756eb0671e;hb=2609cb0411389325f4ee2854cc7159756eb0671e\n> \n> (click on the funny =__ify file)\n\nAaargh? Why this name?\n\n> We ought to handle anything in filenames and I actually see no reason why\n> we don't, modulo very little missing escaping that this patch hopefully\n> also fixes.\n> \n> I have also made esc_param() escape [?=&;]. Not escaping [&;] was downright\n> buggy and [?=] just feels better escaped. ;-) YMMV.\n\nFirst of all, before introduction href() subroutine we escaped (using \nesc_param) the _whole_ generated query string. Now we need to escape\nonly value part (as we can assume that parameter names are correct;\nthey are taken from limited pre-defined set).\n\nI'd rather have new esc_param() or esc_param_value() quote like escape\nsubroutine from CGI::Util, with the esception of _not_ escaping '/'\n(it makes funny bookmark, and lot less readable query string), and rename\ncurrent esc_param() to esc_query_string() or esc_params().\n\nPerhaps we should have also esc_arg() for things like title attribute\nof <a> (link) element (or other element) and filename=\"...\" part of\nContent-disposition: HTTP header.\n\n\nBy the way, the validate_input() should be split into separate subroutines:\nvalidate_ref() for validating hash, hash_base, hash_parent, hash_parent_base,\nand validate_path() for validating project, file_name and file_parent\nparameters.\n\nWe should _never_ use esc_html except during the output, or just before output.\nIt certainly shouldn't take place in parse_* subroutine (or in the fake parse\nlike in git_blobdiff)!\n\nP.S. gitweb was tested I think with filenames wirh spaces. Perhaps we should\nadd some other test file to gitweb/test, with '=', '@', '$', '?', '*', ' ', '\\n'\netc.\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"27522","messageId":"ef4d6v$7vk$3@sea.gmane.org","threadId":"5668","inReplyTo":"ef4csl$7vk$1@sea.gmane.org","subject":"Re: [PATCH] gitweb: Consolidate escaping/validation of query string","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-09-23T22:41:43Z","receivedAt":"2006-09-23T22:41:43Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Jakub Narebski wrote:\n\n> I'd rather have new esc_param() or esc_param_value() quote like escape\n> subroutine from CGI::Util, with the esception of _not_ escaping '/'\n> (it makes funny bookmark, and lot less readable query string), and rename\n> current esc_param() to esc_query_string() or esc_params().\n\nOr just esc_url()\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"27542","messageId":"20060924113613.GM20017@pasky.or.cz","threadId":"5668","inReplyTo":"ef4csl$7vk$1@sea.gmane.org","subject":"Re: [PATCH] gitweb: Consolidate escaping/validation of query string","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-09-24T11:36:13Z","receivedAt":"2006-09-24T11:36:13Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Sun, Sep 24, 2006 at 12:36:13AM CEST, I got a letter\nwhere Jakub Narebski <jnareb@gmail.com> said that...\n> Petr Baudis wrote:\n> > (click on the funny =__ify file)\n> \n> Aaargh? Why this name?\n\nYou tell me... ;-)\n\n> > I have also made esc_param() escape [?=&;]. Not escaping [&;] was downright\n> > buggy and [?=] just feels better escaped. ;-) YMMV.\n..snip..\n> I'd rather have new esc_param() or esc_param_value() quote like escape\n> subroutine from CGI::Util, with the esception of _not_ escaping '/'\n> (it makes funny bookmark, and lot less readable query string), and rename\n> current esc_param() to esc_query_string() or esc_params().\n\nHuh, well, what's the point with the rename and why not keep it as it is\nwith just removing the four characters above? Escaped stuff looks ugly\nin a URL. ;-)\n\nBTW, looking at CGI::Util innards, what sick mind serves CGIs from an\nEBCDIC machine?\n\n> Perhaps we should have also esc_arg() for things like title attribute\n> of <a> (link) element (or other element)\n\nYes. I wanted to implement your few months old wish to have full string\nof abbreviated column contents in title attributes but delayed it for\nnow because we have no such function yet.\n\n> and filename=\"...\" part of Content-disposition: HTTP header.\n\nThis is not HTML-ish so you need quotemeta() here, using entities makes\nno sense in this case.\n\n> By the way, the validate_input() should be split into separate subroutines:\n> validate_ref() for validating hash, hash_base, hash_parent, hash_parent_base,\n> and validate_path() for validating project,\n\nYes, that would be nice.\n\n> file_name and file_parent parameters.\n\nWhat's the point in validating those?\n\n> We should _never_ use esc_html except during the output, or just before output.\n> It certainly shouldn't take place in parse_* subroutine (or in the fake parse\n> like in git_blobdiff)!\n\nYes, I agree. Will send a fixed patch.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\n#!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj\n$/=unpack('H*',$_);$_=`echo 16dio\\U$k\"SK$/SM$n\\EsN0p[lN*1\nlK[d2%Sa2/d0$^Ixp\"|dc`;s/\\W//g;$_=pack('H*',/((..)*)$/)\n"},{"id":"27544","messageId":"20060924113932.11208.33780.stgit@rover","threadId":"5668","inReplyTo":"ef4csl$7vk$1@sea.gmane.org","subject":"[PATCH] gitweb: Consolidate escaping/validation of query string","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-09-24T11:39:32Z","receivedAt":"2006-09-24T11:39:32Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Consider:\n\n\thttp://repo.or.cz/?p=glibc-cvs.git;a=tree;h=2609cb0411389325f4ee2854cc7159756eb0671e;hb=2609cb0411389325f4ee2854cc7159756eb0671e\n\n(click on the funny =__ify file)\n\nWe ought to handle anything in filenames and I actually see no reason why\nwe don't, modulo very little missing escaping that this patch hopefully\nalso fixes.\n\nI have also made esc_param() escape [?=&;]. Not escaping [&;] was downright\nbuggy and [?=] just feels better escaped. ;-) YMMV.\n\nSigned-off-by: Petr Baudis <pasky@suse.cz>\n---\n\n gitweb/gitweb.perl |   28 +++++++++-------------------\n 1 files changed, 9 insertions(+), 19 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 2c6b197..f3c5bd8 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -212,19 +212,9 @@ if (defined $project) {\n \t}\n }\n \n+# We have to handle those containing any characters:\n our $file_name = $cgi->param('f');\n-if (defined $file_name) {\n-\tif (!validate_input($file_name)) {\n-\t\tdie_error(undef, \"Invalid file parameter\");\n-\t}\n-}\n-\n our $file_parent = $cgi->param('fp');\n-if (defined $file_parent) {\n-\tif (!validate_input($file_parent)) {\n-\t\tdie_error(undef, \"Invalid file parent parameter\");\n-\t}\n-}\n \n our $hash = $cgi->param('h');\n if (defined $hash) {\n@@ -305,7 +295,7 @@ sub evaluate_path_info {\n \t\t\t$action  ||= \"blob_plain\";\n \t\t}\n \t\t$hash_base ||= validate_input($refname);\n-\t\t$file_name ||= validate_input($pathname);\n+\t\t$file_name ||= $pathname;\n \t} elsif (defined $refname) {\n \t\t# we got \"project.git/branch\"\n \t\t$action ||= \"shortlog\";\n@@ -416,7 +406,7 @@ # quote unsafe chars, but keep the slash\n # correct, but quoted slashes look too horrible in bookmarks\n sub esc_param {\n \tmy $str = shift;\n-\t$str =~ s/([^A-Za-z0-9\\-_.~();\\/;?:@&=])/sprintf(\"%%%02X\", ord($1))/eg;\n+\t$str =~ s/([^A-Za-z0-9\\-_.~()\\/:@])/sprintf(\"%%%02X\", ord($1))/eg;\n \t$str =~ s/\\+/%2B/g;\n \t$str =~ s/ /\\+/g;\n \treturn $str;\n@@ -1289,7 +1279,7 @@ sub git_header_html {\n \t\tif (defined $action) {\n \t\t\t$title .= \"/$action\";\n \t\t\tif (defined $file_name) {\n-\t\t\t\t$title .= \" - $file_name\";\n+\t\t\t\t$title .= \" - \" . esc_html($file_name);\n \t\t\t\tif ($action eq \"tree\" && $file_name !~ m|/$|) {\n \t\t\t\t\t$title .= \"/\";\n \t\t\t\t}\n@@ -2439,7 +2429,7 @@ sub git_blame2 {\n \tif ($ftype !~ \"blob\") {\n \t\tdie_error(\"400 Bad Request\", \"Object is not a blob\");\n \t}\n-\topen ($fd, \"-|\", git_cmd(), \"blame\", '-l', $file_name, $hash_base)\n+\topen ($fd, \"-|\", git_cmd(), \"blame\", '-l', '--', $file_name, $hash_base)\n \t\tor die_error(undef, \"Open git-blame failed\");\n \tgit_header_html();\n \tmy $formats_nav =\n@@ -3135,7 +3125,7 @@ sub git_blobdiff {\n \t\t\t-type => 'text/plain',\n \t\t\t-charset => 'utf-8',\n \t\t\t-expires => $expires,\n-\t\t\t-content_disposition => qq(inline; filename=\"${file_name}.patch\"));\n+\t\t\t-content_disposition => qq(inline; filename=\") . quotemeta($file_name) . qq(.patch\"));\n \n \t\tprint \"X-Git-Url: \" . $cgi->self_url() . \"\\n\\n\";\n \n@@ -3155,8 +3145,8 @@ sub git_blobdiff {\n \n \t} else {\n \t\twhile (my $line = <$fd>) {\n-\t\t\t$line =~ s!a/($hash|$hash_parent)!a/$diffinfo{'from_file'}!g;\n-\t\t\t$line =~ s!b/($hash|$hash_parent)!b/$diffinfo{'to_file'}!g;\n+\t\t\t$line =~ s!a/($hash|$hash_parent)!'a/'.esc_html($diffinfo{'from_file'})!eg;\n+\t\t\t$line =~ s!b/($hash|$hash_parent)!'b/'.esc_html($diffinfo{'to_file'})!eg;\n \n \t\t\tprint $line;\n \n@@ -3585,7 +3575,7 @@ XML\n \t\t\tif (!($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\\t(.*)$/)) {\n \t\t\t\tnext;\n \t\t\t}\n-\t\t\tmy $file = validate_input(unquote($7));\n+\t\t\tmy $file = esc_html(unquote($7));\n \t\t\t$file = decode(\"utf8\", $file, Encode::FB_DEFAULT);\n \t\t\tprint \"$file<br/>\\n\";\n \t\t}\n"},{"id":"27549","messageId":"200609241421.21930.jnareb@gmail.com","threadId":"5668","inReplyTo":"20060924113613.GM20017@pasky.or.cz","subject":"Re: [PATCH] gitweb: Consolidate escaping/validation of query string","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-09-24T12:21:21Z","receivedAt":"2006-09-24T12:21:21Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Petr \"Pasky\" Baudis wrote:\n>>> I have also made esc_param() escape [?=&;]. Not escaping [&;] was downright\n>>> buggy and [?=] just feels better escaped. ;-) YMMV.\n> ..snip..\n>> I'd rather have new esc_param() or esc_param_value() quote like escape\n>> subroutine from CGI::Util, with the esception of _not_ escaping '/'\n>> (it makes funny bookmark, and lot less readable query string), and rename\n>> current esc_param() to esc_query_string() or esc_params().\n> \n> Huh, well, what's the point with the rename and why not keep it as it is\n> with just removing the four characters above? Escaped stuff looks ugly\n> in a URL. ;-)\n\nThere are few places where we escape whole URL (so I'd prefer esc_url() for\ncurrent implementation): esc_param($home_link) and soon esc_param($githelp_url)\n(and _not_ esc_html($githelp_url)). And those URLs can contain query strings,\nso we cannot escape '?', ';' and '&', '=' there.\n\nBefore introduction of href() subroutine we escaped using esc_param the whole\nquery string, hence esc_param did not escaped [?=&;].\n-- \nJakub Narebski\nPoland\n"},{"id":"27550","messageId":"ef5tqa$bjd$1@sea.gmane.org","threadId":"5668","inReplyTo":"20060924113932.11208.33780.stgit@rover","subject":"Re: [PATCH] gitweb: Consolidate escaping/validation of query string","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-09-24T12:31:08Z","receivedAt":"2006-09-24T12:31:08Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Petr Baudis wrote:\n\n> Consider:\n> \n>       http://repo.or.cz/?p=glibc-cvs.git;a=tree;h=2609cb0411389325f4ee2854cc7159756eb0671e;hb=2609cb0411389325f4ee2854cc7159756eb0671e\n> \n> (click on the funny =__ify file)\n> \n> We ought to handle anything in filenames and I actually see no reason why\n> we don't, modulo very little missing escaping that this patch hopefully\n> also fixes.\n> \n> I have also made esc_param() escape [?=&;]. Not escaping [&;] was downright\n> buggy and [?=] just feels better escaped. ;-) YMMV.\n> \n> Signed-off-by: Petr Baudis <pasky@suse.cz>\n\nThis patch contains a few unrelated changes:\n * changing semantics of esc_param subroutine\n * adding some esc_html where it could be needed\n * removing $file_name and $file_parent validation\n\nAbout change to esc_param: we need current version of esc_param, perhaps\nto be named esc_url to be able to say esc_url($home_link) and soon\nesc_url($githelp_url).\n\nAbout adding esc_html where it could be needed: good change, see\nmy comments below.\n\nAbout removing $file_name and $file_parent validation: those parameters\nhave exactly the same textual restrictions as $project parameter - they\nare pathnames.\n\n> @@ -2439,7 +2429,7 @@ sub git_blame2 {\n>       if ($ftype !~ \"blob\") {\n>               die_error(\"400 Bad Request\", \"Object is not a blob\");\n>       }\n> -     open ($fd, \"-|\", git_cmd(), \"blame\", '-l', $file_name, $hash_base)\n> +     open ($fd, \"-|\", git_cmd(), \"blame\", '-l', '--', $file_name, $hash_base)\n>               or die_error(undef, \"Open git-blame failed\");\n>       git_header_html();\n>       my $formats_nav =\n\nSlightly unrelated change. Shouldn't it be\n\n        open $fd, \"-|\", git_cmd(), \"blame\", '-l', $hash_base, \"--\", $file_name\n\nby the way?\n\n> @@ -3135,7 +3125,7 @@ sub git_blobdiff {\n>                       -type => 'text/plain',\n>                       -charset => 'utf-8',\n>                       -expires => $expires,\n> -                     -content_disposition => qq(inline; filename=\"${file_name}.patch\"));\n> +                     -content_disposition => qq(inline; filename=\") . quotemeta($file_name) . qq(.patch\"));\n>  \n>               print \"X-Git-Url: \" . $cgi->self_url() . \"\\n\\n\";\n>  \n\nI'd check other places where we output Content-Disposition: header.\nAt least one place needs similar quotemeta somewhere.\n\n> @@ -3585,7 +3575,7 @@ XML\n>                       if (!($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\\t(.*)$/)) {\n>                               next;\n>                       }\n> -                     my $file = validate_input(unquote($7));\n> +                     my $file = esc_html(unquote($7));\n>                       $file = decode(\"utf8\", $file, Encode::FB_DEFAULT);\n>                       print \"$file<br/>\\n\";\n>               }\n\nI'd say perhaps\n\n        my $file = unquote($7);\n        $file = decode(\"utf8\", $file, Encode::FB_DEFAULT);\n        print esc_html($file) . \"<br/>\\n\";\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"}]}