1 // Copyright 2016 The rust-url developers.
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8
9 use crate::host::Host;
10 use crate::parser::default_port;
11 use crate::Url;
12 use idna::domain_to_unicode;
13 use std::sync::atomic::{AtomicUsize, Ordering};
14
url_origin(url: &Url) -> Origin15 pub fn url_origin(url: &Url) -> Origin {
16 let scheme = url.scheme();
17 match scheme {
18 "blob" => {
19 let result = Url::parse(url.path());
20 match result {
21 Ok(ref url) => url_origin(url),
22 Err(_) => Origin::new_opaque(),
23 }
24 }
25 "ftp" | "http" | "https" | "ws" | "wss" => Origin::Tuple(
26 scheme.to_owned(),
27 url.host().unwrap().to_owned(),
28 url.port_or_known_default().unwrap(),
29 ),
30 // TODO: Figure out what to do if the scheme is a file
31 "file" => Origin::new_opaque(),
32 _ => Origin::new_opaque(),
33 }
34 }
35
36 /// The origin of an URL
37 ///
38 /// Two URLs with the same origin are considered
39 /// to originate from the same entity and can therefore trust
40 /// each other.
41 ///
42 /// The origin is determined based on the scheme as follows:
43 ///
44 /// - If the scheme is "blob" the origin is the origin of the
45 /// URL contained in the path component. If parsing fails,
46 /// it is an opaque origin.
47 /// - If the scheme is "ftp", "http", "https", "ws", or "wss",
48 /// then the origin is a tuple of the scheme, host, and port.
49 /// - If the scheme is anything else, the origin is opaque, meaning
50 /// the URL does not have the same origin as any other URL.
51 ///
52 /// For more information see <https://url.spec.whatwg.org/#origin>
53 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
54 pub enum Origin {
55 /// A globally unique identifier
56 Opaque(OpaqueOrigin),
57
58 /// Consists of the URL's scheme, host and port
59 Tuple(String, Host<String>, u16),
60 }
61
62 impl Origin {
63 /// Creates a new opaque origin that is only equal to itself.
new_opaque() -> Origin64 pub fn new_opaque() -> Origin {
65 static COUNTER: AtomicUsize = AtomicUsize::new(0);
66 Origin::Opaque(OpaqueOrigin(COUNTER.fetch_add(1, Ordering::SeqCst)))
67 }
68
69 /// Return whether this origin is a (scheme, host, port) tuple
70 /// (as opposed to an opaque origin).
is_tuple(&self) -> bool71 pub fn is_tuple(&self) -> bool {
72 matches!(*self, Origin::Tuple(..))
73 }
74
75 /// <https://html.spec.whatwg.org/multipage/#ascii-serialisation-of-an-origin>
ascii_serialization(&self) -> String76 pub fn ascii_serialization(&self) -> String {
77 match *self {
78 Origin::Opaque(_) => "null".to_owned(),
79 Origin::Tuple(ref scheme, ref host, port) => {
80 if default_port(scheme) == Some(port) {
81 format!("{}://{}", scheme, host)
82 } else {
83 format!("{}://{}:{}", scheme, host, port)
84 }
85 }
86 }
87 }
88
89 /// <https://html.spec.whatwg.org/multipage/#unicode-serialisation-of-an-origin>
unicode_serialization(&self) -> String90 pub fn unicode_serialization(&self) -> String {
91 match *self {
92 Origin::Opaque(_) => "null".to_owned(),
93 Origin::Tuple(ref scheme, ref host, port) => {
94 let host = match *host {
95 Host::Domain(ref domain) => {
96 let (domain, _errors) = domain_to_unicode(domain);
97 Host::Domain(domain)
98 }
99 _ => host.clone(),
100 };
101 if default_port(scheme) == Some(port) {
102 format!("{}://{}", scheme, host)
103 } else {
104 format!("{}://{}:{}", scheme, host, port)
105 }
106 }
107 }
108 }
109 }
110
111 /// Opaque identifier for URLs that have file or other schemes
112 #[derive(Eq, PartialEq, Hash, Clone, Debug)]
113 pub struct OpaqueOrigin(usize);
114