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 http://mozilla.org/MPL/2.0/. */
4 
5 use dom::bindings::codegen::Bindings::LocationBinding;
6 use dom::bindings::codegen::Bindings::LocationBinding::LocationMethods;
7 use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
8 use dom::bindings::error::{Error, ErrorResult, Fallible};
9 use dom::bindings::reflector::{Reflector, reflect_dom_object};
10 use dom::bindings::root::{Dom, DomRoot};
11 use dom::bindings::str::{DOMString, USVString};
12 use dom::globalscope::GlobalScope;
13 use dom::urlhelper::UrlHelper;
14 use dom::window::Window;
15 use dom_struct::dom_struct;
16 use servo_url::{MutableOrigin, ServoUrl};
17 
18 #[dom_struct]
19 pub struct Location {
20     reflector_: Reflector,
21     window: Dom<Window>,
22 }
23 
24 impl Location {
new_inherited(window: &Window) -> Location25     fn new_inherited(window: &Window) -> Location {
26         Location {
27             reflector_: Reflector::new(),
28             window: Dom::from_ref(window)
29         }
30     }
31 
new(window: &Window) -> DomRoot<Location>32     pub fn new(window: &Window) -> DomRoot<Location> {
33         reflect_dom_object(Box::new(Location::new_inherited(window)),
34                            window,
35                            LocationBinding::Wrap)
36     }
37 
get_url(&self) -> ServoUrl38     fn get_url(&self) -> ServoUrl {
39         self.window.get_url()
40     }
41 
set_url_component(&self, value: USVString, setter: fn(&mut ServoUrl, USVString))42     fn set_url_component(&self, value: USVString,
43                          setter: fn(&mut ServoUrl, USVString)) {
44         let mut url = self.window.get_url();
45         setter(&mut url, value);
46         self.window.load_url(url, false, false, None);
47     }
48 
check_same_origin_domain(&self) -> ErrorResult49     fn check_same_origin_domain(&self) -> ErrorResult {
50         let entry_document = GlobalScope::entry().as_window().Document();
51         let this_document = self.window.Document();
52         if entry_document.origin().same_origin_domain(this_document.origin()) {
53             Ok(())
54         } else {
55             Err(Error::Security)
56         }
57     }
58 
59     // https://html.spec.whatwg.org/multipage/#dom-location-reload
reload_without_origin_check(&self)60     pub fn reload_without_origin_check(&self) {
61         self.window.load_url(self.get_url(), true, true, None);
62     }
63 
64     #[allow(dead_code)]
origin(&self) -> &MutableOrigin65     pub fn origin(&self) -> &MutableOrigin {
66         self.window.origin()
67     }
68 }
69 
70 impl LocationMethods for Location {
71     // https://html.spec.whatwg.org/multipage/#dom-location-assign
Assign(&self, url: USVString) -> ErrorResult72     fn Assign(&self, url: USVString) -> ErrorResult {
73         self.check_same_origin_domain()?;
74         // TODO: per spec, we should use the _API base URL_ specified by the
75         //       _entry settings object_.
76         let base_url = self.window.get_url();
77         if let Ok(url) = base_url.join(&url.0) {
78             self.window.load_url(url, false, false, None);
79             Ok(())
80         } else {
81             Err(Error::Syntax)
82         }
83     }
84 
85     // https://html.spec.whatwg.org/multipage/#dom-location-reload
Reload(&self) -> ErrorResult86     fn Reload(&self) -> ErrorResult {
87         self.check_same_origin_domain()?;
88         self.window.load_url(self.get_url(), true, true, None);
89         Ok(())
90     }
91 
92     // https://html.spec.whatwg.org/multipage/#dom-location-replace
Replace(&self, url: USVString) -> ErrorResult93     fn Replace(&self, url: USVString) -> ErrorResult {
94         // Note: no call to self.check_same_origin_domain()
95         // TODO: per spec, we should use the _API base URL_ specified by the
96         //       _entry settings object_.
97         let base_url = self.window.get_url();
98         if let Ok(url) = base_url.join(&url.0) {
99             self.window.load_url(url, true, false, None);
100             Ok(())
101         } else {
102             Err(Error::Syntax)
103         }
104     }
105 
106     // https://html.spec.whatwg.org/multipage/#dom-location-hash
GetHash(&self) -> Fallible<USVString>107     fn GetHash(&self) -> Fallible<USVString> {
108         self.check_same_origin_domain()?;
109         Ok(UrlHelper::Hash(&self.get_url()))
110     }
111 
112     // https://html.spec.whatwg.org/multipage/#dom-location-hash
SetHash(&self, mut value: USVString) -> ErrorResult113     fn SetHash(&self, mut value: USVString) -> ErrorResult {
114         if value.0.is_empty() {
115             value = USVString("#".to_owned());
116         }
117         self.check_same_origin_domain()?;
118         self.set_url_component(value, UrlHelper::SetHash);
119         Ok(())
120     }
121 
122     // https://html.spec.whatwg.org/multipage/#dom-location-host
GetHost(&self) -> Fallible<USVString>123     fn GetHost(&self) -> Fallible<USVString> {
124         self.check_same_origin_domain()?;
125         Ok(UrlHelper::Host(&self.get_url()))
126     }
127 
128     // https://html.spec.whatwg.org/multipage/#dom-location-host
SetHost(&self, value: USVString) -> ErrorResult129     fn SetHost(&self, value: USVString) -> ErrorResult {
130         self.check_same_origin_domain()?;
131         self.set_url_component(value, UrlHelper::SetHost);
132         Ok(())
133     }
134 
135     // https://html.spec.whatwg.org/multipage/#dom-location-origin
GetOrigin(&self) -> Fallible<USVString>136     fn GetOrigin(&self) -> Fallible<USVString> {
137         self.check_same_origin_domain()?;
138         Ok(UrlHelper::Origin(&self.get_url()))
139     }
140 
141     // https://html.spec.whatwg.org/multipage/#dom-location-hostname
GetHostname(&self) -> Fallible<USVString>142     fn GetHostname(&self) -> Fallible<USVString> {
143         self.check_same_origin_domain()?;
144         Ok(UrlHelper::Hostname(&self.get_url()))
145     }
146 
147     // https://html.spec.whatwg.org/multipage/#dom-location-hostname
SetHostname(&self, value: USVString) -> ErrorResult148     fn SetHostname(&self, value: USVString) -> ErrorResult {
149         self.check_same_origin_domain()?;
150         self.set_url_component(value, UrlHelper::SetHostname);
151         Ok(())
152     }
153 
154     // https://html.spec.whatwg.org/multipage/#dom-location-href
GetHref(&self) -> Fallible<USVString>155     fn GetHref(&self) -> Fallible<USVString> {
156         self.check_same_origin_domain()?;
157         Ok(UrlHelper::Href(&self.get_url()))
158     }
159 
160     // https://html.spec.whatwg.org/multipage/#dom-location-href
SetHref(&self, value: USVString) -> ErrorResult161     fn SetHref(&self, value: USVString) -> ErrorResult {
162         // Note: no call to self.check_same_origin_domain()
163         let url = match self.window.get_url().join(&value.0) {
164             Ok(url) => url,
165             Err(e) => return Err(Error::Type(format!("Couldn't parse URL: {}", e))),
166         };
167         self.window.load_url(url, false, false, None);
168         Ok(())
169     }
170 
171     // https://html.spec.whatwg.org/multipage/#dom-location-pathname
GetPathname(&self) -> Fallible<USVString>172     fn GetPathname(&self) -> Fallible<USVString> {
173         self.check_same_origin_domain()?;
174         Ok(UrlHelper::Pathname(&self.get_url()))
175     }
176 
177     // https://html.spec.whatwg.org/multipage/#dom-location-pathname
SetPathname(&self, value: USVString) -> ErrorResult178     fn SetPathname(&self, value: USVString) -> ErrorResult {
179         self.check_same_origin_domain()?;
180         self.set_url_component(value, UrlHelper::SetPathname);
181         Ok(())
182     }
183 
184     // https://html.spec.whatwg.org/multipage/#dom-location-port
GetPort(&self) -> Fallible<USVString>185     fn GetPort(&self) -> Fallible<USVString> {
186         self.check_same_origin_domain()?;
187         Ok(UrlHelper::Port(&self.get_url()))
188     }
189 
190     // https://html.spec.whatwg.org/multipage/#dom-location-port
SetPort(&self, value: USVString) -> ErrorResult191     fn SetPort(&self, value: USVString) -> ErrorResult {
192         self.check_same_origin_domain()?;
193         self.set_url_component(value, UrlHelper::SetPort);
194         Ok(())
195     }
196 
197     // https://html.spec.whatwg.org/multipage/#dom-location-protocol
GetProtocol(&self) -> Fallible<USVString>198     fn GetProtocol(&self) -> Fallible<USVString> {
199         self.check_same_origin_domain()?;
200         Ok(UrlHelper::Protocol(&self.get_url()))
201     }
202 
203     // https://html.spec.whatwg.org/multipage/#dom-location-protocol
SetProtocol(&self, value: USVString) -> ErrorResult204     fn SetProtocol(&self, value: USVString) -> ErrorResult {
205         self.check_same_origin_domain()?;
206         self.set_url_component(value, UrlHelper::SetProtocol);
207         Ok(())
208     }
209 
210     // https://html.spec.whatwg.org/multipage/#dom-location-href
Stringifier(&self) -> Fallible<DOMString>211     fn Stringifier(&self) -> Fallible<DOMString> {
212         Ok(DOMString::from(self.GetHref()?.0))
213     }
214 
215     // https://html.spec.whatwg.org/multipage/#dom-location-search
GetSearch(&self) -> Fallible<USVString>216     fn GetSearch(&self) -> Fallible<USVString> {
217         self.check_same_origin_domain()?;
218         Ok(UrlHelper::Search(&self.get_url()))
219     }
220 
221     // https://html.spec.whatwg.org/multipage/#dom-location-search
SetSearch(&self, value: USVString) -> ErrorResult222     fn SetSearch(&self, value: USVString) -> ErrorResult {
223         self.check_same_origin_domain()?;
224         self.set_url_component(value, UrlHelper::SetSearch);
225         Ok(())
226     }
227 }
228