@@ -1212,13 +1212,12 @@ impl<'a> Parser<'a> {
12121212 | ".%2E" => {
12131213 debug_assert ! ( self . serialization. as_bytes( ) [ segment_start - 1 ] == b'/' ) ;
12141214 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+ {
12171218 self . serialization . pop ( ) ;
1218- self . shorten_path ( scheme_type, path_start) ;
1219- } else {
1220- self . shorten_path ( scheme_type, path_start) ;
12211219 }
1220+ self . shorten_path ( scheme_type, path_start) ;
12221221
12231222 // 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.
12241223 if ends_with_slash && !self . serialization . ends_with ( "/" ) {
@@ -1263,6 +1262,18 @@ impl<'a> Parser<'a> {
12631262 input
12641263 }
12651264
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+
12661277 /// https://url.spec.whatwg.org/#shorten-a-urls-path
12671278 fn shorten_path ( & mut self , scheme_type : SchemeType , path_start : usize ) {
12681279 // If path is empty, then return.
@@ -1535,8 +1546,18 @@ fn is_windows_drive_letter(segment: &str) -> bool {
15351546 segment. len ( ) == 2 && starts_with_windows_drive_letter ( segment)
15361547}
15371548
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+
15381557fn 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'#' ) )
15401561}
15411562
15421563/// https://url.spec.whatwg.org/#start-with-a-windows-drive-letter
0 commit comments