### Replace whatwg_scheme_type_mapper with port_or_known_default Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md The `whatwg_scheme_type_mapper` function and `SchemeType` enum have been removed. Use `port_or_known_default()` on `url::Url` instances to get the default port. ```rust let port = match whatwg_scheme_type_mapper(&url.scheme) { SchemeType::Relative(port) => port, _ => return Err(format!("Invalid special scheme: `{}`", raw_url.scheme)), }; ``` ```rust let port = match url.port_or_known_default() { Some(port) => port, _ => return Err(format!("Invalid special scheme: `{}`", url.scheme())), }; ``` -------------------------------- ### Handle percent_decode return type change Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md `url::percent_encoding::percent_decode()` now returns an iterator. Use `.into().to_owned()` to get a `Vec`. ```rust let decoded_bytes: Vec = url::percent_encoding::percent_decode(encoded_bytes) .into().to_owned(); ``` -------------------------------- ### File System Path to URL Conversion with `from_file_path` Source: https://context7.com/servo/rust-url/llms.txt Use `Url::from_file_path` to convert a file system path into a `file:` URL. Relative paths are rejected, and `Url::from_directory_path` is available for directory paths to ensure correct base resolution. ```rust # #[cfg(unix)] { use url::Url; // Path → URL let url = Url::from_file_path("/tmp/report.pdf").unwrap(); assert_eq!(url.as_str(), "file:///tmp/report.pdf"); // Relative path is rejected assert!(Url::from_file_path("../foo.txt").is_err()); // URL → Path let url = Url::parse("file:///etc/passwd").unwrap(); let path = url.to_file_path().unwrap(); assert_eq!(path, std::path::PathBuf::from("/etc/passwd")); // Directory path (guarantees trailing slash for correct base resolution) let url = Url::from_directory_path("/var/www").unwrap(); assert_eq!(url.as_str(), "file:///var/www/"); let index = url.join("index.html").unwrap(); assert_eq!(index.as_str(), "file:///var/www/index.html"); # } ``` -------------------------------- ### Run Debugger Visualizer Tests Sequentially Source: https://github.com/servo/rust-url/blob/main/debug_metadata/README.md Use this command to run debugger visualizer tests. Passing `--test-threads=1` ensures tests run one after another, preventing issues where parallel tests might try to attach multiple debuggers to the same process. ```bash cargo test --test debugger_visualizer --features debugger_visualizer -- --test-threads=1 ``` -------------------------------- ### Advanced URL parsing with Url::options and ParseOptions Source: https://context7.com/servo/rust-url/llms.txt Configure parsing options, including a base URL for relative resolution and a callback for syntax violations. Collect non-fatal syntax violations without halting the parsing process. ```rust use std::cell::RefCell; use url::{Url, SyntaxViolation, ParseError}; // Resolve a relative URL against a base let base = Url::parse("https://api.example.com")?; let endpoint = Url::options() .base_url(Some(&base)) .parse("version.json")?; assert_eq!(endpoint.as_str(), "https://api.example.com/version.json"); // Collect syntax violations without failing let violations = RefCell::new(Vec::new()); let url = Url::options() .syntax_violation_callback(Some(&|v| violations.borrow_mut().push(v))) .parse("https:////example.com")?; assert_eq!(url.as_str(), "https://example.com/"); assert_eq!( violations.into_inner(), vec![SyntaxViolation::ExpectedDoubleSlash] ); # Ok::<(), ParseError>(()) ``` -------------------------------- ### Mutating URL Path Segments with `path_segments_mut` Source: https://context7.com/servo/rust-url/llms.txt Use `path_segments_mut` to get a mutable guard for manipulating URL path segments. Segments are automatically percent-encoded. This is useful for building or modifying paths programmatically. ```rust use url::{Url, ParseError}; // Build a path from components let mut url = Url::parse("https://github.com/")?; url.path_segments_mut().map_err(|_| "cannot be base")?. extend(&["servo", "rust-url", "issues", "188"]); assert_eq!(url.as_str(), "https://github.com/servo/rust-url/issues/188"); // Pop and push let mut url = Url::parse("http://example.net/foo/index.html")?; url.path_segments_mut().map_err(|_| "cannot be base")?. pop().push("img").push("2/100%.png"); assert_eq!(url.as_str(), "http://example.net/foo/img/2%2F100%25.png"); // Clear then rebuild let mut url = Url::parse("https://github.com/servo/rust-url/")?; url.path_segments_mut().map_err(|_| "cannot be base")?. clear().push("logout"); assert_eq!(url.as_str(), "https://github.com/logout"); # Ok::<(), ParseError>(()) ``` -------------------------------- ### parse_path() removed, use Url::join() workaround Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md `url::parse_path()` and `url::UrlParser::parse_path()` are removed. Use `Url::join()` with a base URL as a workaround. ```rust let (path, query, fragment) = url::parse_path("/foo/bar/../baz?q=42").unwrap(); assert_eq!(path, vec!["foo".to_string(), "baz".to_string()]); assert_eq!(query, Some("q=42".to_string())); assert_eq!(fragment, None); ``` ```rust let base = Url::parse("http://example.com").unwrap(); let with_path = base.join("/foo/bar/../baz?q=42").unwrap(); assert_eq!(with_path.path(), "/foo/baz"); assert_eq!(with_path.query(), Some("q=42")); assert_eq!(with_path.fragment(), None); ``` -------------------------------- ### Access URL Components with Getters Source: https://context7.com/servo/rust-url/llms.txt Provides zero-copy accessors for various URL components like scheme, host, port, path, query, and fragment. Also demonstrates handling of cannot-be-a-base URLs and slicing using `Position`. ```rust use url::{Host, Position, Url, ParseError}; let url = Url::parse("https://github.com/rust-lang/rust/issues?labels=E-easy&state=open")?; // Scheme, host, port assert_eq!(url.scheme(), "https"); assert_eq!(url.host_str(), Some("github.com")); assert_eq!(url.host(), Some(Host::Domain("github.com"))); assert_eq!(url.port(), None); // 443 is the default for https assert_eq!(url.port_or_known_default(), Some(443)); // Path assert_eq!(url.path(), "/rust-lang/rust/issues"); let segments: Vec<_> = url.path_segments().unwrap().collect(); assert_eq!(segments, ["rust-lang", "rust", "issues"]); // Slice using Position assert_eq!(&url[Position::BeforePath..], "/rust-lang/rust/issues?labels=E-easy&state=open"); // Query and fragment assert_eq!(url.query(), Some("labels=E-easy&state=open")); assert_eq!(url.fragment(), None); // Cannot-be-a-base URL (data:, mailto:, etc.) let data = Url::parse("data:text/plain,Hello?World#")?; assert!(data.cannot_be_a_base()); assert!(data.path_segments().is_none()); assert_eq!(data.query(), Some("World")); # Ok::<(), ParseError>(()) ``` -------------------------------- ### Enable Serde Feature for Url Crate Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md To use Url with Serde 1.x, remove the `url_serde` dependency and enable the `serde` feature in your Cargo.toml file. ```toml # Cargo.toml [dependencies] url = { version = "2.0", features = ["serde"] } ``` -------------------------------- ### Handle Default Ports for Sockets with Url Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md In older versions, default ports for specific schemes like SOCKS5 were handled implicitly. After upgrading, use the `socket_addrs` method with a closure to explicitly define default port logic. ```rust let url = Url::parse("socks5://localhost").unwrap(); let stream = TcpStream::connect(url.with_default_port(|url| match url.scheme() { "socks5" => Ok(1080), _ => Err(()), })).unwrap(); ``` ```rust let url = Url::parse("http://github.com:80").unwrap(); let stream = TcpStream::connect(url.socket_addrs(|| match url.scheme() { "socks5" => Some(1080), _ => None, })).unwrap(); ``` -------------------------------- ### Url::from_file_path / Url::to_file_path Source: https://context7.com/servo/rust-url/llms.txt Facilitates conversion between `std::path::Path` and `file:` URLs, enabling interoperability with the file system. ```APIDOC ## `Url::from_file_path` / `Url::to_file_path` — File system interop Convert between `std::path::Path` and `file:` URLs. Available only with the `std` feature on Unix, Windows, WASI, and Redox. ### Example ```rust # #[cfg(unix)] { use url::Url; // Path → URL let url = Url::from_file_path("/tmp/report.pdf").unwrap(); assert_eq!(url.as_str(), "file:///tmp/report.pdf"); // Relative path is rejected assert!(Url::from_file_path("../foo.txt").is_err()); // URL → Path let url = Url::parse("file:///etc/passwd").unwrap(); let path = url.to_file_path().unwrap(); assert_eq!(path, std::path::PathBuf::from("/etc/passwd")); // Directory path (guarantees trailing slash for correct base resolution) let url = Url::from_directory_path("/var/www").unwrap(); assert_eq!(url.as_str(), "file:///var/www/"); let index = url.join("index.html").unwrap(); assert_eq!(index.as_str(), "file:///var/www/index.html"); # } ``` ``` -------------------------------- ### Import Percent Encoding Functions Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md The `percent_encoding` module is no longer exported by the `url` crate. Import functions like `percent_decode` directly from the `percent_encoding` crate. ```rust use url::percent_encoding::percent_decode; ``` ```rust use percent_encoding::percent_decode; ``` -------------------------------- ### Url path() method upgrade Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md The `path()` method now returns `&str` instead of `Option<&[String]>`. Use `path_segments()` for functionality similar to the old behavior. ```rust let issue_list_url = Url::parse( "https://github.com/rust-lang/rust/issues?labels=E-easy&state=open" ).unwrap(); assert_eq!(issue_list_url.path(), Some(&["rust-lang".to_string(), "rust".to_string(), "issues".to_string()][..])); ``` ```rust let issue_list_url = Url::parse( "https://github.com/rust-lang/rust/issues?labels=E-easy&state=open" ).unwrap(); assert_eq!(issue_list_url.path(), "/rust-lang/rust/issues"); assert_eq!(issue_list_url.path_segments().map(|c| c.collect::>()), Some(vec!["rust-lang", "rust", "issues"])); ``` -------------------------------- ### Convert Internationalized Domain Names to ASCII with idna Source: https://context7.com/servo/rust-url/llms.txt Normalizes and converts a Unicode domain name to its ASCII-compatible encoding (ACE / Punycode) per the WHATWG URL Standard. Passing `AsciiDenyList::URL` also applies the forbidden domain code point check. Use `domain_to_ascii_cow` for byte slices or `domain_to_ascii` for owned Strings. ```rust use idna::{domain_to_ascii_cow, domain_to_ascii, domain_to_unicode, AsciiDenyList}; // Standard conversion with the URL deny list (recommended) let ascii = domain_to_ascii_cow("münchen.de".as_bytes(), AsciiDenyList::URL).unwrap(); assert_eq!(ascii, "xn--mnchen-3ya.de"); ``` ```rust use idna::{domain_to_ascii_cow, domain_to_ascii, domain_to_unicode, AsciiDenyList}; // Convenience wrapper returning an owned String let ascii = domain_to_ascii("münchen.de").unwrap(); assert_eq!(ascii, "xn--mnchen-3ya.de"); ``` ```rust use idna::{domain_to_ascii_cow, domain_to_ascii, domain_to_unicode, AsciiDenyList}; // Round-trip: ASCII → Unicode let (unicode, result) = domain_to_unicode("xn--mnchen-3ya.de"); assert!(result.is_ok()); assert_eq!(unicode, "münchen.de"); ``` ```rust use idna::{domain_to_ascii_cow, domain_to_ascii, domain_to_unicode, AsciiDenyList}; // Strict mode enforces DNS length limits and STD3 rules assert!(idna::domain_to_ascii_strict("münchen.de").is_ok()); assert!(idna::domain_to_ascii_strict("under_score.example").is_err()); // STD3 rejects '_' ``` -------------------------------- ### Encode Strings and Bytes with `percent-encoding` Source: https://context7.com/servo/rust-url/llms.txt Use `utf8_percent_encode` for strings and `percent_encode` for raw bytes. Define custom `AsciiSet` for encoding rules. The output can be collected into a String or borrowed if no encoding is needed. ```rust use percent_encoding::{utf8_percent_encode, percent_encode, AsciiSet, CONTROLS, NON_ALPHANUMERIC}; // Define a custom encode set (WHATWG fragment percent-encode set) const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b"\"").add(b'<').add(b'>').add(b'`'); // Encode a string assert_eq!(utf8_percent_encode("foo ", FRAGMENT).to_string(), "foo%20%3Cbar%3E"); // Encode raw bytes assert_eq!(percent_encode(b"foo bar?", NON_ALPHANUMERIC).to_string(), "foo%20bar%3F"); // Collect iterator into a String let encoded: String = utf8_percent_encode("hello world", NON_ALPHANUMERIC).collect(); assert_eq!(encoded, "hello%20world"); // Borrow-optimization: no encoding needed → borrows the original slice use std::borrow::Cow; let cow: Cow = utf8_percent_encode("abc", FRAGMENT).into(); assert!(matches!(cow, Cow::Borrowed("abc"))); ``` -------------------------------- ### Retrieving URL Security Origin with `origin` Source: https://context7.com/servo/rust-url/llms.txt The `origin` method returns the security origin of a URL, which is a tuple of (scheme, host, port) for HTTP(S)/FTP/WS(S) or an opaque origin for other schemes like `file:`. Blob URLs inherit their origin from the inner URL. ```rust use url::{Host, Origin, Url, ParseError}; // Tuple origin for HTTP(S) let url = Url::parse("https://example.com/foo")?; assert_eq!( url.origin(), Origin::Tuple("https".into(), Host::Domain("example.com".into()), 443) ); assert!(url.origin().is_tuple()); assert_eq!(url.origin().ascii_serialization(), "https://example.com"); // blob: URL inherits origin from its inner URL let url = Url::parse("blob:https://example.com/uuid")?; assert_eq!( url.origin(), Origin::Tuple("https".into(), Host::Domain("example.com".into()), 443) ); // file: is always opaque — two identical file: URLs have different origins let a = Url::parse("file:///tmp/foo")?; let b = Url::parse("file:///tmp/foo")?; assert!(!a.origin().is_tuple()); assert_ne!(a.origin(), b.origin()); # Ok::<(), ParseError>(()) ``` -------------------------------- ### Define Custom Query Encoding Set Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md Prepackaged encoding sets like `QUERY_ENCODE_SET` are removed. Construct custom encoding sets using `AsciiSet` builder methods, referencing specifications for your domain. ```rust use percent_encoding::QUERY_ENCODE_SET; percent_encoding::utf8_percent_encode(value, QUERY_ENCODE_SET); ``` ```rust /// https://url.spec.whatwg.org/#query-state const QUERY: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'#').add(b'<').add(b'>'); percent_encoding::utf8_percent_encode(value, QUERY); ``` -------------------------------- ### Component getters Source: https://context7.com/servo/rust-url/llms.txt Provides zero-copy accessors for various components of a URL, such as scheme, host, port, path, query, and fragment. ```APIDOC ## Component getters — Accessing URL parts ### Description The `Url` struct exposes zero-copy accessors for every URL component. ### Method Getters for URL components (e.g., `scheme()`, `host_str()`, `port()`, `path()`, `query()`, `fragment()`) ### Parameters None ### Request Example ```rust use url::{Host, Position, Url, ParseError}; let url = Url::parse("https://github.com/rust-lang/rust/issues?labels=E-easy&state=open")?; // Scheme, host, port assert_eq!(url.scheme(), "https"); assert_eq!(url.host_str(), Some("github.com")); assert_eq!(url.host(), Some(Host::Domain("github.com"))); assert_eq!(url.port(), None); // 443 is the default for https assert_eq!(url.port_or_known_default(), Some(443)); // Path assert_eq!(url.path(), "/rust-lang/rust/issues"); let segments: Vec<_> = url.path_segments().unwrap().collect(); assert_eq!(segments, ["rust-lang", "rust", "issues"]); // Slice using Position assert_eq!(&url[Position::BeforePath..], "/rust-lang/rust/issues?labels=E-easy&state=open"); // Query and fragment assert_eq!(url.query(), Some("labels=E-easy&state=open")); assert_eq!(url.fragment(), None); // Cannot-be-a-base URL (data:, mailto:, etc.) let data = Url::parse("data:text/plain,Hello?World#")?; assert!(data.cannot_be_a_base()); assert!(data.path_segments().is_none()); assert_eq!(data.query(), Some("World")); # Ok::<(), ParseError>(()) ``` ### Response Returns the respective URL component (e.g., `String`, `Option`, `Option<&str>`). ``` -------------------------------- ### Upgrade url::form_urlencoded::serialize to Serializer Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md Use `url::form_urlencoded::Serializer` instead of the `serialize` function for form encoding. ```rust let form = url::form_urlencoded::serialize(form.iter().map(|(k, v)| { (&k[..], &v[..]) })); ``` ```rust let form = url::form_urlencoded::Serializer::new(String::new()).extend_pairs( form.iter().map(|(k, v)| { (&k[..], &v[..]) }) ).finish(); ``` -------------------------------- ### Serde Integration for `Url` Serialization/Deserialization Source: https://context7.com/servo/rust-url/llms.txt Enable the `serde` feature to serialize `Url` objects as plain strings and deserialize them by parsing. This allows `Url` to be used directly in Serde-annotated structs. ```toml # Cargo.toml [dependencies] url = { version = "2", features = ["serde"] } ``` ```rust # #[cfg(feature = "serde")] { use serde::{Deserialize, Serialize}; use url::Url; #[derive(Debug, Serialize, Deserialize)] struct Config { endpoint: Url, redirect: Url, } let json = r#"{ "endpoint": "https://api.example.com/v1", "redirect": "https://example.com/callback" }"#; let cfg: Config = serde_json::from_str(json).unwrap(); assert_eq!(cfg.endpoint.host_str(), Some("api.example.com")); let serialized = serde_json::to_string(&cfg).unwrap(); assert!(serialized.contains("https://api.example.com/v1")); # } ``` -------------------------------- ### Url serialize() replaced by as_str() Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md The `serialize()` method, which returned `String`, has been replaced by `as_str()` which returns `&str`. ```rust let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap(); assert_eq!(this_document.serialize(), "http://servo.github.io/rust-url/url/index.html".to_string()); ``` ```rust let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap(); assert_eq!(this_document.as_str(), "http://servo.github.io/rust-url/url/index.html"); ``` -------------------------------- ### Define Custom Percent-Encode Sets with `AsciiSet` Source: https://context7.com/servo/rust-url/llms.txt Create custom encoding sets using `AsciiSet` by composing built-in sets (`CONTROLS`, `NON_ALPHANUMERIC`) or using set arithmetic (union, complement). ```rust use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS, NON_ALPHANUMERIC}; // Build a set by composing existing ones // WHATWG query percent-encode set const QUERY: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'#').add(b'<').add(b'>'); assert_eq!(utf8_percent_encode("a=1 & b=<2>", QUERY).to_string(), "a=1%20&%20b=%3C2%3E"); // Set arithmetic: union, complement const A: AsciiSet = AsciiSet::EMPTY.add(b'A'); const B: AsciiSet = AsciiSet::EMPTY.add(b'B'); const AB: AsciiSet = A.union(B); // same as A + B operator let not_ab = !AB; // complement — includes everything except A and B assert!(!not_ab.contains(b'A')); assert!(not_ab.contains(b'C')); ``` -------------------------------- ### Component setters Source: https://context7.com/servo/rust-url/llms.txt Allows in-place mutation of URL components such as scheme, host, port, path, query, and fragment. Returns an error for inapplicable mutations. ```APIDOC ## Component setters — Mutating URL parts in place ### Description All setters modify the URL's internal serialization while preserving invariants. They return `Err` for inapplicable mutations (e.g. setting a host on a `mailto:` URL). ### Method Setters for URL components (e.g., `set_scheme()`, `set_host()`, `set_port()`, `set_path()`, `set_query()`, `set_fragment()`, `set_username()`, `set_password()`) ### Parameters Parameters vary depending on the setter, typically taking an `Option` or `&str` representing the new value. ### Request Example ```rust use url::{Url, ParseError}; let mut url = Url::parse("https://example.com/old-path?old=query#old-frag")?; url.set_scheme("http").unwrap(); url.set_host(Some("rust-lang.org")).unwrap(); url.set_port(Some(8080)).unwrap(); url.set_path("new-path"); url.set_query(Some("new=query")); url.set_fragment(Some("new-frag")); assert_eq!(url.as_str(), "http://rust-lang.org:8080/new-path?new=query#new-frag"); // Username and password let mut url = Url::parse("ftp://example.com/")?; url.set_username("alice").unwrap(); url.set_password(Some("s3cret")).unwrap(); assert_eq!(url.as_str(), "ftp://alice:s3cret@example.com/"); // Cannot set port on a cannot-be-a-base URL let mut mailto = Url::parse("mailto:rms@example.net")?; assert!(mailto.set_port(Some(80)).is_err()); # Ok::<(), ParseError>(()) ``` ### Response Returns `Ok(())` on successful mutation, or `Err` if the mutation is not applicable to the URL. ``` -------------------------------- ### idna::domain_to_ascii_cow Source: https://context7.com/servo/rust-url/llms.txt Normalizes and converts a Unicode domain name to its ASCII-compatible encoding (ACE / Punycode) per the WHATWG URL Standard. Passing `AsciiDenyList::URL` also applies the forbidden domain code point check. ```APIDOC ## `idna::domain_to_ascii_cow` — Convert internationalized domain names to ASCII (IDNA) Normalizes and converts a Unicode domain name to its ASCII-compatible encoding (ACE / Punycode) per the WHATWG URL Standard. Passing `AsciiDenyList::URL` also applies the forbidden domain code point check. ### Parameters - **domain**: `&[u8]` - The Unicode domain name to convert. - **deny_list**: `AsciiDenyList` - The set of characters to deny in the output ASCII domain. ### Returns - `Result, Error>` - An ASCII domain name, or an error if conversion fails. ### Usage ```rust use idna::{domain_to_ascii_cow, domain_to_ascii, domain_to_unicode, AsciiDenyList}; // Standard conversion with the URL deny list (recommended) let ascii_cow = domain_to_ascii_cow("münchen.de".as_bytes(), AsciiDenyList::URL).unwrap(); // Convenience wrapper returning an owned String let ascii_owned = domain_to_ascii("münchen.de").unwrap(); // Round-trip: ASCII → Unicode let (unicode, result) = domain_to_unicode("xn--mnchen-3ya.de"); // Strict mode enforces DNS length limits and STD3 rules let strict_ok = idna::domain_to_ascii_strict("münchen.de"); let strict_err = idna::domain_to_ascii_strict("under_score.example"); // STD3 rejects '_' // Example Assertions: // assert_eq!(ascii_cow, "xn--mnchen-3ya.de"); // assert_eq!(ascii_owned, "xn--mnchen-3ya.de"); // assert!(result.is_ok()); // assert_eq!(unicode, "münchen.de"); // assert!(strict_ok.is_ok()); // assert!(strict_err.is_err()); ``` ``` -------------------------------- ### Url::options / ParseOptions Source: https://context7.com/servo/rust-url/llms.txt Provides advanced URL parsing capabilities, including configuring a base URL for relative resolution and specifying a callback for non-fatal syntax violations. ```APIDOC ## Url::options / ParseOptions — Advanced parsing with base URL and violation callback `Url::options()` returns a `ParseOptions` builder for configuring a base URL (for relative resolution) and an optional `SyntaxViolation` callback for non-fatal issues. ### Method GET (conceptual, as this is a library function) ### Parameters - **base_url** (`Option<&Url>`) - The base URL to use for resolving relative URLs. - **syntax_violation_callback** (`Option<&dyn Fn(SyntaxViolation)>`) - A callback function to handle syntax violations. ### Response - **Success Response** (`Result`): On success, returns a `Url` object. On failure, returns a `ParseError`. ### Request Example ```rust use std::cell::RefCell; use url::{Url, SyntaxViolation, ParseError}; // Resolve a relative URL against a base let base = Url::parse("https://api.example.com")?; let endpoint = Url::options() .base_url(Some(&base)) .parse("version.json")?; assert_eq!(endpoint.as_str(), "https://api.example.com/version.json"); // Collect syntax violations without failing let violations = RefCell::new(Vec::new()); let url = Url::options() .syntax_violation_callback(Some(&|v| violations.borrow_mut().push(v))) .parse("https:////example.com")?; assert_eq!(url.as_str(), "https://example.com/"); assert_eq!( violations.into_inner(), vec![SyntaxViolation::ExpectedDoubleSlash] ); ``` ``` -------------------------------- ### Mutate URL Components in Place with Setters Source: https://context7.com/servo/rust-url/llms.txt Allows in-place modification of URL components such as scheme, host, port, path, query, and fragment. Returns `Err` for mutations that are not applicable to the URL's type (e.g., setting a port on a `mailto:` URL). Also demonstrates setting username and password. ```rust use url::{Url, ParseError}; let mut url = Url::parse("https://example.com/old-path?old=query#old-frag")?; url.set_scheme("http").unwrap(); url.set_host(Some("rust-lang.org")).unwrap(); url.set_port(Some(8080)).unwrap(); url.set_path("new-path"); url.set_query(Some("new=query")); url.set_fragment(Some("new-frag")); assert_eq!(url.as_str(), "http://rust-lang.org:8080/new-path?new=query#new-frag"); // Username and password let mut url = Url::parse("ftp://example.com/")?; url.set_username("alice").unwrap(); url.set_password(Some("s3cret")).unwrap(); assert_eq!(url.as_str(), "ftp://alice:s3cret@example.com/"); // Cannot set port on a cannot-be-a-base URL let mut mailto = Url::parse("mailto:rms@example.net")?; assert!(mailto.set_port(Some(80)).is_err()); # Ok::<(), ParseError>(()) ``` -------------------------------- ### Upgrade set_query_from_pairs to query_pairs_mut Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md The `set_query_from_pairs` method on `url::Url` has been replaced by `query_pairs_mut` for modifying query parameters. ```rust let mut url = Url::parse("https://duckduckgo.com/").unwrap(); let pairs = vec![ ("q", "test"), ("ia", "images"), ]; url.set_query_from_pairs(pairs.iter().map(|&(k, v)| { (&k[..], &v[..]) })); ``` ```rust let mut url = Url::parse("https://duckduckgo.com/").unwrap(); let pairs = vec![ ("q", "test"), ("ia", "images"), ]; url.query_pairs_mut().clear().extend_pairs( pairs.iter().map(|&(k, v)| { (&k[..], &v[..]) }) ); ``` -------------------------------- ### Serde integration Source: https://context7.com/servo/rust-url/llms.txt Enables serialization and deserialization of `Url` objects using the Serde library, allowing `Url` to be treated as a string in JSON or other formats. ```APIDOC ## Serde integration — Serialize and deserialize `Url` Enable the `serde` feature to serialize `Url` as a plain string and deserialize by parsing. ### Example ```toml # Cargo.toml [dependencies] url = { version = "2", features = ["serde"] } ``` ```rust # #[cfg(feature = "serde")] { use serde::{Deserialize, Serialize}; use url::Url; #[derive(Debug, Serialize, Deserialize)] struct Config { endpoint: Url, redirect: Url, } let json = r#"{ "endpoint": "https://api.example.com/v1", "redirect": "https://example.com/callback" }"#; let cfg: Config = serde_json::from_str(json).unwrap(); assert_eq!(cfg.endpoint.host_str(), Some("api.example.com")); let serialized = serde_json::to_string(&cfg).unwrap(); assert!(serialized.contains("https://api.example.com/v1")); # } ``` ``` -------------------------------- ### Build application/x-www-form-urlencoded Strings with form_urlencoded Source: https://context7.com/servo/rust-url/llms.txt Encodes key-value pairs into a properly encoded query string. Spaces become '+', and other special characters are percent-encoded. The serializer is reusable after calling `clear()`. ```rust use form_urlencoded; let encoded: String = form_urlencoded::Serializer::new(String::new()) .append_pair("foo", "bar & baz") .append_pair("saison", "Été+hiver") .finish(); assert_eq!(encoded, "foo=bar+%26+baz&saison=%C3%89t%C3%A9%2Bhiver"); ``` ```rust use form_urlencoded; // Append multiple pairs at once let encoded: String = form_urlencoded::Serializer::new(String::new()) .extend_pairs([("q", "rust url"), ("page", "1"), ("per_page", "20")]) .finish(); assert_eq!(encoded, "q=rust+url&page=1&per_page=20"); ``` ```rust use form_urlencoded; // Append key-only entries (no `=value`) let encoded: String = form_urlencoded::Serializer::new(String::new()) .append_pair("active", "true") .append_key_only("verbose") .finish(); assert_eq!(encoded, "active=true&verbose"); ``` ```rust use form_urlencoded; // Clear and rebuild — the serializer is reusable let mut s = form_urlencoded::Serializer::new(String::new()); s.append_pair("old", "data"); s.clear().append_pair("new", "data"); assert_eq!(s.finish(), "new=data"); ``` -------------------------------- ### UrlParser replaced by Url::parse() and Url::join() Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md UrlParser has been replaced by `Url::parse()` and `Url::join()` for parsing and joining URLs. ```rust let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap(); let css_url = UrlParser::new().base_url(&this_document).parse("../main.css").unwrap(); assert_eq!(css_url.serialize(), "http://servo.github.io/rust-url/main.css".to_string()); ``` ```rust let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap(); let css_url = this_document.join("../main.css").unwrap(); assert_eq!(css_url.as_str(), "http://servo.github.io/rust-url/main.css"); ``` -------------------------------- ### Parse URL and append query parameters with Url::parse_with_params Source: https://context7.com/servo/rust-url/llms.txt Parses a URL string and appends key-value pairs to its query string without overwriting existing parameters. Ensure the URL is valid before appending. ```rust use url::{Url, ParseError}; let url = Url::parse_with_params( "https://example.net?dont=clobberme", &[("lang", "rust"), ("browser", "servo")], )?; assert_eq!( url.as_str(), "https://example.net/?dont=clobberme&lang=rust&browser=servo" ); # Ok::<(), ParseError>(()) ``` -------------------------------- ### Use new EncodeSet types for percent encoding Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md The `EncodeSet` struct and its instances have been updated. Use `USERINFO_ENCODE_SET` instead of `USERNAME_ENCODE_SET` and `PASSWORD_ENCODE_SET`. `FORM_URLENCODED_ENCODE_SET` is replaced by `url::form_urlencoded` functionality. ```rust use url::percent_encoding::{DEFAULT_ENCODE_SET, EncodeSet}; let encoded = url::percent_encoding::percent_encode(raw_bytes, DEFAULT_ENCODE_SET); ``` -------------------------------- ### Url::join Source: https://context7.com/servo/rust-url/llms.txt Resolves a relative URL reference against the current URL, following the URL Standard's base-URL resolution rules. A trailing slash on the base URL is significant. ```APIDOC ## Url::join — Resolve a relative reference against a base URL Resolves the given string relative to `self`, following the URL Standard's base-URL resolution rules. A trailing slash on the base is significant. ### Method POST (conceptual, as this is a library function) ### Parameters - **relative_url** (`&str`) - The relative URL string to resolve. ### Response - **Success Response** (`Result`): On success, returns a `Url` object representing the resolved URL. On failure, returns a `ParseError`. ### Request Example ```rust use url::{Url, ParseError}; // Without trailing slash — last segment is treated as a file let base = Url::parse("https://example.net/a/b.html")?; assert_eq!(base.join("c.png")?.as_str(), "https://example.net/a/c.png"); // With trailing slash — full directory is the base let base = Url::parse("https://example.net/a/b/")?; assert_eq!(base.join("c.png")?.as_str(), "https://example.net/a/b/c.png"); // Absolute URL in input replaces everything including scheme let base = Url::parse("https://alice.com/a")?; assert_eq!(base.join("http://eve.com/b")?.as_str(), "http://eve.com/b"); // Root-relative input let base = Url::parse("https://alice.com/a")?; assert_eq!(base.join("/v1/meta")?.as_str(), "https://alice.com/v1/meta"); ``` ``` -------------------------------- ### `utf8_percent_encode` / `percent_encode` Source: https://context7.com/servo/rust-url/llms.txt Encode strings or bytes using a caller-defined `AsciiSet`. The output can be collected into a String or used as an iterator. ```APIDOC ## `utf8_percent_encode` / `percent_encode` — Encode strings or bytes Percent-encode a UTF-8 string or raw bytes against a caller-defined `AsciiSet`. The return type implements `Iterator`, `Display` (`.to_string()`), and `Into>`. ### Usage Examples ```rust use percent_encoding::{utf8_percent_encode, percent_encode, AsciiSet, CONTROLS, NON_ALPHANUMERIC}; // Define a custom encode set (WHATWG fragment percent-encode set) const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`'); // Encode a string assert_eq!(utf8_percent_encode("foo ", FRAGMENT).to_string(), "foo%20%3Cbar%3E"); // Encode raw bytes assert_eq!(percent_encode(b"foo bar?", NON_ALPHANUMERIC).to_string(), "foo%20bar%3F"); // Collect iterator into a String let encoded: String = utf8_percent_encode("hello world", NON_ALPHANUMERIC).collect(); assert_eq!(encoded, "hello%20world"); // Borrow-optimization: no encoding needed → borrows the original slice use std::borrow::Cow; let cow: Cow = utf8_percent_encode("abc", FRAGMENT).into(); assert!(matches!(cow, Cow::Borrowed("abc"))); ``` ``` -------------------------------- ### `form_urlencoded::parse` Source: https://context7.com/servo/rust-url/llms.txt Parse `application/x-www-form-urlencoded` query strings into an iterator of name-value pairs, handling `+` as space and percent-decoding. ```APIDOC ## `form_urlencoded::parse` — Parse `application/x-www-form-urlencoded` query strings Decodes a query byte string into an iterator of `(Cow, Cow)` name-value pairs, handling `+` as space, and percent-decoding. ### Usage Examples ```rust use std::borrow::Cow; use form_urlencoded; // Parse a query string let pairs: Vec<_> = form_urlencoded::parse(b"foo=bar+baz&lang=rust%21").collect(); assert_eq!(pairs[0], (Cow::Borrowed("foo"), Cow::Owned("bar baz".into()))); assert_eq!(pairs[1], (Cow::Borrowed("lang"), Cow::Owned("rust!".into()))); // .into_owned() yields (String, String) pairs let owned: Vec<(String, String)> = form_urlencoded::parse(b"a=1&b=2").into_owned().collect(); assert_eq!(owned, [("a".into(), "1".into()), ("b".into(), "2".into())]); // Empty values and key-only entries let pairs: Vec<_> = form_urlencoded::parse(b"key=&flag").collect(); assert_eq!(pairs[0].0, "key"); assert_eq!(pairs[0].1, ""); assert_eq!(pairs[1].0, "flag"); assert_eq!(pairs[1].1, ""); ``` ``` -------------------------------- ### Decode Percent-Encoded Data with `percent-encoding` Source: https://context7.com/servo/rust-url/llms.txt Use `percent_decode` for byte slices and `percent_decode_str` for strings. The decoded output can be collected as raw bytes, decoded to UTF-8, or lossily decoded. ```rust use percent_encoding::{percent_decode, percent_decode_str}; // Decode to UTF-8 string assert_eq!( percent_decode(b"foo%20bar%3f").decode_utf8().unwrap(), "foo bar?" ); // Decode from &str assert_eq!( percent_decode_str("caf%C3%A9").decode_utf8().unwrap(), "café" ); // Collect raw bytes let bytes: Vec = percent_decode(b"foo%20bar").collect(); assert_eq!(bytes, b"foo bar"); // Lossy decode — invalid UTF-8 sequences become U+FFFD assert_eq!( percent_decode(b"%F0%9F%92%96").decode_utf8_lossy(), "💖" ); // Invalid UTF-8 without lossy mode returns Err let err = percent_decode(b"%00%9F%92%96").decode_utf8().unwrap_err(); assert_eq!(err.valid_up_to(), 1); ``` -------------------------------- ### Parse and Decode data: URLs with data-url crate Source: https://context7.com/servo/rust-url/llms.txt Processes a `data:` URL string per the Fetch Standard, exposing its MIME type and body. The body can be decoded as a `Vec` or streamed via a callback. Ensure the `mime` feature is enabled for MIME type matching. ```rust use data_url::{DataUrl, mime}; // Plain text data URL let url = DataUrl::process("data:,Hello%20World!").unwrap(); let (body, fragment) = url.decode_to_vec().unwrap(); assert!(url.mime_type().matches("text", "plain")); assert_eq!(url.mime_type().get_parameter("charset"), Some("US-ASCII")); assert_eq!(body, b"Hello World!"); assert!(fragment.is_none()); ``` ```rust use data_url::{DataUrl, mime}; // Base64-encoded PNG (abbreviated) let url = DataUrl::process("data:image/png;base64,iVBORw0KGgo=").unwrap(); assert!(url.mime_type().matches("image", "png")); let (body, _) = url.decode_to_vec().unwrap(); assert!(!body.is_empty()); ``` ```rust use data_url::{DataUrl, mime}; // Streaming decode via callback let url = DataUrl::process("data:text/csv,col1%2Ccol2%0A1%2C2").unwrap(); let mut output = Vec::new(); url.decode(|bytes| -> Result<(), ()> { output.extend_from_slice(bytes); Ok(()) }).unwrap(); assert_eq!(output, b"col1,col2\n1,2"); ``` -------------------------------- ### Url::parse_with_params Source: https://context7.com/servo/rust-url/llms.txt Parses a URL string and appends key-value pairs to its query string without overwriting existing parameters. ```APIDOC ## Url::parse_with_params — Parse a URL and append query parameters Parses a URL string and appends key-value pairs to its query string without clobbering existing parameters. ### Method POST (conceptual, as this is a library function) ### Parameters - **url_string** (`&str`) - The base URL string to parse. - **params** (`&[(&str, &str)]`) - A slice of key-value pairs to append to the query string. ### Response - **Success Response** (`Result`): On success, returns a `Url` object with the appended query parameters. On failure, returns a `ParseError`. ### Request Example ```rust use url::{Url, ParseError}; let url = Url::parse_with_params( "https://example.net?dont=clobberme", &[("lang", "rust"), ("browser", "servo")], )?; assert_eq!( url.as_str(), "https://example.net/?dont=clobberme&lang=rust&browser=servo" ); ``` ``` -------------------------------- ### DNS Resolution to Socket Addresses with `socket_addrs` Source: https://context7.com/servo/rust-url/llms.txt The `socket_addrs` method resolves a URL's host and port to a `Vec`, performing DNS lookup for domain hosts. It allows specifying custom default ports for unknown schemes via a closure. ```rust use url::Url; // Custom default port for unknown schemes fn connect(url: Url) -> std::io::Result> { url.socket_addrs(|| match url.scheme() { "socks5" | "socks5h" => Some(1080), "redis" => Some(6379), _ => None, }) } let url = Url::parse("redis://cache.example.com").unwrap(); // connect(url) would resolve cache.example.com:6379 ``` -------------------------------- ### `AsciiSet` Source: https://context7.com/servo/rust-url/llms.txt `AsciiSet` is a compact const-compatible bitset used to specify which characters need to be percent-encoded. It supports set arithmetic like union and complement. ```APIDOC ## `AsciiSet` — Define custom percent-encode sets `AsciiSet` is a compact const-compatible bitset covering the ASCII range, used to specify which characters need to be percent-encoded. Two built-in sets are exported: `CONTROLS` (C0 + DEL) and `NON_ALPHANUMERIC` (everything that is not a letter or digit). ### Usage Examples ```rust use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS, NON_ALPHANUMERIC}; // Build a set by composing existing ones // WHATWG query percent-encode set const QUERY: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'#').add(b'<').add(b'>'); assert_eq!(utf8_percent_encode("a=1 & b=<2>", QUERY).to_string(), "a=1%20&%20b=%3C2%3E"); // Set arithmetic: union, complement const A: AsciiSet = AsciiSet::EMPTY.add(b'A'); const B: AsciiSet = AsciiSet::EMPTY.add(b'B'); const AB: AsciiSet = A.union(B); // same as A + B operator let not_ab = !AB; // complement — includes everything except A and B assert!(!not_ab.contains(b'A')); assert!(not_ab.contains(b'C')); ``` ``` -------------------------------- ### form_urlencoded::serialize replaced by Serializer struct Source: https://github.com/servo/rust-url/blob/main/UPGRADING.md The `url::form_urlencoded::serialize()` method is replaced by the `url::form_urlencoded::Serializer` struct for encoding URL form data. ```rust let mut buf = String::new(); { let mut encoder = url::form_urlencoded::Serializer::new("&buf"); encoder.extend_pairs(vec![("a", "1"), ("b", "2")]).finish(); } assert_eq!(buf, "a=1&b=2"); ```