@@ -1186,7 +1186,7 @@ sub href {
1186
1186
$href =~ s ,/$, ,;
1187
1187
1188
1188
# Then add the project name, if present
1189
- $href .= " /" .esc_url ($params {' project' });
1189
+ $href .= " /" .esc_path_info ($params {' project' });
1190
1190
delete $params {' project' };
1191
1191
1192
1192
# since we destructively absorb parameters, we keep this
@@ -1196,7 +1196,8 @@ sub href {
1196
1196
# Summary just uses the project path URL, any other action is
1197
1197
# added to the URL
1198
1198
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' ;
1200
1201
delete $params {' action' };
1201
1202
}
1202
1203
@@ -1206,33 +1207,33 @@ sub href {
1206
1207
|| $params {' hash_parent' } || $params {' hash' });
1207
1208
if (defined $params {' hash_base' }) {
1208
1209
if (defined $params {' hash_parent_base' }) {
1209
- $href .= esc_url ($params {' hash_parent_base' });
1210
+ $href .= esc_path_info ($params {' hash_parent_base' });
1210
1211
# skip the file_parent if it's the same as the file_name
1211
1212
if (defined $params {' file_parent' }) {
1212
1213
if (defined $params {' file_name' } && $params {' file_parent' } eq $params {' file_name' }) {
1213
1214
delete $params {' file_parent' };
1214
1215
} elsif ($params {' file_parent' } !~ / \.\. / ) {
1215
- $href .= " :/" .esc_url ($params {' file_parent' });
1216
+ $href .= " :/" .esc_path_info ($params {' file_parent' });
1216
1217
delete $params {' file_parent' };
1217
1218
}
1218
1219
}
1219
1220
$href .= " .." ;
1220
1221
delete $params {' hash_parent' };
1221
1222
delete $params {' hash_parent_base' };
1222
1223
} elsif (defined $params {' hash_parent' }) {
1223
- $href .= esc_url ($params {' hash_parent' }). " .." ;
1224
+ $href .= esc_path_info ($params {' hash_parent' }). " .." ;
1224
1225
delete $params {' hash_parent' };
1225
1226
}
1226
1227
1227
- $href .= esc_url ($params {' hash_base' });
1228
+ $href .= esc_path_info ($params {' hash_base' });
1228
1229
if (defined $params {' file_name' } && $params {' file_name' } !~ / \.\. / ) {
1229
- $href .= " :/" .esc_url ($params {' file_name' });
1230
+ $href .= " :/" .esc_path_info ($params {' file_name' });
1230
1231
delete $params {' file_name' };
1231
1232
}
1232
1233
delete $params {' hash' };
1233
1234
delete $params {' hash_base' };
1234
1235
} elsif (defined $params {' hash' }) {
1235
- $href .= esc_url ($params {' hash' });
1236
+ $href .= esc_path_info ($params {' hash' });
1236
1237
delete $params {' hash' };
1237
1238
}
1238
1239
@@ -1265,6 +1266,9 @@ sub href {
1265
1266
}
1266
1267
$href .= " ?" . join (' ;' , @result ) if scalar @result ;
1267
1268
1269
+ # final transformation: trailing spaces must be escaped (URI-encoded)
1270
+ $href =~ s / (\s +)$/ CGI::escape($1 )/ e ;
1271
+
1268
1272
return $href ;
1269
1273
}
1270
1274
@@ -1347,6 +1351,17 @@ sub esc_param {
1347
1351
return $str ;
1348
1352
}
1349
1353
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
+
1350
1365
# quote unsafe chars in whole URL, so some characters cannot be quoted
1351
1366
sub esc_url {
1352
1367
my $str = shift ;
0 commit comments