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