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