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