Skip to content

Commit

Permalink
Make the port of Origin be an Option<u16>
Browse files Browse the repository at this point in the history
The URL specification changed in 2016 [1] [2] such that now the origin's port
should be the same as the URL's port. This means that the port can
`None` in the case that it is the default port for a scheme.

1. whatwg/url@b0e4def
2. whatwg/html#870

Fixes #821.
  • Loading branch information
mrobinson committed Oct 31, 2024
1 parent 08a3268 commit 1538bf4
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 15 deletions.
4 changes: 2 additions & 2 deletions url/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@ impl Url {
/// assert_eq!(url.origin(),
/// Origin::Tuple("ftp".into(),
/// Host::Domain("example.com".into()),
/// 21));
/// None));
/// # Ok(())
/// # }
/// # run().unwrap();
Expand All @@ -837,7 +837,7 @@ impl Url {
/// assert_eq!(url.origin(),
/// Origin::Tuple("https".into(),
/// Host::Domain("example.com".into()),
/// 443));
/// None));
/// # Ok(())
/// # }
/// # run().unwrap();
Expand Down
39 changes: 26 additions & 13 deletions url/src/origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,45 @@
// except according to those terms.

use crate::host::Host;
use crate::parser::default_port;
use crate::Url;
use alloc::borrow::ToOwned;
use alloc::format;
use alloc::string::String;
use core::sync::atomic::{AtomicUsize, Ordering};

/// Get the origin from a URL according to the specification:
/// <https://url.spec.whatwg.org/#origin>
pub fn url_origin(url: &Url) -> Origin {
let scheme = url.scheme();
match scheme {
// > "blob"
// > 1. If url’s blob URL entry is non-null, then return url’s blob URL entry’s
// > environment’s origin.
// > 2. Let pathURL be the result of parsing the result of URL path serializing url.
// > 3. If pathURL is failure, then return a new opaque origin.
// > 4. If pathURL’s scheme is "http", "https", or "file", then return pathURL’s origin.
// > 5. Return a new opaque origin.
"blob" => {
let result = Url::parse(url.path());
match result {
Ok(ref url) => url_origin(url),
Err(_) => Origin::new_opaque(),
}
}
// > "ftp" "http" "https" "ws" "wss": Return the tuple origin (url’s scheme, url’s host,
// > url’s port, null).
//
"ftp" | "http" | "https" | "ws" | "wss" => Origin::Tuple(
scheme.to_owned(),
url.host().unwrap().to_owned(),
url.port_or_known_default().unwrap(),
url.port(),
),
// > "file": Unfortunate as it is, this is left as an exercise to the reader. When in
// > doubt, return a new opaque origin.
//
// TODO: Figure out what to do if the scheme is a file
"file" => Origin::new_opaque(),
// > Otherwise: Return a new opaque origin.
_ => Origin::new_opaque(),
}
}
Expand Down Expand Up @@ -58,7 +73,7 @@ pub enum Origin {
Opaque(OpaqueOrigin),

/// Consists of the URL's scheme, host and port
Tuple(String, Host<String>, u16),
Tuple(String, Host<String>, Option<u16>),
}

impl Origin {
Expand All @@ -78,12 +93,11 @@ impl Origin {
pub fn ascii_serialization(&self) -> String {
match *self {
Origin::Opaque(_) => "null".to_owned(),
Origin::Tuple(ref scheme, ref host, port) => {
if default_port(scheme) == Some(port) {
format!("{}://{}", scheme, host)
} else {
format!("{}://{}:{}", scheme, host, port)
}
Origin::Tuple(ref scheme, ref host, Some(port)) => {
format!("{}://{}:{}", scheme, host, port)
}
Origin::Tuple(ref scheme, ref host, _) => {
format!("{}://{}", scheme, host)
}
}
}
Expand All @@ -100,10 +114,9 @@ impl Origin {
}
_ => host.clone(),
};
if default_port(scheme) == Some(port) {
format!("{}://{}", scheme, host)
} else {
format!("{}://{}:{}", scheme, host, port)
match port {
Some(port) => format!("{}://{}:{}", scheme, host, port),
None => format!("{}://{}", scheme, host),
}
}
}
Expand Down
25 changes: 25 additions & 0 deletions url/tests/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,31 @@ fn test_origin_unicode_serialization() {
}
}

#[test]
fn test_origin_default_port() {
let urls_and_expected_origin_ports = [
("http://example.com:80", None),
("http://example.com", None),
("https://example.com:443", None),
("https://example.com", None),
("ftp://127.0.0.1:21/", None),
("ftp://127.0.0.1/", None),
("http://example.com:221", Some(221)),
("http://example.com:123", Some(123)),
("https://example.com:442", Some(442)),
("https://example.com:80", Some(80)),
("ftp://127.0.0.1:20/", Some(20)),
("ftp://127.0.0.1:80/", Some(80)),
];

for (url_string, expected_port) in &urls_and_expected_origin_ports {
match Url::parse(url_string).unwrap().origin() {
Origin::Opaque(..) => unreachable!("Should not have found an opaque origin."),
Origin::Tuple(_, _, port) => assert_eq!(port, *expected_port),
}
}
}

#[test]
#[cfg(feature = "std")]
#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
Expand Down

0 comments on commit 1538bf4

Please sign in to comment.