Skip to main content

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