@@ -1230,7 +1230,7 @@ sub href {
1230
1230
$href =~ s ,/$, ,;
1231
1231
1232
1232
# Then add the project name, if present
1233
- $href .= " /" .esc_url ($params {' project' });
1233
+ $href .= " /" .esc_path_info ($params {' project' });
1234
1234
delete $params {' project' };
1235
1235
1236
1236
# since we destructively absorb parameters, we keep this
@@ -1240,7 +1240,8 @@ sub href {
1240
1240
# Summary just uses the project path URL, any other action is
1241
1241
# added to the URL
1242
1242
if (defined $params {' action' }) {
1243
- $href .= " /" .esc_url($params {' action' }) unless $params {' action' } eq ' summary' ;
1243
+ $href .= " /" .esc_path_info($params {' action' })
1244
+ unless $params {' action' } eq ' summary' ;
1244
1245
delete $params {' action' };
1245
1246
}
1246
1247
@@ -1250,33 +1251,33 @@ sub href {
1250
1251
|| $params {' hash_parent' } || $params {' hash' });
1251
1252
if (defined $params {' hash_base' }) {
1252
1253
if (defined $params {' hash_parent_base' }) {
1253
- $href .= esc_url ($params {' hash_parent_base' });
1254
+ $href .= esc_path_info ($params {' hash_parent_base' });
1254
1255
# skip the file_parent if it's the same as the file_name
1255
1256
if (defined $params {' file_parent' }) {
1256
1257
if (defined $params {' file_name' } && $params {' file_parent' } eq $params {' file_name' }) {
1257
1258
delete $params {' file_parent' };
1258
1259
} elsif ($params {' file_parent' } !~ / \.\. / ) {
1259
- $href .= " :/" .esc_url ($params {' file_parent' });
1260
+ $href .= " :/" .esc_path_info ($params {' file_parent' });
1260
1261
delete $params {' file_parent' };
1261
1262
}
1262
1263
}
1263
1264
$href .= " .." ;
1264
1265
delete $params {' hash_parent' };
1265
1266
delete $params {' hash_parent_base' };
1266
1267
} elsif (defined $params {' hash_parent' }) {
1267
- $href .= esc_url ($params {' hash_parent' }). " .." ;
1268
+ $href .= esc_path_info ($params {' hash_parent' }). " .." ;
1268
1269
delete $params {' hash_parent' };
1269
1270
}
1270
1271
1271
- $href .= esc_url ($params {' hash_base' });
1272
+ $href .= esc_path_info ($params {' hash_base' });
1272
1273
if (defined $params {' file_name' } && $params {' file_name' } !~ / \.\. / ) {
1273
- $href .= " :/" .esc_url ($params {' file_name' });
1274
+ $href .= " :/" .esc_path_info ($params {' file_name' });
1274
1275
delete $params {' file_name' };
1275
1276
}
1276
1277
delete $params {' hash' };
1277
1278
delete $params {' hash_base' };
1278
1279
} elsif (defined $params {' hash' }) {
1279
- $href .= esc_url ($params {' hash' });
1280
+ $href .= esc_path_info ($params {' hash' });
1280
1281
delete $params {' hash' };
1281
1282
}
1282
1283
@@ -1309,6 +1310,9 @@ sub href {
1309
1310
}
1310
1311
$href .= " ?" . join (' ;' , @result ) if scalar @result ;
1311
1312
1313
+ # final transformation: trailing spaces must be escaped (URI-encoded)
1314
+ $href =~ s / (\s +)$/ CGI::escape($1 )/ e ;
1315
+
1312
1316
return $href ;
1313
1317
}
1314
1318
@@ -1391,6 +1395,17 @@ sub esc_param {
1391
1395
return $str ;
1392
1396
}
1393
1397
1398
+ # the quoting rules for path_info fragment are slightly different
1399
+ sub esc_path_info {
1400
+ my $str = shift ;
1401
+ return undef unless defined $str ;
1402
+
1403
+ # path_info doesn't treat '+' as space (specially), but '?' must be escaped
1404
+ $str =~ s / ([^A-Za-z0-9\- _.~();\/ ;:@&= +]+)/ CGI::escape($1 )/ eg ;
1405
+
1406
+ return $str ;
1407
+ }
1408
+
1394
1409
# quote unsafe chars in whole URL, so some characters cannot be quoted
1395
1410
sub esc_url {
1396
1411
my $str = shift ;
0 commit comments