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::cell::DomRefCell;
6 use dom::bindings::codegen::Bindings::URLBinding::{self, URLMethods};
7 use dom::bindings::error::{Error, ErrorResult, Fallible};
8 use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
9 use dom::bindings::root::{DomRoot, MutNullableDom};
10 use dom::bindings::str::{DOMString, USVString};
11 use dom::blob::Blob;
12 use dom::globalscope::GlobalScope;
13 use dom::urlhelper::UrlHelper;
14 use dom::urlsearchparams::URLSearchParams;
15 use dom_struct::dom_struct;
16 use ipc_channel::ipc;
17 use net_traits::{CoreResourceMsg, IpcSend};
18 use net_traits::blob_url_store::{get_blob_origin, parse_blob_url};
19 use net_traits::filemanager_thread::FileManagerThreadMsg;
20 use servo_url::ServoUrl;
21 use std::default::Default;
22 use uuid::Uuid;
23 
24 // https://url.spec.whatwg.org/#url
25 #[dom_struct]
26 pub struct URL {
27     reflector_: Reflector,
28 
29     // https://url.spec.whatwg.org/#concept-url-url
30     url: DomRefCell<ServoUrl>,
31 
32     // https://url.spec.whatwg.org/#dom-url-searchparams
33     search_params: MutNullableDom<URLSearchParams>,
34 }
35 
36 impl URL {
new_inherited(url: ServoUrl) -> URL37     fn new_inherited(url: ServoUrl) -> URL {
38         URL {
39             reflector_: Reflector::new(),
40             url: DomRefCell::new(url),
41             search_params: Default::default(),
42         }
43     }
44 
new(global: &GlobalScope, url: ServoUrl) -> DomRoot<URL>45     pub fn new(global: &GlobalScope, url: ServoUrl) -> DomRoot<URL> {
46         reflect_dom_object(Box::new(URL::new_inherited(url)),
47                            global, URLBinding::Wrap)
48     }
49 
query_pairs(&self) -> Vec<(String, String)>50     pub fn query_pairs(&self) -> Vec<(String, String)> {
51         self.url.borrow().as_url().query_pairs().into_owned().collect()
52     }
53 
set_query_pairs(&self, pairs: &[(String, String)])54     pub fn set_query_pairs(&self, pairs: &[(String, String)]) {
55         let mut url = self.url.borrow_mut();
56         url.as_mut_url().query_pairs_mut().clear().extend_pairs(pairs);
57     }
58 }
59 
60 impl URL {
61     // https://url.spec.whatwg.org/#constructors
Constructor(global: &GlobalScope, url: USVString, base: Option<USVString>) -> Fallible<DomRoot<URL>>62     pub fn Constructor(global: &GlobalScope, url: USVString,
63                        base: Option<USVString>)
64                        -> Fallible<DomRoot<URL>> {
65         let parsed_base = match base {
66             None => {
67                 // Step 1.
68                 None
69             },
70             Some(base) =>
71                 // Step 2.1.
72                 match ServoUrl::parse(&base.0) {
73                     Ok(base) => Some(base),
74                     Err(error) => {
75                         // Step 2.2.
76                         return Err(Error::Type(format!("could not parse base: {}", error)));
77                     }
78                 }
79         };
80         // Step 3.
81         let parsed_url = match ServoUrl::parse_with_base(parsed_base.as_ref(), &url.0) {
82             Ok(url) => url,
83             Err(error) => {
84                 // Step 4.
85                 return Err(Error::Type(format!("could not parse URL: {}", error)));
86             }
87         };
88         // Step 5: Skip (see step 8 below).
89         // Steps 6-7.
90         let result = URL::new(global, parsed_url);
91         // Step 8: Instead of construcing a new `URLSearchParams` object here, construct it
92         //         on-demand inside `URL::SearchParams`.
93         // Step 9.
94         Ok(result)
95     }
96 
97     // https://w3c.github.io/FileAPI/#dfn-createObjectURL
CreateObjectURL(global: &GlobalScope, blob: &Blob) -> DOMString98     pub fn CreateObjectURL(global: &GlobalScope, blob: &Blob) -> DOMString {
99         // XXX: Second field is an unicode-serialized Origin, it is a temporary workaround
100         //      and should not be trusted. See issue https://github.com/servo/servo/issues/11722
101         let origin = get_blob_origin(&global.get_url());
102 
103         let id = blob.get_blob_url_id();
104 
105         DOMString::from(URL::unicode_serialization_blob_url(&origin, &id))
106     }
107 
108     // https://w3c.github.io/FileAPI/#dfn-revokeObjectURL
RevokeObjectURL(global: &GlobalScope, url: DOMString)109     pub fn RevokeObjectURL(global: &GlobalScope, url: DOMString) {
110         /*
111             If the value provided for the url argument is not a Blob URL OR
112             if the value provided for the url argument does not have an entry in the Blob URL Store,
113 
114             this method call does nothing. User agents may display a message on the error console.
115         */
116         let origin = get_blob_origin(&global.get_url());
117 
118         if let Ok(url) = ServoUrl::parse(&url) {
119              if let Ok((id, _)) = parse_blob_url(&url) {
120                 let resource_threads = global.resource_threads();
121                 let (tx, rx) = ipc::channel().unwrap();
122                 let msg = FileManagerThreadMsg::RevokeBlobURL(id, origin, tx);
123                 let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
124 
125                 let _ = rx.recv().unwrap();
126             }
127         }
128     }
129 
130     // https://w3c.github.io/FileAPI/#unicodeSerializationOfBlobURL
unicode_serialization_blob_url(origin: &str, id: &Uuid) -> String131     fn unicode_serialization_blob_url(origin: &str, id: &Uuid) -> String {
132         // Step 1, 2
133         let mut result = "blob:".to_string();
134 
135         // Step 3
136         result.push_str(origin);
137 
138         // Step 4
139         result.push('/');
140 
141         // Step 5
142         result.push_str(&id.simple().to_string());
143 
144         result
145     }
146 }
147 
148 impl URLMethods for URL {
149     // https://url.spec.whatwg.org/#dom-url-hash
Hash(&self) -> USVString150     fn Hash(&self) -> USVString {
151         UrlHelper::Hash(&self.url.borrow())
152     }
153 
154     // https://url.spec.whatwg.org/#dom-url-hash
SetHash(&self, value: USVString)155     fn SetHash(&self, value: USVString) {
156         UrlHelper::SetHash(&mut self.url.borrow_mut(), value);
157     }
158 
159     // https://url.spec.whatwg.org/#dom-url-host
Host(&self) -> USVString160     fn Host(&self) -> USVString {
161         UrlHelper::Host(&self.url.borrow())
162     }
163 
164     // https://url.spec.whatwg.org/#dom-url-host
SetHost(&self, value: USVString)165     fn SetHost(&self, value: USVString) {
166         UrlHelper::SetHost(&mut self.url.borrow_mut(), value);
167     }
168 
169     // https://url.spec.whatwg.org/#dom-url-hostname
Hostname(&self) -> USVString170     fn Hostname(&self) -> USVString {
171         UrlHelper::Hostname(&self.url.borrow())
172     }
173 
174     // https://url.spec.whatwg.org/#dom-url-hostname
SetHostname(&self, value: USVString)175     fn SetHostname(&self, value: USVString) {
176         UrlHelper::SetHostname(&mut self.url.borrow_mut(), value);
177     }
178 
179     // https://url.spec.whatwg.org/#dom-url-href
Href(&self) -> USVString180     fn Href(&self) -> USVString {
181         UrlHelper::Href(&self.url.borrow())
182     }
183 
184     // https://url.spec.whatwg.org/#dom-url-href
SetHref(&self, value: USVString) -> ErrorResult185     fn SetHref(&self, value: USVString) -> ErrorResult {
186         match ServoUrl::parse(&value.0) {
187             Ok(url) => {
188                 *self.url.borrow_mut() = url;
189                 self.search_params.set(None);  // To be re-initialized in the SearchParams getter.
190                 Ok(())
191             },
192             Err(error) => {
193                 Err(Error::Type(format!("could not parse URL: {}", error)))
194             },
195         }
196     }
197 
198     // https://url.spec.whatwg.org/#dom-url-password
Password(&self) -> USVString199     fn Password(&self) -> USVString {
200         UrlHelper::Password(&self.url.borrow())
201     }
202 
203     // https://url.spec.whatwg.org/#dom-url-password
SetPassword(&self, value: USVString)204     fn SetPassword(&self, value: USVString) {
205         UrlHelper::SetPassword(&mut self.url.borrow_mut(), value);
206     }
207 
208     // https://url.spec.whatwg.org/#dom-url-pathname
Pathname(&self) -> USVString209     fn Pathname(&self) -> USVString {
210         UrlHelper::Pathname(&self.url.borrow())
211     }
212 
213     // https://url.spec.whatwg.org/#dom-url-pathname
SetPathname(&self, value: USVString)214     fn SetPathname(&self, value: USVString) {
215         UrlHelper::SetPathname(&mut self.url.borrow_mut(), value);
216     }
217 
218     // https://url.spec.whatwg.org/#dom-url-port
Port(&self) -> USVString219     fn Port(&self) -> USVString {
220         UrlHelper::Port(&self.url.borrow())
221     }
222 
223     // https://url.spec.whatwg.org/#dom-url-port
SetPort(&self, value: USVString)224     fn SetPort(&self, value: USVString) {
225         UrlHelper::SetPort(&mut self.url.borrow_mut(), value);
226     }
227 
228     // https://url.spec.whatwg.org/#dom-url-protocol
Protocol(&self) -> USVString229     fn Protocol(&self) -> USVString {
230         UrlHelper::Protocol(&self.url.borrow())
231     }
232 
233     // https://url.spec.whatwg.org/#dom-url-protocol
SetProtocol(&self, value: USVString)234     fn SetProtocol(&self, value: USVString) {
235         UrlHelper::SetProtocol(&mut self.url.borrow_mut(), value);
236     }
237 
238     // https://url.spec.whatwg.org/#dom-url-origin
Origin(&self) -> USVString239     fn Origin(&self) -> USVString {
240         UrlHelper::Origin(&self.url.borrow())
241     }
242 
243     // https://url.spec.whatwg.org/#dom-url-search
Search(&self) -> USVString244     fn Search(&self) -> USVString {
245         UrlHelper::Search(&self.url.borrow())
246     }
247 
248     // https://url.spec.whatwg.org/#dom-url-search
SetSearch(&self, value: USVString)249     fn SetSearch(&self, value: USVString) {
250         UrlHelper::SetSearch(&mut self.url.borrow_mut(), value);
251         if let Some(search_params) = self.search_params.get() {
252             search_params.set_list(self.query_pairs());
253         }
254     }
255 
256     // https://url.spec.whatwg.org/#dom-url-searchparams
SearchParams(&self) -> DomRoot<URLSearchParams>257     fn SearchParams(&self) -> DomRoot<URLSearchParams> {
258         self.search_params.or_init(|| {
259             URLSearchParams::new(&self.global(), Some(self))
260         })
261     }
262 
263     // https://url.spec.whatwg.org/#dom-url-href
Stringifier(&self) -> DOMString264     fn Stringifier(&self) -> DOMString {
265         DOMString::from(self.Href().0)
266     }
267 
268     // https://url.spec.whatwg.org/#dom-url-username
Username(&self) -> USVString269     fn Username(&self) -> USVString {
270         UrlHelper::Username(&self.url.borrow())
271     }
272 
273     // https://url.spec.whatwg.org/#dom-url-username
SetUsername(&self, value: USVString)274     fn SetUsername(&self, value: USVString) {
275         UrlHelper::SetUsername(&mut self.url.borrow_mut(), value);
276     }
277 }
278