@@ -620,7 +620,7 @@ impl<'a> Parser<'a> {
620
620
( Some ( i) , _) | ( None , Some ( i) ) => base_url. slice ( ..i) ,
621
621
} ;
622
622
self . serialization . push_str ( before_query) ;
623
- self . pop_path ( SchemeType :: File , base_url. path_start as usize ) ;
623
+ self . shorten_path ( SchemeType :: File , base_url. path_start as usize ) ;
624
624
let remaining = self . parse_path (
625
625
SchemeType :: File ,
626
626
& mut true ,
@@ -1139,15 +1139,15 @@ impl<'a> Parser<'a> {
1139
1139
".." | "%2e%2e" | "%2e%2E" | "%2E%2e" | "%2E%2E" | "%2e." | "%2E." | ".%2e"
1140
1140
| ".%2E" => {
1141
1141
debug_assert ! ( self . serialization. as_bytes( ) [ segment_start - 1 ] == b'/' ) ;
1142
- // We dont want to truncate beyond the path start:
1143
- if segment_start - 1 > path_start {
1144
- self . serialization . truncate ( segment_start - 1 ) ; // Truncate "/.."
1142
+ self . serialization . truncate ( segment_start) ;
1143
+ // Do not remove the root slash
1144
+ if self . serialization . ends_with ( "/" ) && path_start + 1 < segment_start {
1145
+ self . serialization . pop ( ) ;
1146
+ self . shorten_path ( scheme_type, path_start) ;
1145
1147
} else {
1146
- self . serialization . truncate ( segment_start ) ; // Truncate ".."
1148
+ self . shorten_path ( scheme_type , path_start ) ;
1147
1149
}
1148
1150
1149
- self . pop_path ( scheme_type, path_start) ;
1150
-
1151
1151
// 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.
1152
1152
if ends_with_slash && !self . serialization . ends_with ( "/" ) {
1153
1153
self . serialization . push ( '/' ) ;
@@ -1191,16 +1191,36 @@ impl<'a> Parser<'a> {
1191
1191
input
1192
1192
}
1193
1193
1194
+ /// https://url.spec.whatwg.org/#shorten-a-urls-path
1195
+ fn shorten_path ( & mut self , scheme_type : SchemeType , path_start : usize ) {
1196
+ // If path is empty, then return.
1197
+ if self . serialization . len ( ) <= path_start {
1198
+ return ;
1199
+ }
1200
+ // If url’s scheme is "file", path’s size is 1, and path[0] is a normalized Windows drive letter, then return.
1201
+ let segments: Vec < & str > = self . serialization [ path_start..]
1202
+ . split ( '/' )
1203
+ . filter ( |s| !s. is_empty ( ) )
1204
+ . collect ( ) ;
1205
+ if scheme_type. is_file ( )
1206
+ && segments. len ( ) == 1
1207
+ && is_normalized_windows_drive_letter ( segments[ 0 ] )
1208
+ {
1209
+ return ;
1210
+ }
1211
+ // Remove path’s last item.
1212
+ self . pop_path ( scheme_type, path_start) ;
1213
+ }
1214
+
1194
1215
/// https://url.spec.whatwg.org/#pop-a-urls-path
1195
1216
fn pop_path ( & mut self , scheme_type : SchemeType , path_start : usize ) {
1196
1217
if self . serialization . len ( ) > path_start {
1197
1218
let slash_position = self . serialization [ path_start..] . rfind ( '/' ) . unwrap ( ) ;
1198
1219
// + 1 since rfind returns the position before the slash.
1199
1220
let segment_start = path_start + slash_position + 1 ;
1200
1221
// Don’t pop a Windows drive letter
1201
- // FIXME: *normalized* Windows drive letter
1202
1222
if !( scheme_type. is_file ( )
1203
- && is_windows_drive_letter ( & self . serialization [ segment_start..] ) )
1223
+ && is_normalized_windows_drive_letter ( & self . serialization [ segment_start..] ) )
1204
1224
{
1205
1225
self . serialization . truncate ( segment_start) ;
1206
1226
}
0 commit comments