Skip to content

Commit 67976c6

Browse files
jnarebgitster
authored andcommitted
gitweb: Fix handling of whitespace in generated links
When creating path_info part of link, don't encode space as '+', because while $cgi->param('foo') translates '+' in query param to ' ', neither $ENV{'PATH_INFO'} nor $cgi->path_info() do. This fixes the issue with pathnames with embedded whitespace and $feature{'pathinfo'} / path_info links. It is done by using newly introduced esc_path_info() instead of esc_url() in href() subroutine. Also while links are more clear not escaping space (' ') characters in generated links, the trailing space must be URI-encoded, otherwise would get discarded. Issue noticed thanks to John 'Warthog9' Hawley. Signed-off-by: Jakub Narebski <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c6d059b commit 67976c6

File tree

1 file changed

+23
-8
lines changed

1 file changed

+23
-8
lines changed

gitweb/gitweb.perl

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,7 +1186,7 @@ sub href {
11861186
$href =~ s,/$,,;
11871187

11881188
# Then add the project name, if present
1189-
$href .= "/".esc_url($params{'project'});
1189+
$href .= "/".esc_path_info($params{'project'});
11901190
delete $params{'project'};
11911191

11921192
# since we destructively absorb parameters, we keep this
@@ -1196,7 +1196,8 @@ sub href {
11961196
# Summary just uses the project path URL, any other action is
11971197
# added to the URL
11981198
if (defined $params{'action'}) {
1199-
$href .= "/".esc_url($params{'action'}) unless $params{'action'} eq 'summary';
1199+
$href .= "/".esc_path_info($params{'action'})
1200+
unless $params{'action'} eq 'summary';
12001201
delete $params{'action'};
12011202
}
12021203

@@ -1206,33 +1207,33 @@ sub href {
12061207
|| $params{'hash_parent'} || $params{'hash'});
12071208
if (defined $params{'hash_base'}) {
12081209
if (defined $params{'hash_parent_base'}) {
1209-
$href .= esc_url($params{'hash_parent_base'});
1210+
$href .= esc_path_info($params{'hash_parent_base'});
12101211
# skip the file_parent if it's the same as the file_name
12111212
if (defined $params{'file_parent'}) {
12121213
if (defined $params{'file_name'} && $params{'file_parent'} eq $params{'file_name'}) {
12131214
delete $params{'file_parent'};
12141215
} elsif ($params{'file_parent'} !~ /\.\./) {
1215-
$href .= ":/".esc_url($params{'file_parent'});
1216+
$href .= ":/".esc_path_info($params{'file_parent'});
12161217
delete $params{'file_parent'};
12171218
}
12181219
}
12191220
$href .= "..";
12201221
delete $params{'hash_parent'};
12211222
delete $params{'hash_parent_base'};
12221223
} elsif (defined $params{'hash_parent'}) {
1223-
$href .= esc_url($params{'hash_parent'}). "..";
1224+
$href .= esc_path_info($params{'hash_parent'}). "..";
12241225
delete $params{'hash_parent'};
12251226
}
12261227

1227-
$href .= esc_url($params{'hash_base'});
1228+
$href .= esc_path_info($params{'hash_base'});
12281229
if (defined $params{'file_name'} && $params{'file_name'} !~ /\.\./) {
1229-
$href .= ":/".esc_url($params{'file_name'});
1230+
$href .= ":/".esc_path_info($params{'file_name'});
12301231
delete $params{'file_name'};
12311232
}
12321233
delete $params{'hash'};
12331234
delete $params{'hash_base'};
12341235
} elsif (defined $params{'hash'}) {
1235-
$href .= esc_url($params{'hash'});
1236+
$href .= esc_path_info($params{'hash'});
12361237
delete $params{'hash'};
12371238
}
12381239

@@ -1265,6 +1266,9 @@ sub href {
12651266
}
12661267
$href .= "?" . join(';', @result) if scalar @result;
12671268

1269+
# final transformation: trailing spaces must be escaped (URI-encoded)
1270+
$href =~ s/(\s+)$/CGI::escape($1)/e;
1271+
12681272
return $href;
12691273
}
12701274

@@ -1347,6 +1351,17 @@ sub esc_param {
13471351
return $str;
13481352
}
13491353

1354+
# the quoting rules for path_info fragment are slightly different
1355+
sub esc_path_info {
1356+
my $str = shift;
1357+
return undef unless defined $str;
1358+
1359+
# path_info doesn't treat '+' as space (specially), but '?' must be escaped
1360+
$str =~ s/([^A-Za-z0-9\-_.~();\/;:@&= +]+)/CGI::escape($1)/eg;
1361+
1362+
return $str;
1363+
}
1364+
13501365
# quote unsafe chars in whole URL, so some characters cannot be quoted
13511366
sub esc_url {
13521367
my $str = shift;

0 commit comments

Comments
 (0)