{"thread":{"id":"24001","subject":"[RFC/PATCH] gitweb: Create Gitweb::Escape module","startedAt":"2010-06-04T09:07:17Z","lastAt":"2010-06-05T09:22:10Z","messageCount":2,"participants":["Pavan Kumar Sunkara","Jakub Narebski"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"142953","messageId":"1275642437-4846-1-git-send-email-pavan.sss1991@gmail.com","threadId":"24001","inReplyTo":null,"subject":"[RFC/PATCH] gitweb: Create Gitweb::Escape module","fromName":"Pavan Kumar Sunkara","fromEmail":"pavan.sss1991@gmail.com","sentAt":"2010-06-04T09:07:17Z","receivedAt":"2010-06-04T09:07:17Z","isPatch":true,"sender":{"key":"pavan.sss1991@gmail.com","avatar":"https://avatars.githubusercontent.com/u/174703?v=4"},"body":"Create a Gitweb::Escape module in 'gitweb/lib/Gitweb/Escape.pm'\nto store all the quoting/unquoting and escaping subroutines\nregarding the gitweb.perl script.\n\nSubroutines moved:\n\tto_utf8\n\tesc_param\n\tesc_url\n\tesc_html\n\tesc_path\n\tquot_cec\n\tquot_upr\n\tunquote\n\tuntabify\n\nSubroutines yet to move: (Contains not yet packaged subs & vars)\n\tNone\n\nUpdate gitweb/Makefile to install gitweb modules alongside gitwe\n\nSigned-off-by: Pavan Kumar Sunkara <pavan.sss1991@gmail.com>\n---\n gitweb/Makefile             |    1 +\n gitweb/gitweb.perl          |  157 +--------------------------------------\n gitweb/lib/Gitweb/Escape.pm |  175 +++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 177 insertions(+), 156 deletions(-)\n create mode 100644 gitweb/lib/Gitweb/Escape.pm\n\ndiff --git a/gitweb/Makefile b/gitweb/Makefile\nindex 15646b2..4343396 100644\n--- a/gitweb/Makefile\n+++ b/gitweb/Makefile\n@@ -114,6 +114,7 @@ GITWEB_FILES += static/git-logo.png static/git-favicon.png\n # Files: gitweb/lib/Gitweb\n GITWEB_LIB_GITWEB += lib/Gitweb/Config.pm\n GITWEB_LIB_GITWEB += lib/Gitweb/Request.pm\n+GITWEB_LIB_GITWEB += lib/Gitweb/Escape.pm\n \n GITWEB_REPLACE = \\\n \t-e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \\\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex b30ac48..9e54983 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -12,7 +12,6 @@ use warnings;\n use CGI qw(:standard :escapeHTML -nosticky);\n use CGI::Util qw(unescape);\n use CGI::Carp qw(fatalsToBrowser set_message);\n-use Encode;\n use Fcntl ':mode';\n use File::Find qw();\n use File::Basename qw(basename);\n@@ -27,6 +26,7 @@ use lib __DIR__ . \"/lib\";\n \n use Gitweb::Config;\n use Gitweb::Request;\n+use Gitweb::Escape;\n \n BEGIN {\n \tCGI->compile() if $ENV{'MOD_PERL'};\n@@ -762,161 +762,6 @@ sub validate_project {\n \t}\n }\n \n-# decode sequences of octets in utf8 into Perl's internal form,\n-# which is utf-8 with utf8 flag set if needed.  gitweb writes out\n-# in utf-8 thanks to \"binmode STDOUT, ':utf8'\" at beginning\n-sub to_utf8 {\n-\tmy $str = shift;\n-\treturn undef unless defined $str;\n-\tif (utf8::valid($str)) {\n-\t\tutf8::decode($str);\n-\t\treturn $str;\n-\t} else {\n-\t\treturn decode($fallback_encoding, $str, Encode::FB_DEFAULT);\n-\t}\n-}\n-\n-# quote unsafe chars, but keep the slash, even when it's not\n-# correct, but quoted slashes look too horrible in bookmarks\n-sub esc_param {\n-\tmy $str = shift;\n-\treturn undef unless defined $str;\n-\t$str =~ s/([^A-Za-z0-9\\-_.~()\\/:@ ]+)/CGI::escape($1)/eg;\n-\t$str =~ s/ /\\+/g;\n-\treturn $str;\n-}\n-\n-# quote unsafe chars in whole URL, so some charactrs cannot be quoted\n-sub esc_url {\n-\tmy $str = shift;\n-\treturn undef unless defined $str;\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-}\n-\n-# replace invalid utf8 character with SUBSTITUTION sequence\n-sub esc_html {\n-\tmy $str = shift;\n-\tmy %opts = @_;\n-\n-\treturn undef unless defined $str;\n-\n-\t$str = to_utf8($str);\n-\t$str = $cgi->escapeHTML($str);\n-\tif ($opts{'-nbsp'}) {\n-\t\t$str =~ s/ /&nbsp;/g;\n-\t}\n-\t$str =~ s|([[:cntrl:]])|(($1 ne \"\\t\") ? quot_cec($1) : $1)|eg;\n-\treturn $str;\n-}\n-\n-# quote control characters and escape filename to HTML\n-sub esc_path {\n-\tmy $str = shift;\n-\tmy %opts = @_;\n-\n-\treturn undef unless defined $str;\n-\n-\t$str = to_utf8($str);\n-\t$str = $cgi->escapeHTML($str);\n-\tif ($opts{'-nbsp'}) {\n-\t\t$str =~ s/ /&nbsp;/g;\n-\t}\n-\t$str =~ s|([[:cntrl:]])|quot_cec($1)|eg;\n-\treturn $str;\n-}\n-\n-# Make control characters \"printable\", using character escape codes (CEC)\n-sub quot_cec {\n-\tmy $cntrl = shift;\n-\tmy %opts = @_;\n-\tmy %es = ( # character escape codes, aka escape sequences\n-\t\t\"\\t\" => '\\t',   # tab            (HT)\n-\t\t\"\\n\" => '\\n',   # line feed      (LF)\n-\t\t\"\\r\" => '\\r',   # carrige return (CR)\n-\t\t\"\\f\" => '\\f',   # form feed      (FF)\n-\t\t\"\\b\" => '\\b',   # backspace      (BS)\n-\t\t\"\\a\" => '\\a',   # alarm (bell)   (BEL)\n-\t\t\"\\e\" => '\\e',   # escape         (ESC)\n-\t\t\"\\013\" => '\\v', # vertical tab   (VT)\n-\t\t\"\\000\" => '\\0', # nul character  (NUL)\n-\t);\n-\tmy $chr = ( (exists $es{$cntrl})\n-\t\t    ? $es{$cntrl}\n-\t\t    : sprintf('\\%2x', ord($cntrl)) );\n-\tif ($opts{-nohtml}) {\n-\t\treturn $chr;\n-\t} else {\n-\t\treturn \"<span class=\\\"cntrl\\\">$chr</span>\";\n-\t}\n-}\n-\n-# Alternatively use unicode control pictures codepoints,\n-# Unicode \"printable representation\" (PR)\n-sub quot_upr {\n-\tmy $cntrl = shift;\n-\tmy %opts = @_;\n-\n-\tmy $chr = sprintf('&#%04d;', 0x2400+ord($cntrl));\n-\tif ($opts{-nohtml}) {\n-\t\treturn $chr;\n-\t} else {\n-\t\treturn \"<span class=\\\"cntrl\\\">$chr</span>\";\n-\t}\n-}\n-\n-# git may return quoted and escaped filenames\n-sub unquote {\n-\tmy $str = shift;\n-\n-\tsub unq {\n-\t\tmy $seq = shift;\n-\t\tmy %es = ( # character escape codes, aka escape sequences\n-\t\t\t't' => \"\\t\",   # tab            (HT, TAB)\n-\t\t\t'n' => \"\\n\",   # newline        (NL)\n-\t\t\t'r' => \"\\r\",   # return         (CR)\n-\t\t\t'f' => \"\\f\",   # form feed      (FF)\n-\t\t\t'b' => \"\\b\",   # backspace      (BS)\n-\t\t\t'a' => \"\\a\",   # alarm (bell)   (BEL)\n-\t\t\t'e' => \"\\e\",   # escape         (ESC)\n-\t\t\t'v' => \"\\013\", # vertical tab   (VT)\n-\t\t);\n-\n-\t\tif ($seq =~ m/^[0-7]{1,3}$/) {\n-\t\t\t# octal char sequence\n-\t\t\treturn chr(oct($seq));\n-\t\t} elsif (exists $es{$seq}) {\n-\t\t\t# C escape sequence, aka character escape code\n-\t\t\treturn $es{$seq};\n-\t\t}\n-\t\t# quoted ordinary character\n-\t\treturn $seq;\n-\t}\n-\n-\tif ($str =~ m/^\"(.*)\"$/) {\n-\t\t# needs unquoting\n-\t\t$str = $1;\n-\t\t$str =~ s/\\\\([^0-7]|[0-7]{1,3})/unq($1)/eg;\n-\t}\n-\treturn $str;\n-}\n-\n-# escape tabs (convert tabs to spaces)\n-sub untabify {\n-\tmy $line = shift;\n-\n-\twhile ((my $pos = index($line, \"\\t\")) != -1) {\n-\t\tif (my $count = (8 - ($pos % 8))) {\n-\t\t\tmy $spaces = ' ' x $count;\n-\t\t\t$line =~ s/\\t/$spaces/;\n-\t\t}\n-\t}\n-\n-\treturn $line;\n-}\n-\n sub project_in_list {\n \tmy $project = shift;\n \tmy @list = git_get_projects_list();\ndiff --git a/gitweb/lib/Gitweb/Escape.pm b/gitweb/lib/Gitweb/Escape.pm\nnew file mode 100644\nindex 0000000..f6ea209\n--- /dev/null\n+++ b/gitweb/lib/Gitweb/Escape.pm\n@@ -0,0 +1,175 @@\n+#!/usr/bin/perl\n+#\n+# Gitweb::Escape -- gitweb's quoting/unquoting, escaping package\n+#\n+# This program is licensed under the GPLv2\n+\n+package Gitweb::Escape;\n+\n+use strict;\n+use warnings;\n+use Exporter qw(import);\n+\n+our @ISA = qw(Exporter);\n+our @EXPORT = qw(&to_utf8 &esc_param &esc_url &esc_html &esc_path &quot_cec &quot_upr &unquote &untabify);\n+\n+use Encode;\n+use Gitweb::Config;\n+use Gitweb::Request;\n+\n+# decode sequences of octets in utf8 into Perl's internal form,\n+# which is utf-8 with utf8 flag set if needed.  gitweb writes out\n+# in utf-8 thanks to \"binmode STDOUT, ':utf8'\" at beginning\n+sub to_utf8 {\n+\tmy $str = shift;\n+\treturn undef unless defined $str;\n+\tif (utf8::valid($str)) {\n+\t\tutf8::decode($str);\n+\t\treturn $str;\n+\t} else {\n+\t\treturn decode($fallback_encoding, $str, Encode::FB_DEFAULT);\n+\t}\n+}\n+\n+# quote unsafe chars, but keep the slash, even when it's not\n+# correct, but quoted slashes look too horrible in bookmarks\n+sub esc_param {\n+\tmy $str = shift;\n+\treturn undef unless defined $str;\n+\t$str =~ s/([^A-Za-z0-9\\-_.~()\\/:@ ]+)/CGI::escape($1)/eg;\n+\t$str =~ s/ /\\+/g;\n+\treturn $str;\n+}\n+\n+# quote unsafe chars in whole URL, so some charactrs cannot be quoted\n+sub esc_url {\n+\tmy $str = shift;\n+\treturn undef unless defined $str;\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+}\n+\n+# replace invalid utf8 character with SUBSTITUTION sequence\n+sub esc_html {\n+\tmy $str = shift;\n+\tmy %opts = @_;\n+\n+\treturn undef unless defined $str;\n+\n+\t$str = to_utf8($str);\n+\t$str = $cgi->escapeHTML($str);\n+\tif ($opts{'-nbsp'}) {\n+\t\t$str =~ s/ /&nbsp;/g;\n+\t}\n+\t$str =~ s|([[:cntrl:]])|(($1 ne \"\\t\") ? quot_cec($1) : $1)|eg;\n+\treturn $str;\n+}\n+\n+# quote control characters and escape filename to HTML\n+sub esc_path {\n+\tmy $str = shift;\n+\tmy %opts = @_;\n+\n+\treturn undef unless defined $str;\n+\n+\t$str = to_utf8($str);\n+\t$str = $cgi->escapeHTML($str);\n+\tif ($opts{'-nbsp'}) {\n+\t\t$str =~ s/ /&nbsp;/g;\n+\t}\n+\t$str =~ s|([[:cntrl:]])|quot_cec($1)|eg;\n+\treturn $str;\n+}\n+\n+# Make control characters \"printable\", using character escape codes (CEC)\n+sub quot_cec {\n+\tmy $cntrl = shift;\n+\tmy %opts = @_;\n+\tmy %es = ( # character escape codes, aka escape sequences\n+\t\t\"\\t\" => '\\t',   # tab            (HT)\n+\t\t\"\\n\" => '\\n',   # line feed      (LF)\n+\t\t\"\\r\" => '\\r',   # carrige return (CR)\n+\t\t\"\\f\" => '\\f',   # form feed      (FF)\n+\t\t\"\\b\" => '\\b',   # backspace      (BS)\n+\t\t\"\\a\" => '\\a',   # alarm (bell)   (BEL)\n+\t\t\"\\e\" => '\\e',   # escape         (ESC)\n+\t\t\"\\013\" => '\\v', # vertical tab   (VT)\n+\t\t\"\\000\" => '\\0', # nul character  (NUL)\n+\t);\n+\tmy $chr = ( (exists $es{$cntrl})\n+\t\t    ? $es{$cntrl}\n+\t\t    : sprintf('\\%2x', ord($cntrl)) );\n+\tif ($opts{-nohtml}) {\n+\t\treturn $chr;\n+\t} else {\n+\t\treturn \"<span class=\\\"cntrl\\\">$chr</span>\";\n+\t}\n+}\n+\n+# Alternatively use unicode control pictures codepoints,\n+# Unicode \"printable representation\" (PR)\n+sub quot_upr {\n+\tmy $cntrl = shift;\n+\tmy %opts = @_;\n+\n+\tmy $chr = sprintf('&#%04d;', 0x2400+ord($cntrl));\n+\tif ($opts{-nohtml}) {\n+\t\treturn $chr;\n+\t} else {\n+\t\treturn \"<span class=\\\"cntrl\\\">$chr</span>\";\n+\t}\n+}\n+\n+# git may return quoted and escaped filenames\n+sub unquote {\n+\tmy $str = shift;\n+\n+\tsub unq {\n+\t\tmy $seq = shift;\n+\t\tmy %es = ( # character escape codes, aka escape sequences\n+\t\t\t't' => \"\\t\",   # tab            (HT, TAB)\n+\t\t\t'n' => \"\\n\",   # newline        (NL)\n+\t\t\t'r' => \"\\r\",   # return         (CR)\n+\t\t\t'f' => \"\\f\",   # form feed      (FF)\n+\t\t\t'b' => \"\\b\",   # backspace      (BS)\n+\t\t\t'a' => \"\\a\",   # alarm (bell)   (BEL)\n+\t\t\t'e' => \"\\e\",   # escape         (ESC)\n+\t\t\t'v' => \"\\013\", # vertical tab   (VT)\n+\t\t);\n+\n+\t\tif ($seq =~ m/^[0-7]{1,3}$/) {\n+\t\t\t# octal char sequence\n+\t\t\treturn chr(oct($seq));\n+\t\t} elsif (exists $es{$seq}) {\n+\t\t\t# C escape sequence, aka character escape code\n+\t\t\treturn $es{$seq};\n+\t\t}\n+\t\t# quoted ordinary character\n+\t\treturn $seq;\n+\t}\n+\n+\tif ($str =~ m/^\"(.*)\"$/) {\n+\t\t# needs unquoting\n+\t\t$str = $1;\n+\t\t$str =~ s/\\\\([^0-7]|[0-7]{1,3})/unq($1)/eg;\n+\t}\n+\treturn $str;\n+}\n+\n+# escape tabs (convert tabs to spaces)\n+sub untabify {\n+\tmy $line = shift;\n+\n+\twhile ((my $pos = index($line, \"\\t\")) != -1) {\n+\t\tif (my $count = (8 - ($pos % 8))) {\n+\t\t\tmy $spaces = ' ' x $count;\n+\t\t\t$line =~ s/\\t/$spaces/;\n+\t\t}\n+\t}\n+\n+\treturn $line;\n+}\n+\n+1;\n-- \n1.7.1.447.g2b98e.dirty\n"},{"id":"143027","messageId":"201006051122.12565.jnareb@gmail.com","threadId":"24001","inReplyTo":"1275642437-4846-1-git-send-email-pavan.sss1991@gmail.com","subject":"Re: [RFC/PATCH] gitweb: Create Gitweb::Escape module","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2010-06-05T09:22:10Z","receivedAt":"2010-06-05T09:22:10Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Fri, 4 June 2010, Pavan Kumar Sunkara wrote:\n\n> Create a Gitweb::Escape module in 'gitweb/lib/Gitweb/Escape.pm'\n> to store all the quoting/unquoting and escaping subroutines\n> regarding the gitweb.perl script.\n\n<del>\nI would ask if it wouldn't be simpler to just have Gitweb::Util\nfor all auxiliary / helper subroutines...\n\n...if not for the fact that to avoid circular dependencies you would\nhave, most probably, split this module further into\n * Gitweb::Escape::CGI\n * Gitweb::Escape::HTML\nand perhaps move 'unquote' to Gitweb::Git or Gitweb::Escape::Git.\nThen Gitweb::Escape could just import both.\n</del>\n\nErrr... sorry.  I guess that either Gitweb::Config nor Gitweb::Request\nneeds to include Gitweb::Escape.\n\nNote that 'Escape' part of name is not entirely correct, because some of\nsubroutines mentioned below deal with _quoting_ / _unquoting_, not with\nescaping / unescaping.\n\n> \n> Subroutines moved:\n> \tto_utf8\n> \tesc_param\n> \tesc_url\n> \tesc_html\n> \tesc_path\n> \tquot_cec\n> \tquot_upr\n> \tunquote\n> \tuntabify\n> \n> Subroutines yet to move: (Contains not yet packaged subs & vars)\n> \tNone\n> \n> Update gitweb/Makefile to install gitweb modules alongside gitwe\n> \n> Signed-off-by: Pavan Kumar Sunkara <pavan.sss1991@gmail.com>\n> ---\n>  gitweb/Makefile             |    1 +\n>  gitweb/gitweb.perl          |  157 +--------------------------------------\n>  gitweb/lib/Gitweb/Escape.pm |  175 +++++++++++++++++++++++++++++++++++++++++++\n>  3 files changed, 177 insertions(+), 156 deletions(-)\n>  create mode 100644 gitweb/lib/Gitweb/Escape.pm\n\nIt's a pity that git cannot tell us here that it is straight code\nmovement (moving code block from one file to the other)...\n\n> diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\n> index b30ac48..9e54983 100755\n> --- a/gitweb/gitweb.perl\n> +++ b/gitweb/gitweb.perl\n> @@ -12,7 +12,6 @@ use warnings;\n>  use CGI qw(:standard :escapeHTML -nosticky);\n>  use CGI::Util qw(unescape);\n>  use CGI::Carp qw(fatalsToBrowser set_message);\n> -use Encode;\n>  use Fcntl ':mode';\n>  use File::Find qw();\n>  use File::Basename qw(basename);\n> @@ -27,6 +26,7 @@ use lib __DIR__ . \"/lib\";\n>  \n>  use Gitweb::Config;\n>  use Gitweb::Request;\n> +use Gitweb::Escape;\n>  \n>  BEGIN {\n>  \tCGI->compile() if $ENV{'MOD_PERL'};\n> @@ -762,161 +762,6 @@ sub validate_project {\n>  \t}\n>  }\n>  \n> -# decode sequences of octets in utf8 into Perl's internal form,\n> -# which is utf-8 with utf8 flag set if needed.  gitweb writes out\n> -# in utf-8 thanks to \"binmode STDOUT, ':utf8'\" at beginning\n> -sub to_utf8 {\n\n[cut]\n\n> diff --git a/gitweb/lib/Gitweb/Escape.pm b/gitweb/lib/Gitweb/Escape.pm\n> new file mode 100644\n> index 0000000..f6ea209\n> --- /dev/null\n> +++ b/gitweb/lib/Gitweb/Escape.pm\n> @@ -0,0 +1,175 @@\n> +#!/usr/bin/perl\n> +#\n> +# Gitweb::Escape -- gitweb's quoting/unquoting, escaping package\n> +#\n> +# This program is licensed under the GPLv2\n> +\n> +package Gitweb::Escape;\n> +\n> +use strict;\n> +use warnings;\n> +use Exporter qw(import);\n> +\n> +our @ISA = qw(Exporter);\n\nThis line is not necessary if you are using 'use Exporter qw(import);'\n\n\nThis code:\n\n  use Exporter;\n  our @ISA = qw(Exporter);\n\nis equivalent to (safer)\n\n  use Exporter;\n  use base qw(Exporter);\n\nThe section \"Exporting without inheriting from Exporter\" of\nExporter(3pm) manpage says that using\n\n  use Exporter qw(import);\n\nallows to avoid inheriting our package from Exporter.\n\n> +our @EXPORT = qw(&to_utf8 &esc_param &esc_url &esc_html &esc_path &quot_cec &quot_upr &unquote &untabify);\n\nPlease try to not introduce such long likes.  Perhaps:\n\n  +our @EXPORT = qw(&to_utf8 &esc_param &esc_url &esc_html &esc_path\n                    &quot_cec &quot_upr &unquote &untabify);\n\nAlso ampersands are not needed there, and I think hat they are not used\nusually, so it would be:\n\n  +our @EXPORT = qw(to_utf8 esc_param esc_url esc_html esc_path\n                    quot_cec quot_upr unquote untabify);\n\nBut note also comment below about splitting this file further.\n\n> +\n> +use Encode;\n\nPerhaps empty line between 'use Exporter;' (using outside Perl modules)\nand 'use Gitweb::Config;' would help readibility of code, hmmm...?\n\nAlso, don't you need 'use CGI;' or 'use CGI qw(:escapeHTML);' here, to\nhave access to CGI::escape (to be more exact CGI::Util::escape, but\nimported by CGI to CGI::escape) and CGI::escapeHTML?\n\n> +use Gitweb::Config;\n\nI personally would say here explicitely\n\n  +use Gitweb::Config qw($fallback_encoding);\n\nto make it clear that we need only this single one config variable.\n\n> +use Gitweb::Request;\n\nAs it is shown below, this is not necessary.\n\n> +\n> +# decode sequences of octets in utf8 into Perl's internal form,\n> +# which is utf-8 with utf8 flag set if needed.  gitweb writes out\n> +# in utf-8 thanks to \"binmode STDOUT, ':utf8'\" at beginning\n\ns/at beginning/at beginning of XXX/;\n\n> +sub to_utf8 {\n> +\tmy $str = shift;\n> +\treturn undef unless defined $str;\n> +\tif (utf8::valid($str)) {\n> +\t\tutf8::decode($str);\n> +\t\treturn $str;\n> +\t} else {\n> +\t\treturn decode($fallback_encoding, $str, Encode::FB_DEFAULT);\n> +\t}\n> +}\n\nThis single one uses $fallback_encoding from Gitweb::Config.\n\n> +\n> +# quote unsafe chars, but keep the slash, even when it's not\n> +# correct, but quoted slashes look too horrible in bookmarks\n> +sub esc_param {\n> +\tmy $str = shift;\n> +\treturn undef unless defined $str;\n> +\t$str =~ s/([^A-Za-z0-9\\-_.~()\\/:@ ]+)/CGI::escape($1)/eg;\n> +\t$str =~ s/ /\\+/g;\n> +\treturn $str;\n> +}\n> +\n> +# quote unsafe chars in whole URL, so some charactrs cannot be quoted\n> +sub esc_url {\n> +\tmy $str = shift;\n> +\treturn undef unless defined $str;\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> +}\n\nHmmm... why this difference?  esc_url() should differ from esc_param()\nonly in that esc_url() escapes less (it should not escape query\nparameter delimites).  It seems like 452e225 (gitweb: fix esc_param,\n2009-10-13) by Giuseppe Bilotta missed fixing esc_url(), isn't it?\n\nMight be worth fixing upfront (in a separate commit, of course).  Could\nyou do this, please?\n\n> +\n> +# replace invalid utf8 character with SUBSTITUTION sequence\n> +sub esc_html {\n> +\tmy $str = shift;\n> +\tmy %opts = @_;\n> +\n> +\treturn undef unless defined $str;\n> +\n> +\t$str = to_utf8($str);\n> +\t$str = $cgi->escapeHTML($str);\n\nWe can use 'CGI::escapeHTML;' here, and avoid dependency on\nGitweb::Request.\n\nThis change probably should be done in a separate cleanup patch,\npreceding this one.\n\n> +\tif ($opts{'-nbsp'}) {\n> +\t\t$str =~ s/ /&nbsp;/g;\n> +\t}\n> +\t$str =~ s|([[:cntrl:]])|(($1 ne \"\\t\") ? quot_cec($1) : $1)|eg;\n> +\treturn $str;\n> +}\n> +\n> +# quote control characters and escape filename to HTML\n> +sub esc_path {\n> +\tmy $str = shift;\n> +\tmy %opts = @_;\n> +\n> +\treturn undef unless defined $str;\n> +\n> +\t$str = to_utf8($str);\n> +\t$str = $cgi->escapeHTML($str);\n\nSame here.\n\n> +\tif ($opts{'-nbsp'}) {\n> +\t\t$str =~ s/ /&nbsp;/g;\n> +\t}\n> +\t$str =~ s|([[:cntrl:]])|quot_cec($1)|eg;\n> +\treturn $str;\n> +}\n\nThose two subroutines use to_utf8(), which in turn uses\n$fallback_encoding.\n\n> +\n> +# Make control characters \"printable\", using character escape codes (CEC)\n> +sub quot_cec {\n[...]\n> +}\n> +\n> +# Alternatively use unicode control pictures codepoints,\n> +# Unicode \"printable representation\" (PR)\n> +sub quot_upr {\n[...]\n> +}\n\n> +# git may return quoted and escaped filenames\n> +sub unquote {\n[...]\n> +}\n\nNote that this subroutine is about neither CGI nor HTML, but about\nunquoting and unescaping output of git commands.  Just FYI.\n\n> +\n> +# escape tabs (convert tabs to spaces)\n> +sub untabify {\n> +\tmy $line = shift;\n> +\n> +\twhile ((my $pos = index($line, \"\\t\")) != -1) {\n> +\t\tif (my $count = (8 - ($pos % 8))) {\n> +\t\t\tmy $spaces = ' ' x $count;\n> +\t\t\t$line =~ s/\\t/$spaces/;\n> +\t\t}\n> +\t}\n> +\n> +\treturn $line;\n> +}\n> +\n> +1;\n\nGood work!\n-- \nJakub Narebski\nPoland\n"}]}