1use 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#[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 fn extract_an_origin_from_platform_object(
58 value: HandleValue,
59 cx: JSContext,
60 current_global: &GlobalScope,
61 ) -> Option<ImmutableOrigin> {
62 if let Ok(origin_obj) = root_from_handlevalue::<Origin>(value, cx) {
64 return Some(origin_obj.origin.clone());
65 }
66
67 if let Ok(url_obj) = root_from_handlevalue::<URL>(value, cx) {
69 return Some(url_obj.origin());
70 }
71
72 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 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 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 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 fn From(cx: JSContext, global: &GlobalScope, value: HandleValue) -> Fallible<DomRoot<Origin>> {
115 let can_gc = CanGc::note();
116
117 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 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 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 Err(Error::Type(
147 "Value must be a string or a platform object with an origin".to_string(),
148 ))
149 }
150
151 fn Opaque(&self) -> bool {
153 !self.origin.is_tuple()
154 }
155
156 fn IsSameOrigin(&self, other: &Origin) -> bool {
158 self.origin == other.origin
159 }
160
161 fn IsSameSite(&self, other: &Origin) -> bool {
163 is_same_site(&self.origin, &other.origin)
164 }
165}