1use std::cell::RefCell;
6use std::net::IpAddr;
7use std::rc::Rc;
8
9use malloc_size_of::malloc_size_of_is_0;
10use malloc_size_of_derive::MallocSizeOf;
11use serde::{Deserialize, Serialize};
12use url::{Host, Origin};
13use uuid::Uuid;
14
15#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
17pub enum ImmutableOrigin {
18 Opaque(OpaqueOrigin),
20
21 Tuple(String, Host, u16),
23}
24
25pub trait DomainComparable {
26 fn has_domain(&self) -> bool;
27 fn immutable(&self) -> &ImmutableOrigin;
28}
29
30impl DomainComparable for OriginSnapshot {
31 fn has_domain(&self) -> bool {
32 self.1.is_some()
33 }
34 fn immutable(&self) -> &ImmutableOrigin {
35 &self.0
36 }
37}
38
39impl DomainComparable for MutableOrigin {
40 fn has_domain(&self) -> bool {
41 (self.0).1.borrow().is_some()
42 }
43 fn immutable(&self) -> &ImmutableOrigin {
44 &(self.0).0
45 }
46}
47
48impl ImmutableOrigin {
49 pub fn new(origin: Origin) -> ImmutableOrigin {
50 match origin {
51 Origin::Opaque(_) => ImmutableOrigin::new_opaque(),
52 Origin::Tuple(scheme, host, port) => ImmutableOrigin::Tuple(scheme, host, port),
53 }
54 }
55
56 pub fn same_origin(&self, other: &impl DomainComparable) -> bool {
57 self == other.immutable()
58 }
59
60 pub fn same_origin_domain(&self, other: &impl DomainComparable) -> bool {
61 !other.has_domain() && self == other.immutable()
62 }
63
64 pub fn new_opaque() -> ImmutableOrigin {
66 ImmutableOrigin::Opaque(OpaqueOrigin::Opaque(Uuid::new_v4()))
67 }
68
69 pub fn new_opaque_data_url_worker() -> ImmutableOrigin {
71 ImmutableOrigin::Opaque(OpaqueOrigin::SecureWorkerFromDataUrl(Uuid::new_v4()))
72 }
73
74 pub fn scheme(&self) -> Option<&str> {
75 match *self {
76 ImmutableOrigin::Opaque(_) => None,
77 ImmutableOrigin::Tuple(ref scheme, _, _) => Some(&**scheme),
78 }
79 }
80
81 pub fn host(&self) -> Option<&Host> {
82 match *self {
83 ImmutableOrigin::Opaque(_) => None,
84 ImmutableOrigin::Tuple(_, ref host, _) => Some(host),
85 }
86 }
87
88 pub fn port(&self) -> Option<u16> {
89 match *self {
90 ImmutableOrigin::Opaque(_) => None,
91 ImmutableOrigin::Tuple(_, _, port) => Some(port),
92 }
93 }
94
95 pub fn into_url_origin(self) -> Origin {
96 match self {
97 ImmutableOrigin::Opaque(_) => Origin::new_opaque(),
98 ImmutableOrigin::Tuple(scheme, host, port) => Origin::Tuple(scheme, host, port),
99 }
100 }
101
102 pub fn is_tuple(&self) -> bool {
105 match *self {
106 ImmutableOrigin::Opaque(..) => false,
107 ImmutableOrigin::Tuple(..) => true,
108 }
109 }
110
111 pub fn is_potentially_trustworthy(&self) -> bool {
113 if matches!(self, ImmutableOrigin::Opaque(_)) {
115 return false;
116 }
117
118 if let ImmutableOrigin::Tuple(scheme, host, _) = self {
119 if scheme == "https" || scheme == "wss" {
121 return true;
122 }
123 if scheme == "file" {
125 return true;
126 }
127
128 if let Ok(ip_addr) = host.to_string().parse::<IpAddr>() {
131 return ip_addr.is_loopback();
132 }
133 if let Host::Domain(domain) = host {
139 if domain == "localhost" || domain.ends_with(".localhost") {
140 return true;
141 }
142 }
143 }
144 false
146 }
147
148 pub fn ascii_serialization(&self) -> String {
150 self.clone().into_url_origin().ascii_serialization()
151 }
152}
153
154#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
156pub enum OpaqueOrigin {
157 Opaque(Uuid),
158 SecureWorkerFromDataUrl(Uuid),
162}
163malloc_size_of_is_0!(OpaqueOrigin);
164
165#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
167pub struct OriginSnapshot(ImmutableOrigin, Option<Host>);
168
169impl OriginSnapshot {
170 pub fn immutable(&self) -> &ImmutableOrigin {
171 &self.0
172 }
173
174 pub fn has_domain(&self) -> bool {
175 self.1.is_some()
176 }
177
178 pub fn same_origin(&self, other: &impl DomainComparable) -> bool {
179 self.immutable() == other.immutable()
180 }
181
182 pub fn same_origin_domain(&self, other: &OriginSnapshot) -> bool {
183 if let Some(ref self_domain) = self.1 {
184 if let Some(ref other_domain) = other.1 {
185 self_domain == other_domain && self.0.scheme() == other.0.scheme()
186 } else {
187 false
188 }
189 } else {
190 self.0.same_origin_domain(other)
191 }
192 }
193}
194
195#[derive(Clone, Debug, Deserialize, Serialize)]
197pub struct MutableOrigin(Rc<(ImmutableOrigin, RefCell<Option<Host>>)>);
198
199malloc_size_of_is_0!(MutableOrigin);
200
201impl MutableOrigin {
202 pub fn snapshot(&self) -> OriginSnapshot {
203 OriginSnapshot(self.0.0.clone(), self.0.1.borrow().clone())
204 }
205
206 pub fn new(origin: ImmutableOrigin) -> MutableOrigin {
207 MutableOrigin(Rc::new((origin, RefCell::new(None))))
208 }
209
210 pub fn immutable(&self) -> &ImmutableOrigin {
211 &(self.0).0
212 }
213
214 pub fn is_tuple(&self) -> bool {
215 self.immutable().is_tuple()
216 }
217
218 pub fn scheme(&self) -> Option<&str> {
219 self.immutable().scheme()
220 }
221
222 pub fn host(&self) -> Option<&Host> {
223 self.immutable().host()
224 }
225
226 pub fn port(&self) -> Option<u16> {
227 self.immutable().port()
228 }
229
230 pub fn same_origin(&self, other: &MutableOrigin) -> bool {
231 self.immutable() == other.immutable()
232 }
233
234 pub fn same_origin_domain(&self, other: &MutableOrigin) -> bool {
235 if let Some(ref self_domain) = *(self.0).1.borrow() {
236 if let Some(ref other_domain) = *(other.0).1.borrow() {
237 self_domain == other_domain &&
238 self.immutable().scheme() == other.immutable().scheme()
239 } else {
240 false
241 }
242 } else {
243 self.immutable().same_origin_domain(other)
244 }
245 }
246
247 pub fn domain(&self) -> Option<Host> {
248 (self.0).1.borrow().clone()
249 }
250
251 pub fn set_domain(&self, domain: Host) {
252 *(self.0).1.borrow_mut() = Some(domain);
253 }
254
255 pub fn has_domain(&self) -> bool {
256 (self.0).1.borrow().is_some()
257 }
258
259 pub fn effective_domain(&self) -> Option<Host> {
261 if !self.is_tuple() {
263 return None;
264 }
265 self.immutable()
266 .host()
267 .map(|host| self.domain().unwrap_or_else(|| host.clone()))
270 }
271}