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