@@ -1230,13 +1230,12 @@ impl<'a> Parser<'a> {
1230
1230
| ".%2E" => {
1231
1231
debug_assert ! ( self . serialization. as_bytes( ) [ segment_start - 1 ] == b'/' ) ;
1232
1232
self . serialization . truncate ( segment_start) ;
1233
- // Do not remove the root slash
1234
- if self . serialization . ends_with ( "/" ) && path_start + 1 < segment_start {
1233
+ if self . serialization . ends_with ( "/" )
1234
+ && Parser :: last_slash_can_be_removed ( & self . serialization , path_start)
1235
+ {
1235
1236
self . serialization . pop ( ) ;
1236
- self . shorten_path ( scheme_type, path_start) ;
1237
- } else {
1238
- self . shorten_path ( scheme_type, path_start) ;
1239
1237
}
1238
+ self . shorten_path ( scheme_type, path_start) ;
1240
1239
1241
1240
// 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.
1242
1241
if ends_with_slash && !self . serialization . ends_with ( "/" ) {
@@ -1281,6 +1280,18 @@ impl<'a> Parser<'a> {
1281
1280
input
1282
1281
}
1283
1282
1283
+ fn last_slash_can_be_removed ( serialization : & String , path_start : usize ) -> bool {
1284
+ let url_before_segment = & serialization[ ..serialization. len ( ) - 1 ] ;
1285
+ if let Some ( segment_before_start) = url_before_segment. rfind ( "/" ) {
1286
+ // Do not remove the root slash
1287
+ segment_before_start >= path_start
1288
+ // Or a windows drive letter slash
1289
+ && !path_starts_with_windows_drive_letter ( & serialization[ segment_before_start..] )
1290
+ } else {
1291
+ false
1292
+ }
1293
+ }
1294
+
1284
1295
/// https://url.spec.whatwg.org/#shorten-a-urls-path
1285
1296
fn shorten_path ( & mut self , scheme_type : SchemeType , path_start : usize ) {
1286
1297
// If path is empty, then return.
@@ -1553,8 +1564,18 @@ fn is_windows_drive_letter(segment: &str) -> bool {
1553
1564
segment. len ( ) == 2 && starts_with_windows_drive_letter ( segment)
1554
1565
}
1555
1566
1567
+ /// Wether path starts with a root slash
1568
+ /// and a windows drive letter eg: "/c:" or "/a:/"
1569
+ fn path_starts_with_windows_drive_letter ( s : & str ) -> bool {
1570
+ s. len ( ) > 3
1571
+ && matches ! ( s. as_bytes( ) [ 0 ] , b'/' | b'\\' | b'?' | b'#' )
1572
+ && starts_with_windows_drive_letter ( & s[ 1 ..] )
1573
+ }
1574
+
1556
1575
fn starts_with_windows_drive_letter ( s : & str ) -> bool {
1557
- ascii_alpha ( s. as_bytes ( ) [ 0 ] as char ) && matches ! ( s. as_bytes( ) [ 1 ] , b':' | b'|' )
1576
+ ascii_alpha ( s. as_bytes ( ) [ 0 ] as char )
1577
+ && matches ! ( s. as_bytes( ) [ 1 ] , b':' | b'|' )
1578
+ && ( s. len ( ) == 2 || matches ! ( s. as_bytes( ) [ 2 ] , b'/' | b'\\' | b'?' | b'#' ) )
1558
1579
}
1559
1580
1560
1581
/// https://url.spec.whatwg.org/#start-with-a-windows-drive-letter
0 commit comments