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