Bumping manifests a=b2g-bump
[gecko.git] / dom / base / URL.cpp
blobe34731fd846d9aa039fbc62b59aeb2aea2b7a6fe
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/. */
6 #include "URL.h"
8 #include "nsGlobalWindow.h"
9 #include "nsDOMFile.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 "nsNetUtil.h"
19 #include "nsIURL.h"
21 namespace mozilla {
22 namespace dom {
24 NS_IMPL_CYCLE_COLLECTION_CLASS(URL)
26 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(URL)
27 if (tmp->mSearchParams) {
28 tmp->mSearchParams->RemoveObserver(tmp);
29 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSearchParams)
31 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
33 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(URL)
34 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSearchParams)
35 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
37 NS_IMPL_CYCLE_COLLECTING_ADDREF(URL)
38 NS_IMPL_CYCLE_COLLECTING_RELEASE(URL)
40 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URL)
41 NS_INTERFACE_MAP_ENTRY(nsISupports)
42 NS_INTERFACE_MAP_END
44 URL::URL(nsIURI* aURI)
45 : mURI(aURI)
49 JSObject*
50 URL::WrapObject(JSContext* aCx)
52 return URLBinding::Wrap(aCx, this);
55 /* static */ already_AddRefed<URL>
56 URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
57 URL& aBase, ErrorResult& aRv)
59 nsresult rv;
60 nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
61 if (NS_FAILED(rv)) {
62 aRv.Throw(rv);
63 return nullptr;
66 nsCOMPtr<nsIURI> uri;
67 rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aUrl), nullptr, aBase.GetURI(),
68 getter_AddRefs(uri));
69 if (NS_FAILED(rv)) {
70 nsAutoString label(aUrl);
71 aRv.ThrowTypeError(MSG_INVALID_URL, &label);
72 return nullptr;
75 nsRefPtr<URL> url = new URL(uri);
76 return url.forget();
79 /* static */ already_AddRefed<URL>
80 URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
81 const nsAString& aBase, ErrorResult& aRv)
83 nsresult rv;
84 nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
85 if (NS_FAILED(rv)) {
86 aRv.Throw(rv);
87 return nullptr;
90 nsCOMPtr<nsIURI> baseUri;
91 rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aBase), nullptr, nullptr,
92 getter_AddRefs(baseUri));
93 if (NS_FAILED(rv)) {
94 nsAutoString label(aBase);
95 aRv.ThrowTypeError(MSG_INVALID_URL, &label);
96 return nullptr;
99 nsCOMPtr<nsIURI> uri;
100 rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aUrl), nullptr, baseUri,
101 getter_AddRefs(uri));
102 if (NS_FAILED(rv)) {
103 nsAutoString label(aUrl);
104 aRv.ThrowTypeError(MSG_INVALID_URL, &label);
105 return nullptr;
108 nsRefPtr<URL> url = new URL(uri);
109 return url.forget();
112 void
113 URL::CreateObjectURL(const GlobalObject& aGlobal,
114 nsIDOMBlob* aBlob,
115 const objectURLOptions& aOptions,
116 nsString& aResult,
117 ErrorResult& aError)
119 DOMFile* blob = static_cast<DOMFile*>(aBlob);
120 MOZ_ASSERT(blob);
122 CreateObjectURLInternal(aGlobal, blob->Impl(),
123 NS_LITERAL_CSTRING(BLOBURI_SCHEME), aOptions, aResult,
124 aError);
127 void
128 URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
129 const mozilla::dom::objectURLOptions& aOptions,
130 nsString& aResult,
131 ErrorResult& aError)
133 CreateObjectURLInternal(aGlobal, &aStream,
134 NS_LITERAL_CSTRING(MEDIASTREAMURI_SCHEME), aOptions,
135 aResult, aError);
138 void
139 URL::CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource,
140 const objectURLOptions& aOptions,
141 nsString& aResult,
142 ErrorResult& aError)
144 CreateObjectURLInternal(aGlobal, &aSource,
145 NS_LITERAL_CSTRING(MEDIASOURCEURI_SCHEME), aOptions,
146 aResult, aError);
149 void
150 URL::CreateObjectURLInternal(const GlobalObject& aGlobal, nsISupports* aObject,
151 const nsACString& aScheme,
152 const objectURLOptions& aOptions,
153 nsString& aResult, ErrorResult& aError)
155 nsCOMPtr<nsIPrincipal> principal = nsContentUtils::ObjectPrincipal(aGlobal.Get());
157 nsCString url;
158 nsresult rv = nsHostObjectProtocolHandler::AddDataEntry(aScheme, aObject,
159 principal, url);
160 if (NS_FAILED(rv)) {
161 aError.Throw(rv);
162 return;
165 nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.GetAsSupports());
166 nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get());
168 if (window) {
169 NS_PRECONDITION(window->IsInnerWindow(), "Should be inner window");
171 if (!window->GetExtantDoc()) {
172 aError.Throw(NS_ERROR_INVALID_POINTER);
173 return;
176 nsIDocument* doc = window->GetExtantDoc();
177 if (doc) {
178 doc->RegisterHostObjectUri(url);
182 CopyASCIItoUTF16(url, aResult);
185 void
186 URL::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL)
188 nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal.Get());
190 NS_LossyConvertUTF16toASCII asciiurl(aURL);
192 nsIPrincipal* urlPrincipal =
193 nsHostObjectProtocolHandler::GetDataEntryPrincipal(asciiurl);
195 if (urlPrincipal && principal->Subsumes(urlPrincipal)) {
196 nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.GetAsSupports());
197 nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get());
199 if (window && window->GetExtantDoc()) {
200 window->GetExtantDoc()->UnregisterHostObjectUri(asciiurl);
202 nsHostObjectProtocolHandler::RemoveDataEntry(asciiurl);
206 void
207 URL::GetHref(nsString& aHref, ErrorResult& aRv) const
209 aHref.Truncate();
211 nsAutoCString href;
212 nsresult rv = mURI->GetSpec(href);
213 if (NS_SUCCEEDED(rv)) {
214 CopyUTF8toUTF16(href, aHref);
218 void
219 URL::SetHref(const nsAString& aHref, ErrorResult& aRv)
221 nsCString href = NS_ConvertUTF16toUTF8(aHref);
223 nsresult rv;
224 nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
225 if (NS_FAILED(rv)) {
226 aRv.Throw(rv);
227 return;
230 nsCOMPtr<nsIURI> uri;
231 rv = ioService->NewURI(href, nullptr, nullptr, getter_AddRefs(uri));
232 if (NS_FAILED(rv)) {
233 nsAutoString label(aHref);
234 aRv.ThrowTypeError(MSG_INVALID_URL, &label);
235 return;
238 mURI = uri;
239 UpdateURLSearchParams();
242 void
243 URL::GetOrigin(nsString& aOrigin, ErrorResult& aRv) const
245 nsCOMPtr<nsIURIWithPrincipal> uriWithPrincipal = do_QueryInterface(mURI);
246 if (uriWithPrincipal) {
247 nsCOMPtr<nsIPrincipal> principal;
248 uriWithPrincipal->GetPrincipal(getter_AddRefs(principal));
250 if (principal) {
251 nsContentUtils::GetUTFOrigin(principal, aOrigin);
252 return;
256 nsContentUtils::GetUTFOrigin(mURI, aOrigin);
259 void
260 URL::GetProtocol(nsString& aProtocol, ErrorResult& aRv) const
262 nsCString protocol;
263 if (NS_SUCCEEDED(mURI->GetScheme(protocol))) {
264 aProtocol.Truncate();
267 CopyASCIItoUTF16(protocol, aProtocol);
268 aProtocol.Append(char16_t(':'));
271 void
272 URL::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv)
274 nsAString::const_iterator start, end;
275 aProtocol.BeginReading(start);
276 aProtocol.EndReading(end);
277 nsAString::const_iterator iter(start);
279 FindCharInReadable(':', iter, end);
281 // Changing the protocol of a URL, changes the "nature" of the URI
282 // implementation. In order to do this properly, we have to serialize the
283 // existing URL and reparse it in a new object.
284 nsCOMPtr<nsIURI> clone;
285 nsresult rv = mURI->Clone(getter_AddRefs(clone));
286 if (NS_WARN_IF(NS_FAILED(rv)) || !clone) {
287 return;
290 rv = clone->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)));
291 if (NS_WARN_IF(NS_FAILED(rv))) {
292 return;
295 nsAutoCString href;
296 rv = clone->GetSpec(href);
297 if (NS_WARN_IF(NS_FAILED(rv))) {
298 return;
301 nsCOMPtr<nsIURI> uri;
302 rv = NS_NewURI(getter_AddRefs(uri), href);
303 if (NS_WARN_IF(NS_FAILED(rv))) {
304 return;
307 mURI = uri;
310 #define URL_GETTER( value, func ) \
311 value.Truncate(); \
312 nsAutoCString tmp; \
313 nsresult rv = mURI->func(tmp); \
314 if (NS_SUCCEEDED(rv)) { \
315 CopyUTF8toUTF16(tmp, value); \
318 void
319 URL::GetUsername(nsString& aUsername, ErrorResult& aRv) const
321 URL_GETTER(aUsername, GetUsername);
324 void
325 URL::SetUsername(const nsAString& aUsername, ErrorResult& aRv)
327 mURI->SetUsername(NS_ConvertUTF16toUTF8(aUsername));
330 void
331 URL::GetPassword(nsString& aPassword, ErrorResult& aRv) const
333 URL_GETTER(aPassword, GetPassword);
336 void
337 URL::SetPassword(const nsAString& aPassword, ErrorResult& aRv)
339 mURI->SetPassword(NS_ConvertUTF16toUTF8(aPassword));
342 void
343 URL::GetHost(nsString& aHost, ErrorResult& aRv) const
345 URL_GETTER(aHost, GetHostPort);
348 void
349 URL::SetHost(const nsAString& aHost, ErrorResult& aRv)
351 mURI->SetHostPort(NS_ConvertUTF16toUTF8(aHost));
354 void
355 URL::URLSearchParamsUpdated(URLSearchParams* aSearchParams)
357 MOZ_ASSERT(mSearchParams);
358 MOZ_ASSERT(mSearchParams == aSearchParams);
360 nsAutoString search;
361 mSearchParams->Serialize(search);
362 SetSearchInternal(search);
365 void
366 URL::UpdateURLSearchParams()
368 if (!mSearchParams) {
369 return;
372 nsAutoCString search;
373 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
374 if (url) {
375 nsresult rv = url->GetQuery(search);
376 if (NS_FAILED(rv)) {
377 NS_WARNING("Failed to get the query from a nsIURL.");
381 mSearchParams->ParseInput(search, this);
384 void
385 URL::GetHostname(nsString& aHostname, ErrorResult& aRv) const
387 aHostname.Truncate();
388 nsAutoCString tmp;
389 nsresult rv = mURI->GetHost(tmp);
390 if (NS_SUCCEEDED(rv)) {
391 if (tmp.FindChar(':') != -1) { // Escape IPv6 address
392 MOZ_ASSERT(!tmp.Length() ||
393 (tmp[0] !='[' && tmp[tmp.Length() - 1] != ']'));
394 tmp.Insert('[', 0);
395 tmp.Append(']');
397 CopyUTF8toUTF16(tmp, aHostname);
401 void
402 URL::SetHostname(const nsAString& aHostname, ErrorResult& aRv)
404 // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname
405 // The return code is silently ignored
406 mURI->SetHost(NS_ConvertUTF16toUTF8(aHostname));
409 void
410 URL::GetPort(nsString& aPort, ErrorResult& aRv) const
412 aPort.Truncate();
414 int32_t port;
415 nsresult rv = mURI->GetPort(&port);
416 if (NS_SUCCEEDED(rv) && port != -1) {
417 nsAutoString portStr;
418 portStr.AppendInt(port, 10);
419 aPort.Assign(portStr);
423 void
424 URL::SetPort(const nsAString& aPort, ErrorResult& aRv)
426 nsresult rv;
427 nsAutoString portStr(aPort);
428 int32_t port = -1;
430 // nsIURI uses -1 as default value.
431 if (!portStr.IsEmpty()) {
432 port = portStr.ToInteger(&rv);
433 if (NS_FAILED(rv)) {
434 return;
438 mURI->SetPort(port);
441 void
442 URL::GetPathname(nsString& aPathname, ErrorResult& aRv) const
444 aPathname.Truncate();
446 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
447 if (!url) {
448 // Do not throw! Not having a valid URI or URL should result in an empty
449 // string.
450 return;
453 nsAutoCString file;
454 nsresult rv = url->GetFilePath(file);
455 if (NS_SUCCEEDED(rv)) {
456 CopyUTF8toUTF16(file, aPathname);
460 void
461 URL::SetPathname(const nsAString& aPathname, ErrorResult& aRv)
463 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
464 if (!url) {
465 // Ignore failures to be compatible with NS4.
466 return;
469 url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
472 void
473 URL::GetSearch(nsString& aSearch, ErrorResult& aRv) const
475 aSearch.Truncate();
477 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
478 if (!url) {
479 // Do not throw! Not having a valid URI or URL should result in an empty
480 // string.
481 return;
484 nsAutoCString search;
485 nsresult rv = url->GetQuery(search);
486 if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
487 CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
491 void
492 URL::SetSearch(const nsAString& aSearch, ErrorResult& aRv)
494 SetSearchInternal(aSearch);
495 UpdateURLSearchParams();
498 void
499 URL::SetSearchInternal(const nsAString& aSearch)
501 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
502 if (!url) {
503 // Ignore failures to be compatible with NS4.
504 return;
507 url->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
510 URLSearchParams*
511 URL::SearchParams()
513 CreateSearchParamsIfNeeded();
514 return mSearchParams;
517 void
518 URL::SetSearchParams(URLSearchParams& aSearchParams)
520 if (mSearchParams) {
521 mSearchParams->RemoveObserver(this);
524 // the observer will be cleared using the cycle collector.
525 mSearchParams = &aSearchParams;
526 mSearchParams->AddObserver(this);
528 nsAutoString search;
529 mSearchParams->Serialize(search);
530 SetSearchInternal(search);
533 void
534 URL::GetHash(nsString& aHash, ErrorResult& aRv) const
536 aHash.Truncate();
538 nsAutoCString ref;
539 nsresult rv = mURI->GetRef(ref);
540 if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
541 NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
542 aHash.Assign(char16_t('#'));
543 AppendUTF8toUTF16(ref, aHash);
547 void
548 URL::SetHash(const nsAString& aHash, ErrorResult& aRv)
550 mURI->SetRef(NS_ConvertUTF16toUTF8(aHash));
553 bool IsChromeURI(nsIURI* aURI)
555 bool isChrome = false;
556 if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)))
557 return isChrome;
558 return false;
561 void
562 URL::CreateSearchParamsIfNeeded()
564 if (!mSearchParams) {
565 mSearchParams = new URLSearchParams();
566 mSearchParams->AddObserver(this);
567 UpdateURLSearchParams();