Skip to content

Commit 1538bf4

Browse files
committed
Make the port of Origin be an Option<u16>
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.
1 parent 08a3268 commit 1538bf4

File tree

3 files changed

+53
-15
lines changed

3 files changed

+53
-15
lines changed

url/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -820,7 +820,7 @@ impl Url {
820820
/// assert_eq!(url.origin(),
821821
/// Origin::Tuple("ftp".into(),
822822
/// Host::Domain("example.com".into()),
823-
/// 21));
823+
/// None));
824824
/// # Ok(())
825825
/// # }
826826
/// # run().unwrap();
@@ -837,7 +837,7 @@ impl Url {
837837
/// assert_eq!(url.origin(),
838838
/// Origin::Tuple("https".into(),
839839
/// Host::Domain("example.com".into()),
840-
/// 443));
840+
/// None));
841841
/// # Ok(())
842842
/// # }
843843
/// # run().unwrap();

url/src/origin.rs

+26-13
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,45 @@
77
// except according to those terms.
88

99
use crate::host::Host;
10-
use crate::parser::default_port;
1110
use crate::Url;
1211
use alloc::borrow::ToOwned;
1312
use alloc::format;
1413
use alloc::string::String;
1514
use core::sync::atomic::{AtomicUsize, Ordering};
1615

16+
/// Get the origin from a URL according to the specification:
17+
/// <https://url.spec.whatwg.org/#origin>
1718
pub fn url_origin(url: &Url) -> Origin {
1819
let scheme = url.scheme();
1920
match scheme {
21+
// > "blob"
22+
// > 1. If url’s blob URL entry is non-null, then return url’s blob URL entry’s
23+
// > environment’s origin.
24+
// > 2. Let pathURL be the result of parsing the result of URL path serializing url.
25+
// > 3. If pathURL is failure, then return a new opaque origin.
26+
// > 4. If pathURL’s scheme is "http", "https", or "file", then return pathURL’s origin.
27+
// > 5. Return a new opaque origin.
2028
"blob" => {
2129
let result = Url::parse(url.path());
2230
match result {
2331
Ok(ref url) => url_origin(url),
2432
Err(_) => Origin::new_opaque(),
2533
}
2634
}
35+
// > "ftp" "http" "https" "ws" "wss": Return the tuple origin (url’s scheme, url’s host,
36+
// > url’s port, null).
37+
//
2738
"ftp" | "http" | "https" | "ws" | "wss" => Origin::Tuple(
2839
scheme.to_owned(),
2940
url.host().unwrap().to_owned(),
30-
url.port_or_known_default().unwrap(),
41+
url.port(),
3142
),
43+
// > "file": Unfortunate as it is, this is left as an exercise to the reader. When in
44+
// > doubt, return a new opaque origin.
45+
//
3246
// TODO: Figure out what to do if the scheme is a file
3347
"file" => Origin::new_opaque(),
48+
// > Otherwise: Return a new opaque origin.
3449
_ => Origin::new_opaque(),
3550
}
3651
}
@@ -58,7 +73,7 @@ pub enum Origin {
5873
Opaque(OpaqueOrigin),
5974

6075
/// Consists of the URL's scheme, host and port
61-
Tuple(String, Host<String>, u16),
76+
Tuple(String, Host<String>, Option<u16>),
6277
}
6378

6479
impl Origin {
@@ -78,12 +93,11 @@ impl Origin {
7893
pub fn ascii_serialization(&self) -> String {
7994
match *self {
8095
Origin::Opaque(_) => "null".to_owned(),
81-
Origin::Tuple(ref scheme, ref host, port) => {
82-
if default_port(scheme) == Some(port) {
83-
format!("{}://{}", scheme, host)
84-
} else {
85-
format!("{}://{}:{}", scheme, host, port)
86-
}
96+
Origin::Tuple(ref scheme, ref host, Some(port)) => {
97+
format!("{}://{}:{}", scheme, host, port)
98+
}
99+
Origin::Tuple(ref scheme, ref host, _) => {
100+
format!("{}://{}", scheme, host)
87101
}
88102
}
89103
}
@@ -100,10 +114,9 @@ impl Origin {
100114
}
101115
_ => host.clone(),
102116
};
103-
if default_port(scheme) == Some(port) {
104-
format!("{}://{}", scheme, host)
105-
} else {
106-
format!("{}://{}:{}", scheme, host, port)
117+
match port {
118+
Some(port) => format!("{}://{}:{}", scheme, host, port),
119+
None => format!("{}://{}", scheme, host),
107120
}
108121
}
109122
}

url/tests/unit.rs

+25
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,31 @@ fn test_origin_unicode_serialization() {
667667
}
668668
}
669669

670+
#[test]
671+
fn test_origin_default_port() {
672+
let urls_and_expected_origin_ports = [
673+
("http://example.com:80", None),
674+
("http://example.com", None),
675+
("https://example.com:443", None),
676+
("https://example.com", None),
677+
("ftp://127.0.0.1:21/", None),
678+
("ftp://127.0.0.1/", None),
679+
("http://example.com:221", Some(221)),
680+
("http://example.com:123", Some(123)),
681+
("https://example.com:442", Some(442)),
682+
("https://example.com:80", Some(80)),
683+
("ftp://127.0.0.1:20/", Some(20)),
684+
("ftp://127.0.0.1:80/", Some(80)),
685+
];
686+
687+
for (url_string, expected_port) in &urls_and_expected_origin_ports {
688+
match Url::parse(url_string).unwrap().origin() {
689+
Origin::Opaque(..) => unreachable!("Should not have found an opaque origin."),
690+
Origin::Tuple(_, _, port) => assert_eq!(port, *expected_port),
691+
}
692+
}
693+
}
694+
670695
#[test]
671696
#[cfg(feature = "std")]
672697
#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]

0 commit comments

Comments
 (0)