script/dom/
origin.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use dom_struct::dom_struct;
6use js::rust::{HandleObject, HandleValue};
7use net_traits::pub_domains::is_same_site;
8use servo_url::{ImmutableOrigin, ServoUrl};
9
10use crate::dom::bindings::codegen::Bindings::OriginBinding::OriginMethods;
11use crate::dom::bindings::conversions::{
12    ConversionResult, SafeFromJSValConvertible, StringificationBehavior, root_from_handlevalue,
13};
14use crate::dom::bindings::error::{Error, Fallible};
15use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
16use crate::dom::bindings::root::DomRoot;
17use crate::dom::bindings::str::DOMString;
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
20use crate::dom::html::htmlareaelement::HTMLAreaElement;
21use crate::dom::html::htmlhyperlinkelementutils::{HyperlinkElement, HyperlinkElementTraits};
22use crate::dom::url::URL;
23use crate::dom::window::Window;
24use crate::script_runtime::{CanGc, JSContext};
25
26/// <https://html.spec.whatwg.org/multipage/#the-origin-interface>
27#[dom_struct]
28pub(crate) struct Origin {
29    reflector: Reflector,
30    #[no_trace]
31    origin: ImmutableOrigin,
32}
33
34impl Origin {
35    fn new_inherited(origin: ImmutableOrigin) -> Origin {
36        Origin {
37            reflector: Reflector::new(),
38            origin,
39        }
40    }
41
42    fn new(
43        global: &GlobalScope,
44        proto: Option<HandleObject>,
45        origin: ImmutableOrigin,
46        can_gc: CanGc,
47    ) -> DomRoot<Origin> {
48        reflect_dom_object_with_proto(
49            Box::new(Origin::new_inherited(origin)),
50            global,
51            proto,
52            can_gc,
53        )
54    }
55
56    /// <https://html.spec.whatwg.org/multipage/#extract-an-origin>
57    fn extract_an_origin_from_platform_object(
58        value: HandleValue,
59        cx: JSContext,
60        current_global: &GlobalScope,
61    ) -> Option<ImmutableOrigin> {
62        // <https://html.spec.whatwg.org/multipage/#the-origin-interface:extract-an-origin>
63        if let Ok(origin_obj) = root_from_handlevalue::<Origin>(value, cx) {
64            return Some(origin_obj.origin.clone());
65        }
66
67        // <https://url.spec.whatwg.org/#concept-url-origin>
68        if let Ok(url_obj) = root_from_handlevalue::<URL>(value, cx) {
69            return Some(url_obj.origin());
70        }
71
72        // <https://html.spec.whatwg.org/multipage/#window:extract-an-origin>
73        if let Ok(window_obj) = root_from_handlevalue::<Window>(value, cx) {
74            let window_origin = window_obj.origin();
75            if !current_global.origin().same_origin_domain(window_origin) {
76                return None;
77            }
78            return Some(window_origin.immutable().clone());
79        }
80
81        // <https://html.spec.whatwg.org/multipage/#api-for-a-and-area-elements:extract-an-origin>
82        if let Ok(anchor_obj) = root_from_handlevalue::<HTMLAnchorElement>(value, cx) {
83            anchor_obj.reinitialize_url();
84            if let Some(ref url) = *anchor_obj.get_url().borrow() {
85                return Some(url.origin());
86            }
87            return None;
88        }
89
90        // <https://html.spec.whatwg.org/multipage/#api-for-a-and-area-elements:extract-an-origin>
91        if let Ok(area_obj) = root_from_handlevalue::<HTMLAreaElement>(value, cx) {
92            area_obj.reinitialize_url();
93            if let Some(ref url) = *area_obj.get_url().borrow() {
94                return Some(url.origin());
95            }
96            return None;
97        }
98
99        None
100    }
101}
102
103impl OriginMethods<crate::DomTypeHolder> for Origin {
104    /// <https://html.spec.whatwg.org/multipage/#dom-origin-constructor>
105    fn Constructor(
106        global: &GlobalScope,
107        proto: Option<HandleObject>,
108        can_gc: CanGc,
109    ) -> DomRoot<Origin> {
110        Origin::new(global, proto, ImmutableOrigin::new_opaque(), can_gc)
111    }
112
113    /// <https://html.spec.whatwg.org/multipage/#dom-origin-from>
114    fn From(cx: JSContext, global: &GlobalScope, value: HandleValue) -> Fallible<DomRoot<Origin>> {
115        let can_gc = CanGc::note();
116
117        // Step 1. If value is a platform object:
118        //   1. Let origin be the result of executing value's extract an origin operation.
119        //   2. If origin is not null, then return a new Origin object whose origin is origin.
120        if let Some(origin) = Origin::extract_an_origin_from_platform_object(value, cx, global) {
121            return Ok(Origin::new(global, None, origin, can_gc));
122        }
123
124        // Step 2. If value is a string:
125        if value.get().is_string() {
126            let s = match DOMString::safe_from_jsval(
127                cx,
128                value,
129                StringificationBehavior::Default,
130                can_gc,
131            ) {
132                Ok(ConversionResult::Success(s)) => s,
133                _ => return Err(Error::Type("Failed to convert value to string".to_string())),
134            };
135
136            // Step 2.1. Let parsedURL be the result of basic URL parsing value.
137            // Step 2.2. If parsedURL is not failure, then return a new Origin object whose
138            //           origin is set to parsedURL's origin.
139            match ServoUrl::parse(&s.to_string()) {
140                Ok(url) => return Ok(Origin::new(global, None, url.origin(), can_gc)),
141                Err(_) => return Err(Error::Type("Failed to parse URL".to_string())),
142            }
143        }
144
145        // Step 3. Throw a TypeError.
146        Err(Error::Type(
147            "Value must be a string or a platform object with an origin".to_string(),
148        ))
149    }
150
151    /// <https://html.spec.whatwg.org/multipage/#dom-origin-opaque>
152    fn Opaque(&self) -> bool {
153        !self.origin.is_tuple()
154    }
155
156    /// <https://html.spec.whatwg.org/multipage/#dom-origin-issameorigin>
157    fn IsSameOrigin(&self, other: &Origin) -> bool {
158        self.origin == other.origin
159    }
160
161    /// <https://html.spec.whatwg.org/multipage/#dom-origin-issamesite>
162    fn IsSameSite(&self, other: &Origin) -> bool {
163        is_same_site(&self.origin, &other.origin)
164    }
165}