1# Upgrade guide 2 3This guide contains steps for upgrading crates in this project between major 4versions. 5 6## Upgrading from url 1.x to 2.1+ 7 8* The minimum supported Rust version is now v1.33.0. Verify that you can bump 9 your library or application to the same MSRV. 10 11* `Url` no longer implements `std::net::ToSocketAddrs`. You will instead need to 12 explicitly call `socket_addrs` to convert your `Url` to a type that implements 13 `ToSocketAddrs`. 14 15 Note that v2.0 removed support for `std::net::ToSocketAddrs` with no 16 replacement; the `socket_addrs` method was not added until v2.1. 17 18 Before upgrading: 19 20 ```rust 21 let url = Url::parse("http://github.com:80").unwrap(); 22 let stream = TcpStream::connect(url).unwrap(); 23 ``` 24 25 After upgrading: 26 27 ```rust 28 let url = Url::parse("http://github.com:80").unwrap(); 29 let addrs = url.socket_addrs(|| None).unwrap(); 30 let stream = TcpStream::connect(addrs).unwrap(); 31 ``` 32 33 Before upgrading: 34 35 ```rust 36 let url = Url::parse("socks5://localhost").unwrap(); 37 let stream = TcpStream::connect(url.with_default_port(|url| match url.scheme() { 38 "socks5" => Ok(1080), 39 _ => Err(()), 40 })).unwrap(); 41 ``` 42 43 After upgrading: 44 45 ```rust 46 let url = Url::parse("http://github.com:80").unwrap(); 47 let stream = TcpStream::connect(url.socket_addrs(|| match url.scheme() { 48 "socks5" => Some(1080), 49 _ => Err(()), 50 })).unwrap(); 51 ``` 52 53* `url_serde` is no longer required to use `Url` with Serde 1.x. Remove 54 references to `url_serde` and enable the `serde` feature instead. 55 56 ```toml 57 # Cargo.toml 58 [dependencies] 59 url = { version = "2.0", features = ["serde"] } 60 ``` 61 62* The `idna` and `percent_export` crates are no longer exported by the `url` 63 crate. Depend on those crates directly instead. See below for additional 64 breaking changes in the percent-export package. 65 66 Before upgrading: 67 68 ```rust 69 use url::percent_encoding::percent_decode; 70 ``` 71 72 After upgrading: 73 74 ```rust 75 use percent_encoding::percent_decode; 76 ``` 77 78## Upgrading from percent-encoding 1.x to 2.x 79 80* Prepackaged encoding sets, like `QUERY_ENCODE_SET` and 81 `PATH_SEGMENT_ENCODE_SET`, are no longer provided. You 82 will need to read the specifications relevant to your domain and construct 83 your own encoding sets by using the `percent_encoding::AsciiSet` builder 84 methods on either of the base encoding sets, `percent_encoding::CONTROLS` or 85 `percent_encoding::NON_ALPHANUMERIC`. 86 87 Before upgrading: 88 89 ```rust 90 use percent_encoding::QUERY_ENCODE_SET; 91 92 percent_encoding::utf8_percent_encode(value, QUERY_ENCODE_SET); 93 ``` 94 95 After upgrading: 96 97 ```rust 98 /// https://url.spec.whatwg.org/#query-state 99 const QUERY: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'#').add(b'<').add(b'>'); 100 101 percent_encoding::utf8_percent_encode(value, QUERY); 102 ``` 103 104 105## Upgrading from url 0.x to 1.x 106 107* The fields of `Url` are now private because the `Url` constructor, parser, 108 and setters maintain invariants that could be violated if you were to set the fields directly. 109 Instead of accessing, for example, `url.scheme`, use the getter method, such as `url.scheme()`. 110 Instead of assigning directly to a field, for example `url.scheme = "https".to_string()`, 111 use the setter method, such as `url.set_scheme("https").unwrap()`. 112 (Some setters validate the new value and return a `Result` that must be used). 113 114* The methods of `Url` now return `&str` instead of `String`, 115 thus reducing allocations and making serialization cheap. 116 117* The `path()` method on `url::Url` instances used to return `Option<&[String]>`; 118 now it returns `&str`. 119 If you would like functionality more similar to the old behavior of `path()`, 120 use `path_segments()` that returns `Option<str::Split<char>>`. 121 122 Before upgrading: 123 124 ```rust 125 let issue_list_url = Url::parse( 126 "https://github.com/rust-lang/rust/issues?labels=E-easy&state=open" 127 ).unwrap(); 128 assert_eq!(issue_list_url.path(), Some(&["rust-lang".to_string(), 129 "rust".to_string(), 130 "issues".to_string()][..])); 131 ``` 132 133 After upgrading: 134 135 ```rust 136 let issue_list_url = Url::parse( 137 "https://github.com/rust-lang/rust/issues?labels=E-easy&state=open" 138 ).unwrap(); 139 assert_eq!(issue_list_url.path(), "/rust-lang/rust/issues"); 140 assert_eq!(issue_list_url.path_segments().map(|c| c.collect::<Vec<_>>()), 141 Some(vec!["rust-lang", "rust", "issues"])); 142 ``` 143 144* The `path_mut()` method on `url::Url` instances that allowed modification of a URL's path 145 has been replaced by `path_segments_mut()`. 146 147 Before upgrading: 148 149 ```rust 150 let mut url = Url::parse("https://github.com/rust-lang/rust").unwrap(); 151 url.path_mut().unwrap().push("issues"); 152 ``` 153 154 After upgrading: 155 156 ```rust 157 let mut url = Url::parse("https://github.com/rust-lang/rust").unwrap(); 158 url.path_segments_mut().unwrap().push("issues"); 159 ``` 160 161* The `domain_mut()` method on `url::Url` instances that allowed modification of a URL's domain 162 has been replaced by `set_host()` and `set_ip_host()`. 163 164* The `host()` method on `url::Url` instances used to return `Option<&Host>`; 165 now it returns `Option<Host<&str>>`. 166 The `serialize_host()` method that returned `Option<String>` 167 has been replaced by the `host_str()` method that returns `Option<&str>`. 168 169* The `serialize()` method on `url::Url` instances that returned `String` 170 has been replaced by an `as_str()` method that returns `&str`. 171 172 Before upgrading: 173 174 ```rust 175 let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap(); 176 assert_eq!(this_document.serialize(), "http://servo.github.io/rust-url/url/index.html".to_string()); 177 ``` 178 179 After upgrading: 180 181 ```rust 182 let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap(); 183 assert_eq!(this_document.as_str(), "http://servo.github.io/rust-url/url/index.html"); 184 ``` 185 186* `url::UrlParser` has been replaced by `url::Url::parse()` and `url::Url::join()`. 187 188 Before upgrading: 189 190 ```rust 191 let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap(); 192 let css_url = UrlParser::new().base_url(&this_document).parse("../main.css").unwrap(); 193 assert_eq!(css_url.serialize(), "http://servo.github.io/rust-url/main.css".to_string()); 194 ``` 195 196 After upgrading: 197 198 ```rust 199 let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap(); 200 let css_url = this_document.join("../main.css").unwrap(); 201 assert_eq!(css_url.as_str(), "http://servo.github.io/rust-url/main.css"); 202 ``` 203 204* `url::parse_path()` and `url::UrlParser::parse_path()` have been removed without replacement. 205 As a workaround, you can give a base URL that you then ignore too `url::Url::parse()`. 206 207 Before upgrading: 208 209 ```rust 210 let (path, query, fragment) = url::parse_path("/foo/bar/../baz?q=42").unwrap(); 211 assert_eq!(path, vec!["foo".to_string(), "baz".to_string()]); 212 assert_eq!(query, Some("q=42".to_string())); 213 assert_eq!(fragment, None); 214 ``` 215 216 After upgrading: 217 218 ```rust 219 let base = Url::parse("http://example.com").unwrap(); 220 let with_path = base.join("/foo/bar/../baz?q=42").unwrap(); 221 assert_eq!(with_path.path(), "/foo/baz"); 222 assert_eq!(with_path.query(), Some("q=42")); 223 assert_eq!(with_path.fragment(), None); 224 ``` 225 226* The `url::form_urlencoded::serialize()` method 227 has been replaced with the `url::form_urlencoded::Serializer` struct. 228 Instead of calling `serialize()` with key/value pairs, 229 create a new `Serializer` with a new string, 230 call the `extend_pairs()` method on the `Serializer` instance with the key/value pairs as the argument, 231 then call `finish()`. 232 233 Before upgrading: 234 235 ```rust 236 let form = url::form_urlencoded::serialize(form.iter().map(|(k, v)| { 237 (&k[..], &v[..]) 238 })); 239 ``` 240 241 After upgrading: 242 243 ```rust 244 let form = url::form_urlencoded::Serializer::new(String::new()).extend_pairs( 245 form.iter().map(|(k, v)| { (&k[..], &v[..]) }) 246 ).finish(); 247 ``` 248 249* The `set_query_from_pairs()` method on `url::Url` instances that took key/value pairs 250 has been replaced with `query_pairs_mut()`, which allows you to modify the `url::Url`'s query pairs. 251 252 Before upgrading: 253 254 ```rust 255 let mut url = Url::parse("https://duckduckgo.com/").unwrap(); 256 let pairs = vec![ 257 ("q", "test"), 258 ("ia", "images"), 259 ]; 260 url.set_query_from_pairs(pairs.iter().map(|&(k, v)| { 261 (&k[..], &v[..]) 262 })); 263 ``` 264 265 After upgrading: 266 267 ```rust 268 let mut url = Url::parse("https://duckduckgo.com/").unwrap(); 269 let pairs = vec![ 270 ("q", "test"), 271 ("ia", "images"), 272 ]; 273 url.query_pairs_mut().clear().extend_pairs( 274 pairs.iter().map(|&(k, v)| { (&k[..], &v[..]) }) 275 ); 276 ``` 277 278* `url::SchemeData`, its variants `Relative` and `NonRelative`, 279 and the struct `url::RelativeSchemeData` have been removed. 280 Instead of matching on these variants 281 to determine if you have a URL in a relative scheme such as HTTP 282 versus a URL in a non-relative scheme as data, 283 use the `cannot_be_a_base()` method to determine which kind you have. 284 285 Before upgrading: 286 287 ```rust 288 match url.scheme_data { 289 url::SchemeData::Relative(..) => {} 290 url::SchemeData::NonRelative(..) => { 291 return Err(human(format!("`{}` must have relative scheme \ 292 data: {}", field, url))) 293 } 294 } 295 ``` 296 297 After upgrading: 298 299 ```rust 300 if url.cannot_be_a_base() { 301 return Err(human(format!("`{}` must have relative scheme \ 302 data: {}", field, url))) 303 } 304 ``` 305 306* The functions `url::whatwg_scheme_type_mapper()`, the `SchemeType` enum, 307 and the `scheme_type_mapper()` method on `url::UrlParser` instances have been removed. 308 `SchemeType` had a method for getting the `default_port()`; 309 to replicate this functionality, use the method `port_or_known_default()` on `url::Url` instances. 310 The `port_or_default()` method on `url::Url` instances has been removed; 311 use `port_or_known_default()` instead. 312 313 Before upgrading: 314 315 ```rust 316 let port = match whatwg_scheme_type_mapper(&url.scheme) { 317 SchemeType::Relative(port) => port, 318 _ => return Err(format!("Invalid special scheme: `{}`", 319 raw_url.scheme)), 320 }; 321 ``` 322 323 After upgrading: 324 325 ```rust 326 let port = match url.port_or_known_default() { 327 Some(port) => port, 328 _ => return Err(format!("Invalid special scheme: `{}`", 329 url.scheme())), 330 }; 331 ``` 332 333* The following formatting utilities have been removed without replacement; 334 look at their linked previous implementations 335 if you would like to replicate the functionality in your code: 336 * [`url::format::PathFormatter`](https://github.com/servo/rust-url/pull/176/commits/9e759f18726c8e1343162922b87163d4dd08fe3c#diff-0bb16ac13b75e9b568fa4aff61b0e71dL24) 337 * [`url::format::UserInfoFormatter`](https://github.com/servo/rust-url/pull/176/commits/9e759f18726c8e1343162922b87163d4dd08fe3c#diff-0bb16ac13b75e9b568fa4aff61b0e71dL50) 338 * [`url::format::UrlNoFragmentFormatter`](https://github.com/servo/rust-url/pull/176/commits/9e759f18726c8e1343162922b87163d4dd08fe3c#diff-0bb16ac13b75e9b568fa4aff61b0e71dL70) 339 340* `url::percent_encoding::percent_decode()` used to have a return type of `Vec<u8>`; 341 now it returns an iterator of decoded `u8` bytes that also implements `Into<Cow<u8>>`. 342 Use `.into().to_owned()` to obtain a `Vec<u8>`. 343 (`.collect()` also works but might not be as efficient.) 344 345* The `url::percent_encoding::EncodeSet` struct and constant instances 346 used with `url::percent_encoding::percent_encode()` 347 have been changed to structs that implement the trait `url::percent_encoding::EncodeSet`. 348 * `SIMPLE_ENCODE_SET`, `QUERY_ENCODE_SET`, `DEFAULT_ENCODE_SET`, 349 and `USERINFO_ENCODE_SET` have the same behavior. 350 * `USERNAME_ENCODE_SET` and `PASSWORD_ENCODE_SET` have been removed; 351 use `USERINFO_ENCODE_SET` instead. 352 * `HTTP_VALUE_ENCODE_SET` has been removed; 353 an implementation of it in the new types can be found [in hyper's source]( 354 https://github.com/hyperium/hyper/blob/67436c5bf615cf5a55a71e32b788afef5985570e/src/header/parsing.rs#L131-L138) 355 if you need to replicate this functionality in your code. 356 * `FORM_URLENCODED_ENCODE_SET` has been removed; 357 instead, use the functionality in `url::form_urlencoded`. 358 * `PATH_SEGMENT_ENCODE_SET` has been added for use on '/'-separated path segments. 359 360* `url::percent_encoding::percent_decode_to()` has been removed. 361 Use `url::percent_encoding::percent_decode()` which returns an iterator. 362 You can then use the iterator’s `collect()` method 363 or give it to some data structure’s `extend()` method. 364* A number of `ParseError` variants have changed. 365 [See the documentation for the current set](http://servo.github.io/rust-url/url/enum.ParseError.html). 366* `url::OpaqueOrigin::new()` and `url::Origin::UID(OpaqueOrigin)` 367 have been replaced by `url::Origin::new_opaque()` and `url::Origin::Opaque(OpaqueOrigin)`, respectively. 368