|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "URL.h" |
|
7 |
|
8 #include "nsGlobalWindow.h" |
|
9 #include "nsIDOMFile.h" |
|
10 #include "DOMMediaStream.h" |
|
11 #include "mozilla/dom/MediaSource.h" |
|
12 #include "mozilla/dom/URLBinding.h" |
|
13 #include "nsHostObjectProtocolHandler.h" |
|
14 #include "nsServiceManagerUtils.h" |
|
15 #include "nsIIOService.h" |
|
16 #include "nsEscape.h" |
|
17 #include "nsNetCID.h" |
|
18 #include "nsIURL.h" |
|
19 |
|
20 namespace mozilla { |
|
21 namespace dom { |
|
22 |
|
23 NS_IMPL_CYCLE_COLLECTION_CLASS(URL) |
|
24 |
|
25 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(URL) |
|
26 if (tmp->mSearchParams) { |
|
27 tmp->mSearchParams->RemoveObserver(tmp); |
|
28 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSearchParams) |
|
29 } |
|
30 NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
|
31 |
|
32 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(URL) |
|
33 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSearchParams) |
|
34 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
|
35 |
|
36 NS_IMPL_CYCLE_COLLECTING_ADDREF(URL) |
|
37 NS_IMPL_CYCLE_COLLECTING_RELEASE(URL) |
|
38 |
|
39 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URL) |
|
40 NS_INTERFACE_MAP_ENTRY(nsISupports) |
|
41 NS_INTERFACE_MAP_END |
|
42 |
|
43 URL::URL(nsIURI* aURI) |
|
44 : mURI(aURI) |
|
45 { |
|
46 } |
|
47 |
|
48 JSObject* |
|
49 URL::WrapObject(JSContext* aCx) |
|
50 { |
|
51 return URLBinding::Wrap(aCx, this); |
|
52 } |
|
53 |
|
54 /* static */ already_AddRefed<URL> |
|
55 URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl, |
|
56 URL& aBase, ErrorResult& aRv) |
|
57 { |
|
58 nsresult rv; |
|
59 nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); |
|
60 if (NS_FAILED(rv)) { |
|
61 aRv.Throw(rv); |
|
62 return nullptr; |
|
63 } |
|
64 |
|
65 nsCOMPtr<nsIURI> uri; |
|
66 rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aUrl), nullptr, aBase.GetURI(), |
|
67 getter_AddRefs(uri)); |
|
68 if (NS_FAILED(rv)) { |
|
69 nsAutoString label(aUrl); |
|
70 aRv.ThrowTypeError(MSG_INVALID_URL, &label); |
|
71 return nullptr; |
|
72 } |
|
73 |
|
74 nsRefPtr<URL> url = new URL(uri); |
|
75 return url.forget(); |
|
76 } |
|
77 |
|
78 /* static */ already_AddRefed<URL> |
|
79 URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl, |
|
80 const nsAString& aBase, ErrorResult& aRv) |
|
81 { |
|
82 nsresult rv; |
|
83 nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); |
|
84 if (NS_FAILED(rv)) { |
|
85 aRv.Throw(rv); |
|
86 return nullptr; |
|
87 } |
|
88 |
|
89 nsCOMPtr<nsIURI> baseUri; |
|
90 rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aBase), nullptr, nullptr, |
|
91 getter_AddRefs(baseUri)); |
|
92 if (NS_FAILED(rv)) { |
|
93 nsAutoString label(aBase); |
|
94 aRv.ThrowTypeError(MSG_INVALID_URL, &label); |
|
95 return nullptr; |
|
96 } |
|
97 |
|
98 nsCOMPtr<nsIURI> uri; |
|
99 rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aUrl), nullptr, baseUri, |
|
100 getter_AddRefs(uri)); |
|
101 if (NS_FAILED(rv)) { |
|
102 nsAutoString label(aUrl); |
|
103 aRv.ThrowTypeError(MSG_INVALID_URL, &label); |
|
104 return nullptr; |
|
105 } |
|
106 |
|
107 nsRefPtr<URL> url = new URL(uri); |
|
108 return url.forget(); |
|
109 } |
|
110 |
|
111 void |
|
112 URL::CreateObjectURL(const GlobalObject& aGlobal, |
|
113 nsIDOMBlob* aBlob, |
|
114 const objectURLOptions& aOptions, |
|
115 nsString& aResult, |
|
116 ErrorResult& aError) |
|
117 { |
|
118 CreateObjectURLInternal(aGlobal, aBlob, |
|
119 NS_LITERAL_CSTRING(BLOBURI_SCHEME), aOptions, aResult, |
|
120 aError); |
|
121 } |
|
122 |
|
123 void |
|
124 URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream, |
|
125 const mozilla::dom::objectURLOptions& aOptions, |
|
126 nsString& aResult, |
|
127 ErrorResult& aError) |
|
128 { |
|
129 CreateObjectURLInternal(aGlobal, &aStream, |
|
130 NS_LITERAL_CSTRING(MEDIASTREAMURI_SCHEME), aOptions, |
|
131 aResult, aError); |
|
132 } |
|
133 |
|
134 void |
|
135 URL::CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource, |
|
136 const objectURLOptions& aOptions, |
|
137 nsString& aResult, |
|
138 ErrorResult& aError) |
|
139 { |
|
140 CreateObjectURLInternal(aGlobal, &aSource, |
|
141 NS_LITERAL_CSTRING(MEDIASOURCEURI_SCHEME), aOptions, |
|
142 aResult, aError); |
|
143 } |
|
144 |
|
145 void |
|
146 URL::CreateObjectURLInternal(const GlobalObject& aGlobal, nsISupports* aObject, |
|
147 const nsACString& aScheme, |
|
148 const objectURLOptions& aOptions, |
|
149 nsString& aResult, ErrorResult& aError) |
|
150 { |
|
151 nsCOMPtr<nsIPrincipal> principal = nsContentUtils::GetObjectPrincipal(aGlobal.Get()); |
|
152 |
|
153 nsCString url; |
|
154 nsresult rv = nsHostObjectProtocolHandler::AddDataEntry(aScheme, aObject, |
|
155 principal, url); |
|
156 if (NS_FAILED(rv)) { |
|
157 aError.Throw(rv); |
|
158 return; |
|
159 } |
|
160 |
|
161 nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.GetAsSupports()); |
|
162 nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get()); |
|
163 |
|
164 if (window) { |
|
165 NS_PRECONDITION(window->IsInnerWindow(), "Should be inner window"); |
|
166 |
|
167 if (!window->GetExtantDoc()) { |
|
168 aError.Throw(NS_ERROR_INVALID_POINTER); |
|
169 return; |
|
170 } |
|
171 |
|
172 nsIDocument* doc = window->GetExtantDoc(); |
|
173 if (doc) { |
|
174 doc->RegisterHostObjectUri(url); |
|
175 } |
|
176 } |
|
177 |
|
178 CopyASCIItoUTF16(url, aResult); |
|
179 } |
|
180 |
|
181 void |
|
182 URL::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL) |
|
183 { |
|
184 nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aGlobal.Get()); |
|
185 |
|
186 NS_LossyConvertUTF16toASCII asciiurl(aURL); |
|
187 |
|
188 nsIPrincipal* urlPrincipal = |
|
189 nsHostObjectProtocolHandler::GetDataEntryPrincipal(asciiurl); |
|
190 |
|
191 if (urlPrincipal && principal->Subsumes(urlPrincipal)) { |
|
192 nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.GetAsSupports()); |
|
193 nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get()); |
|
194 |
|
195 if (window && window->GetExtantDoc()) { |
|
196 window->GetExtantDoc()->UnregisterHostObjectUri(asciiurl); |
|
197 } |
|
198 nsHostObjectProtocolHandler::RemoveDataEntry(asciiurl); |
|
199 } |
|
200 } |
|
201 |
|
202 void |
|
203 URL::GetHref(nsString& aHref) const |
|
204 { |
|
205 aHref.Truncate(); |
|
206 |
|
207 nsAutoCString href; |
|
208 nsresult rv = mURI->GetSpec(href); |
|
209 if (NS_SUCCEEDED(rv)) { |
|
210 CopyUTF8toUTF16(href, aHref); |
|
211 } |
|
212 } |
|
213 |
|
214 void |
|
215 URL::SetHref(const nsAString& aHref, ErrorResult& aRv) |
|
216 { |
|
217 nsCString href = NS_ConvertUTF16toUTF8(aHref); |
|
218 |
|
219 nsresult rv; |
|
220 nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); |
|
221 if (NS_FAILED(rv)) { |
|
222 aRv.Throw(rv); |
|
223 return; |
|
224 } |
|
225 |
|
226 nsCOMPtr<nsIURI> uri; |
|
227 rv = ioService->NewURI(href, nullptr, nullptr, getter_AddRefs(uri)); |
|
228 if (NS_FAILED(rv)) { |
|
229 nsAutoString label(aHref); |
|
230 aRv.ThrowTypeError(MSG_INVALID_URL, &label); |
|
231 return; |
|
232 } |
|
233 |
|
234 mURI = uri; |
|
235 UpdateURLSearchParams(); |
|
236 } |
|
237 |
|
238 void |
|
239 URL::GetOrigin(nsString& aOrigin) const |
|
240 { |
|
241 nsContentUtils::GetUTFNonNullOrigin(mURI, aOrigin); |
|
242 } |
|
243 |
|
244 void |
|
245 URL::GetProtocol(nsString& aProtocol) const |
|
246 { |
|
247 nsCString protocol; |
|
248 if (NS_SUCCEEDED(mURI->GetScheme(protocol))) { |
|
249 aProtocol.Truncate(); |
|
250 } |
|
251 |
|
252 CopyASCIItoUTF16(protocol, aProtocol); |
|
253 aProtocol.Append(char16_t(':')); |
|
254 } |
|
255 |
|
256 void |
|
257 URL::SetProtocol(const nsAString& aProtocol) |
|
258 { |
|
259 nsAString::const_iterator start, end; |
|
260 aProtocol.BeginReading(start); |
|
261 aProtocol.EndReading(end); |
|
262 nsAString::const_iterator iter(start); |
|
263 |
|
264 FindCharInReadable(':', iter, end); |
|
265 mURI->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter))); |
|
266 } |
|
267 |
|
268 #define URL_GETTER( value, func ) \ |
|
269 value.Truncate(); \ |
|
270 nsAutoCString tmp; \ |
|
271 nsresult rv = mURI->func(tmp); \ |
|
272 if (NS_SUCCEEDED(rv)) { \ |
|
273 CopyUTF8toUTF16(tmp, value); \ |
|
274 } |
|
275 |
|
276 void |
|
277 URL::GetUsername(nsString& aUsername) const |
|
278 { |
|
279 URL_GETTER(aUsername, GetUsername); |
|
280 } |
|
281 |
|
282 void |
|
283 URL::SetUsername(const nsAString& aUsername) |
|
284 { |
|
285 mURI->SetUsername(NS_ConvertUTF16toUTF8(aUsername)); |
|
286 } |
|
287 |
|
288 void |
|
289 URL::GetPassword(nsString& aPassword) const |
|
290 { |
|
291 URL_GETTER(aPassword, GetPassword); |
|
292 } |
|
293 |
|
294 void |
|
295 URL::SetPassword(const nsAString& aPassword) |
|
296 { |
|
297 mURI->SetPassword(NS_ConvertUTF16toUTF8(aPassword)); |
|
298 } |
|
299 |
|
300 void |
|
301 URL::GetHost(nsString& aHost) const |
|
302 { |
|
303 URL_GETTER(aHost, GetHostPort); |
|
304 } |
|
305 |
|
306 void |
|
307 URL::SetHost(const nsAString& aHost) |
|
308 { |
|
309 mURI->SetHostPort(NS_ConvertUTF16toUTF8(aHost)); |
|
310 } |
|
311 |
|
312 void |
|
313 URL::URLSearchParamsUpdated() |
|
314 { |
|
315 MOZ_ASSERT(mSearchParams); |
|
316 |
|
317 nsAutoString search; |
|
318 mSearchParams->Serialize(search); |
|
319 SetSearchInternal(search); |
|
320 } |
|
321 |
|
322 void |
|
323 URL::UpdateURLSearchParams() |
|
324 { |
|
325 if (!mSearchParams) { |
|
326 return; |
|
327 } |
|
328 |
|
329 nsAutoCString search; |
|
330 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI)); |
|
331 if (url) { |
|
332 nsresult rv = url->GetQuery(search); |
|
333 if (NS_FAILED(rv)) { |
|
334 NS_WARNING("Failed to get the query from a nsIURL."); |
|
335 } |
|
336 } |
|
337 |
|
338 mSearchParams->ParseInput(search, this); |
|
339 } |
|
340 |
|
341 void |
|
342 URL::GetHostname(nsString& aHostname) const |
|
343 { |
|
344 URL_GETTER(aHostname, GetHost); |
|
345 } |
|
346 |
|
347 void |
|
348 URL::SetHostname(const nsAString& aHostname) |
|
349 { |
|
350 // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname |
|
351 // The return code is silently ignored |
|
352 mURI->SetHost(NS_ConvertUTF16toUTF8(aHostname)); |
|
353 } |
|
354 |
|
355 void |
|
356 URL::GetPort(nsString& aPort) const |
|
357 { |
|
358 aPort.Truncate(); |
|
359 |
|
360 int32_t port; |
|
361 nsresult rv = mURI->GetPort(&port); |
|
362 if (NS_SUCCEEDED(rv) && port != -1) { |
|
363 nsAutoString portStr; |
|
364 portStr.AppendInt(port, 10); |
|
365 aPort.Assign(portStr); |
|
366 } |
|
367 } |
|
368 |
|
369 void |
|
370 URL::SetPort(const nsAString& aPort) |
|
371 { |
|
372 nsresult rv; |
|
373 nsAutoString portStr(aPort); |
|
374 int32_t port = -1; |
|
375 |
|
376 // nsIURI uses -1 as default value. |
|
377 if (!portStr.IsEmpty()) { |
|
378 port = portStr.ToInteger(&rv); |
|
379 if (NS_FAILED(rv)) { |
|
380 return; |
|
381 } |
|
382 } |
|
383 |
|
384 mURI->SetPort(port); |
|
385 } |
|
386 |
|
387 void |
|
388 URL::GetPathname(nsString& aPathname) const |
|
389 { |
|
390 aPathname.Truncate(); |
|
391 |
|
392 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI)); |
|
393 if (!url) { |
|
394 // Do not throw! Not having a valid URI or URL should result in an empty |
|
395 // string. |
|
396 return; |
|
397 } |
|
398 |
|
399 nsAutoCString file; |
|
400 nsresult rv = url->GetFilePath(file); |
|
401 if (NS_SUCCEEDED(rv)) { |
|
402 CopyUTF8toUTF16(file, aPathname); |
|
403 } |
|
404 } |
|
405 |
|
406 void |
|
407 URL::SetPathname(const nsAString& aPathname) |
|
408 { |
|
409 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI)); |
|
410 if (!url) { |
|
411 // Ignore failures to be compatible with NS4. |
|
412 return; |
|
413 } |
|
414 |
|
415 url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)); |
|
416 } |
|
417 |
|
418 void |
|
419 URL::GetSearch(nsString& aSearch) const |
|
420 { |
|
421 aSearch.Truncate(); |
|
422 |
|
423 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI)); |
|
424 if (!url) { |
|
425 // Do not throw! Not having a valid URI or URL should result in an empty |
|
426 // string. |
|
427 return; |
|
428 } |
|
429 |
|
430 nsAutoCString search; |
|
431 nsresult rv = url->GetQuery(search); |
|
432 if (NS_SUCCEEDED(rv) && !search.IsEmpty()) { |
|
433 CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch); |
|
434 } |
|
435 } |
|
436 |
|
437 void |
|
438 URL::SetSearch(const nsAString& aSearch) |
|
439 { |
|
440 SetSearchInternal(aSearch); |
|
441 UpdateURLSearchParams(); |
|
442 } |
|
443 |
|
444 void |
|
445 URL::SetSearchInternal(const nsAString& aSearch) |
|
446 { |
|
447 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI)); |
|
448 if (!url) { |
|
449 // Ignore failures to be compatible with NS4. |
|
450 return; |
|
451 } |
|
452 |
|
453 url->SetQuery(NS_ConvertUTF16toUTF8(aSearch)); |
|
454 } |
|
455 |
|
456 URLSearchParams* |
|
457 URL::SearchParams() |
|
458 { |
|
459 CreateSearchParamsIfNeeded(); |
|
460 return mSearchParams; |
|
461 } |
|
462 |
|
463 void |
|
464 URL::SetSearchParams(URLSearchParams& aSearchParams) |
|
465 { |
|
466 if (mSearchParams) { |
|
467 mSearchParams->RemoveObserver(this); |
|
468 } |
|
469 |
|
470 // the observer will be cleared using the cycle collector. |
|
471 mSearchParams = &aSearchParams; |
|
472 mSearchParams->AddObserver(this); |
|
473 |
|
474 nsAutoString search; |
|
475 mSearchParams->Serialize(search); |
|
476 SetSearchInternal(search); |
|
477 } |
|
478 |
|
479 void |
|
480 URL::GetHash(nsString& aHash) const |
|
481 { |
|
482 aHash.Truncate(); |
|
483 |
|
484 nsAutoCString ref; |
|
485 nsresult rv = mURI->GetRef(ref); |
|
486 if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) { |
|
487 NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes! |
|
488 aHash.Assign(char16_t('#')); |
|
489 AppendUTF8toUTF16(ref, aHash); |
|
490 } |
|
491 } |
|
492 |
|
493 void |
|
494 URL::SetHash(const nsAString& aHash) |
|
495 { |
|
496 mURI->SetRef(NS_ConvertUTF16toUTF8(aHash)); |
|
497 } |
|
498 |
|
499 bool IsChromeURI(nsIURI* aURI) |
|
500 { |
|
501 bool isChrome = false; |
|
502 if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome))) |
|
503 return isChrome; |
|
504 return false; |
|
505 } |
|
506 |
|
507 void |
|
508 URL::CreateSearchParamsIfNeeded() |
|
509 { |
|
510 if (!mSearchParams) { |
|
511 mSearchParams = new URLSearchParams(); |
|
512 mSearchParams->AddObserver(this); |
|
513 UpdateURLSearchParams(); |
|
514 } |
|
515 } |
|
516 |
|
517 } |
|
518 } |