@@ -1212,13 +1212,12 @@ impl<'a> Parser<'a> {
1212
1212
| ".%2E" => {
1213
1213
debug_assert ! ( self . serialization. as_bytes( ) [ segment_start - 1 ] == b'/' ) ;
1214
1214
self . serialization . truncate ( segment_start) ;
1215
- // Do not remove the root slash
1216
- if self . serialization . ends_with ( "/" ) && path_start + 1 < segment_start {
1215
+ if self . serialization . ends_with ( "/" )
1216
+ && Parser :: last_slash_can_be_removed ( & self . serialization , path_start)
1217
+ {
1217
1218
self . serialization . pop ( ) ;
1218
- self . shorten_path ( scheme_type, path_start) ;
1219
- } else {
1220
- self . shorten_path ( scheme_type, path_start) ;
1221
1219
}
1220
+ self . shorten_path ( scheme_type, path_start) ;
1222
1221
1223
1222
// and then if neither c is U+002F (/), nor url is special and c is U+005C (\), append the empty string to url’s path.
1224
1223
if ends_with_slash && !self . serialization . ends_with ( "/" ) {
@@ -1263,6 +1262,18 @@ impl<'a> Parser<'a> {
1263
1262
input
1264
1263
}
1265
1264
1265
+ fn last_slash_can_be_removed ( serialization : & String , path_start : usize ) -> bool {
1266
+ let url_before_segment = & serialization[ ..serialization. len ( ) - 1 ] ;
1267
+ if let Some ( segment_before_start) = url_before_segment. rfind ( "/" ) {
1268
+ // Do not remove the root slash
1269
+ segment_before_start >= path_start
1270
+ // Or a windows drive letter slash
1271
+ && !path_starts_with_windows_drive_letter ( & serialization[ segment_before_start..] )
1272
+ } else {
1273
+ false
1274
+ }
1275
+ }
1276
+
1266
1277
/// https://url.spec.whatwg.org/#shorten-a-urls-path
1267
1278
fn shorten_path ( & mut self , scheme_type : SchemeType , path_start : usize ) {
1268
1279
// If path is empty, then return.
@@ -1535,8 +1546,18 @@ fn is_windows_drive_letter(segment: &str) -> bool {
1535
1546
segment. len ( ) == 2 && starts_with_windows_drive_letter ( segment)
1536
1547
}
1537
1548
1549
+ /// Wether path starts with a root slash
1550
+ /// and a windows drive letter eg: "/c:" or "/a:/"
1551
+ fn path_starts_with_windows_drive_letter ( s : & str ) -> bool {
1552
+ s. len ( ) > 3
1553
+ && matches ! ( s. as_bytes( ) [ 0 ] , b'/' | b'\\' | b'?' | b'#' )
1554
+ && starts_with_windows_drive_letter ( & s[ 1 ..] )
1555
+ }
1556
+
1538
1557
fn starts_with_windows_drive_letter ( s : & str ) -> bool {
1539
- ascii_alpha ( s. as_bytes ( ) [ 0 ] as char ) && matches ! ( s. as_bytes( ) [ 1 ] , b':' | b'|' )
1558
+ ascii_alpha ( s. as_bytes ( ) [ 0 ] as char )
1559
+ && matches ! ( s. as_bytes( ) [ 1 ] , b':' | b'|' )
1560
+ && ( s. len ( ) == 2 || matches ! ( s. as_bytes( ) [ 2 ] , b'/' | b'\\' | b'?' | b'#' ) )
1540
1561
}
1541
1562
1542
1563
/// https://url.spec.whatwg.org/#start-with-a-windows-drive-letter
0 commit comments