@@ -2720,7 +2720,26 @@ impl Url {
2720
2720
_ => return Err ( ( ) ) ,
2721
2721
} ;
2722
2722
2723
- return file_url_segments_to_pathbuf ( host, segments) ;
2723
+ let str_len = self . as_str ( ) . len ( ) ;
2724
+ let estimated_capacity = if cfg ! ( target_os = "redox" ) {
2725
+ let scheme_len = self . scheme ( ) . len ( ) ;
2726
+ let file_scheme_len = "file" . len ( ) ;
2727
+ // remove only // because it still has file:
2728
+ if scheme_len < file_scheme_len {
2729
+ let scheme_diff = file_scheme_len - scheme_len;
2730
+ ( str_len + scheme_diff) . saturating_sub ( 2 )
2731
+ } else {
2732
+ let scheme_diff = scheme_len - file_scheme_len;
2733
+ str_len. saturating_sub ( scheme_diff + 2 )
2734
+ }
2735
+ } else if cfg ! ( windows) {
2736
+ // remove scheme: - has posssible \\ for hostname
2737
+ str_len. saturating_sub ( self . scheme ( ) . len ( ) + 1 )
2738
+ } else {
2739
+ // remove scheme://
2740
+ str_len. saturating_sub ( self . scheme ( ) . len ( ) + 3 )
2741
+ } ;
2742
+ return file_url_segments_to_pathbuf ( estimated_capacity, host, segments) ;
2724
2743
}
2725
2744
Err ( ( ) )
2726
2745
}
@@ -3030,6 +3049,7 @@ fn path_to_file_url_segments_windows(
3030
3049
any( unix, target_os = "redox" , target_os = "wasi" , target_os = "hermit" )
3031
3050
) ) ]
3032
3051
fn file_url_segments_to_pathbuf (
3052
+ estimated_capacity : usize ,
3033
3053
host : Option < & str > ,
3034
3054
segments : str:: Split < ' _ , char > ,
3035
3055
) -> Result < PathBuf , ( ) > {
@@ -3047,11 +3067,11 @@ fn file_url_segments_to_pathbuf(
3047
3067
return Err ( ( ) ) ;
3048
3068
}
3049
3069
3050
- let mut bytes = if cfg ! ( target_os = "redox" ) {
3051
- b"file:" . to_vec ( )
3052
- } else {
3053
- Vec :: new ( )
3054
- } ;
3070
+ let mut bytes = Vec :: new ( ) ;
3071
+ bytes . try_reserve ( estimated_capacity ) . map_err ( |_| ( ) ) ? ;
3072
+ if cfg ! ( target_os = "redox" ) {
3073
+ bytes . extend ( b"file:" ) ;
3074
+ }
3055
3075
3056
3076
for segment in segments {
3057
3077
bytes. push ( b'/' ) ;
@@ -3083,22 +3103,27 @@ fn file_url_segments_to_pathbuf(
3083
3103
3084
3104
#[ cfg( all( feature = "std" , windows) ) ]
3085
3105
fn file_url_segments_to_pathbuf (
3106
+ estimated_capacity : usize ,
3086
3107
host : Option < & str > ,
3087
3108
segments : str:: Split < char > ,
3088
3109
) -> Result < PathBuf , ( ) > {
3089
- file_url_segments_to_pathbuf_windows ( host, segments)
3110
+ file_url_segments_to_pathbuf_windows ( estimated_capacity , host, segments)
3090
3111
}
3091
3112
3092
3113
// Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102
3093
3114
#[ cfg( feature = "std" ) ]
3094
3115
#[ cfg_attr( not( windows) , allow( dead_code) ) ]
3095
3116
fn file_url_segments_to_pathbuf_windows (
3117
+ estimated_capacity : usize ,
3096
3118
host : Option < & str > ,
3097
3119
mut segments : str:: Split < ' _ , char > ,
3098
3120
) -> Result < PathBuf , ( ) > {
3099
- use percent_encoding:: percent_decode;
3100
- let mut string = if let Some ( host) = host {
3101
- r"\\" . to_owned ( ) + host
3121
+ use percent_encoding:: percent_decode_str;
3122
+ let mut string = String :: new ( ) ;
3123
+ string. try_reserve ( estimated_capacity) . map_err ( |_| ( ) ) ?;
3124
+ if let Some ( host) = host {
3125
+ string. push_str ( r"\\" ) ;
3126
+ string. push_str ( host) ;
3102
3127
} else {
3103
3128
let first = segments. next ( ) . ok_or ( ( ) ) ?;
3104
3129
@@ -3108,7 +3133,7 @@ fn file_url_segments_to_pathbuf_windows(
3108
3133
return Err ( ( ) ) ;
3109
3134
}
3110
3135
3111
- first . to_owned ( )
3136
+ string . push_str ( first ) ;
3112
3137
}
3113
3138
3114
3139
4 => {
@@ -3120,7 +3145,8 @@ fn file_url_segments_to_pathbuf_windows(
3120
3145
return Err ( ( ) ) ;
3121
3146
}
3122
3147
3123
- first[ 0 ..1 ] . to_owned ( ) + ":"
3148
+ string. push_str ( & first[ 0 ..1 ] ) ;
3149
+ string. push ( ':' ) ;
3124
3150
}
3125
3151
3126
3152
_ => return Err ( ( ) ) ,
@@ -3131,11 +3157,20 @@ fn file_url_segments_to_pathbuf_windows(
3131
3157
string. push ( '\\' ) ;
3132
3158
3133
3159
// Currently non-unicode windows paths cannot be represented
3134
- match String :: from_utf8 ( percent_decode ( segment. as_bytes ( ) ) . collect ( ) ) {
3160
+ match percent_decode_str ( segment) . decode_utf8 ( ) {
3135
3161
Ok ( s) => string. push_str ( & s) ,
3136
3162
Err ( ..) => return Err ( ( ) ) ,
3137
3163
}
3138
3164
}
3165
+ // ensure our estimated capacity was good
3166
+ if cfg ! ( test) {
3167
+ debug_assert ! (
3168
+ string. len( ) <= estimated_capacity,
3169
+ "len: {}, capacity: {}" ,
3170
+ string. len( ) ,
3171
+ estimated_capacity
3172
+ ) ;
3173
+ }
3139
3174
let path = PathBuf :: from ( string) ;
3140
3175
debug_assert ! (
3141
3176
path. is_absolute( ) ,
0 commit comments