@@ -638,7 +638,7 @@ impl<'a> Parser<'a> {
638
638
( Some ( i) , _) | ( None , Some ( i) ) => base_url. slice ( ..i) ,
639
639
} ;
640
640
self . serialization . push_str ( before_query) ;
641
- self . pop_path ( SchemeType :: File , base_url. path_start as usize ) ;
641
+ self . shorten_path ( SchemeType :: File , base_url. path_start as usize ) ;
642
642
let remaining = self . parse_path (
643
643
SchemeType :: File ,
644
644
& mut true ,
@@ -1157,15 +1157,15 @@ impl<'a> Parser<'a> {
1157
1157
".." | "%2e%2e" | "%2e%2E" | "%2E%2e" | "%2E%2E" | "%2e." | "%2E." | ".%2e"
1158
1158
| ".%2E" => {
1159
1159
debug_assert ! ( self . serialization. as_bytes( ) [ segment_start - 1 ] == b'/' ) ;
1160
- // We dont want to truncate beyond the path start:
1161
- if segment_start - 1 > path_start {
1162
- self . serialization . truncate ( segment_start - 1 ) ; // Truncate "/.."
1160
+ self . serialization . truncate ( segment_start) ;
1161
+ // Do not remove the root slash
1162
+ if self . serialization . ends_with ( "/" ) && path_start + 1 < segment_start {
1163
+ self . serialization . pop ( ) ;
1164
+ self . shorten_path ( scheme_type, path_start) ;
1163
1165
} else {
1164
- self . serialization . truncate ( segment_start ) ; // Truncate ".."
1166
+ self . shorten_path ( scheme_type , path_start ) ;
1165
1167
}
1166
1168
1167
- self . pop_path ( scheme_type, path_start) ;
1168
-
1169
1169
// 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.
1170
1170
if ends_with_slash && !self . serialization . ends_with ( "/" ) {
1171
1171
self . serialization . push ( '/' ) ;
@@ -1209,16 +1209,36 @@ impl<'a> Parser<'a> {
1209
1209
input
1210
1210
}
1211
1211
1212
+ /// https://url.spec.whatwg.org/#shorten-a-urls-path
1213
+ fn shorten_path ( & mut self , scheme_type : SchemeType , path_start : usize ) {
1214
+ // If path is empty, then return.
1215
+ if self . serialization . len ( ) <= path_start {
1216
+ return ;
1217
+ }
1218
+ // If url’s scheme is "file", path’s size is 1, and path[0] is a normalized Windows drive letter, then return.
1219
+ let segments: Vec < & str > = self . serialization [ path_start..]
1220
+ . split ( '/' )
1221
+ . filter ( |s| !s. is_empty ( ) )
1222
+ . collect ( ) ;
1223
+ if scheme_type. is_file ( )
1224
+ && segments. len ( ) == 1
1225
+ && is_normalized_windows_drive_letter ( segments[ 0 ] )
1226
+ {
1227
+ return ;
1228
+ }
1229
+ // Remove path’s last item.
1230
+ self . pop_path ( scheme_type, path_start) ;
1231
+ }
1232
+
1212
1233
/// https://url.spec.whatwg.org/#pop-a-urls-path
1213
1234
fn pop_path ( & mut self , scheme_type : SchemeType , path_start : usize ) {
1214
1235
if self . serialization . len ( ) > path_start {
1215
1236
let slash_position = self . serialization [ path_start..] . rfind ( '/' ) . unwrap ( ) ;
1216
1237
// + 1 since rfind returns the position before the slash.
1217
1238
let segment_start = path_start + slash_position + 1 ;
1218
1239
// Don’t pop a Windows drive letter
1219
- // FIXME: *normalized* Windows drive letter
1220
1240
if !( scheme_type. is_file ( )
1221
- && is_windows_drive_letter ( & self . serialization [ segment_start..] ) )
1241
+ && is_normalized_windows_drive_letter ( & self . serialization [ segment_start..] ) )
1222
1242
{
1223
1243
self . serialization . truncate ( segment_start) ;
1224
1244
}
0 commit comments