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/. */
8 #include "nsGlobalWindow.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"
18 #include "nsNetUtil.h"
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
)
44 URL::URL(nsIURI
* aURI
)
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
)
60 nsCOMPtr
<nsIIOService
> ioService(do_GetService(NS_IOSERVICE_CONTRACTID
, &rv
));
67 rv
= ioService
->NewURI(NS_ConvertUTF16toUTF8(aUrl
), nullptr, aBase
.GetURI(),
70 nsAutoString
label(aUrl
);
71 aRv
.ThrowTypeError(MSG_INVALID_URL
, &label
);
75 nsRefPtr
<URL
> url
= new URL(uri
);
79 /* static */ already_AddRefed
<URL
>
80 URL::Constructor(const GlobalObject
& aGlobal
, const nsAString
& aUrl
,
81 const nsAString
& aBase
, ErrorResult
& aRv
)
84 nsCOMPtr
<nsIIOService
> ioService(do_GetService(NS_IOSERVICE_CONTRACTID
, &rv
));
90 nsCOMPtr
<nsIURI
> baseUri
;
91 rv
= ioService
->NewURI(NS_ConvertUTF16toUTF8(aBase
), nullptr, nullptr,
92 getter_AddRefs(baseUri
));
94 nsAutoString
label(aBase
);
95 aRv
.ThrowTypeError(MSG_INVALID_URL
, &label
);
100 rv
= ioService
->NewURI(NS_ConvertUTF16toUTF8(aUrl
), nullptr, baseUri
,
101 getter_AddRefs(uri
));
103 nsAutoString
label(aUrl
);
104 aRv
.ThrowTypeError(MSG_INVALID_URL
, &label
);
108 nsRefPtr
<URL
> url
= new URL(uri
);
113 URL::CreateObjectURL(const GlobalObject
& aGlobal
,
115 const objectURLOptions
& aOptions
,
119 DOMFile
* blob
= static_cast<DOMFile
*>(aBlob
);
122 CreateObjectURLInternal(aGlobal
, blob
->Impl(),
123 NS_LITERAL_CSTRING(BLOBURI_SCHEME
), aOptions
, aResult
,
128 URL::CreateObjectURL(const GlobalObject
& aGlobal
, DOMMediaStream
& aStream
,
129 const mozilla::dom::objectURLOptions
& aOptions
,
133 CreateObjectURLInternal(aGlobal
, &aStream
,
134 NS_LITERAL_CSTRING(MEDIASTREAMURI_SCHEME
), aOptions
,
139 URL::CreateObjectURL(const GlobalObject
& aGlobal
, MediaSource
& aSource
,
140 const objectURLOptions
& aOptions
,
144 CreateObjectURLInternal(aGlobal
, &aSource
,
145 NS_LITERAL_CSTRING(MEDIASOURCEURI_SCHEME
), aOptions
,
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());
158 nsresult rv
= nsHostObjectProtocolHandler::AddDataEntry(aScheme
, aObject
,
165 nsCOMPtr
<nsPIDOMWindow
> w
= do_QueryInterface(aGlobal
.GetAsSupports());
166 nsGlobalWindow
* window
= static_cast<nsGlobalWindow
*>(w
.get());
169 NS_PRECONDITION(window
->IsInnerWindow(), "Should be inner window");
171 if (!window
->GetExtantDoc()) {
172 aError
.Throw(NS_ERROR_INVALID_POINTER
);
176 nsIDocument
* doc
= window
->GetExtantDoc();
178 doc
->RegisterHostObjectUri(url
);
182 CopyASCIItoUTF16(url
, aResult
);
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
);
207 URL::GetHref(nsString
& aHref
, ErrorResult
& aRv
) const
212 nsresult rv
= mURI
->GetSpec(href
);
213 if (NS_SUCCEEDED(rv
)) {
214 CopyUTF8toUTF16(href
, aHref
);
219 URL::SetHref(const nsAString
& aHref
, ErrorResult
& aRv
)
221 nsCString href
= NS_ConvertUTF16toUTF8(aHref
);
224 nsCOMPtr
<nsIIOService
> ioService(do_GetService(NS_IOSERVICE_CONTRACTID
, &rv
));
230 nsCOMPtr
<nsIURI
> uri
;
231 rv
= ioService
->NewURI(href
, nullptr, nullptr, getter_AddRefs(uri
));
233 nsAutoString
label(aHref
);
234 aRv
.ThrowTypeError(MSG_INVALID_URL
, &label
);
239 UpdateURLSearchParams();
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
));
251 nsContentUtils::GetUTFOrigin(principal
, aOrigin
);
256 nsContentUtils::GetUTFOrigin(mURI
, aOrigin
);
260 URL::GetProtocol(nsString
& aProtocol
, ErrorResult
& aRv
) const
263 if (NS_SUCCEEDED(mURI
->GetScheme(protocol
))) {
264 aProtocol
.Truncate();
267 CopyASCIItoUTF16(protocol
, aProtocol
);
268 aProtocol
.Append(char16_t(':'));
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
) {
290 rv
= clone
->SetScheme(NS_ConvertUTF16toUTF8(Substring(start
, iter
)));
291 if (NS_WARN_IF(NS_FAILED(rv
))) {
296 rv
= clone
->GetSpec(href
);
297 if (NS_WARN_IF(NS_FAILED(rv
))) {
301 nsCOMPtr
<nsIURI
> uri
;
302 rv
= NS_NewURI(getter_AddRefs(uri
), href
);
303 if (NS_WARN_IF(NS_FAILED(rv
))) {
310 #define URL_GETTER( value, func ) \
313 nsresult rv = mURI->func(tmp); \
314 if (NS_SUCCEEDED(rv)) { \
315 CopyUTF8toUTF16(tmp, value); \
319 URL::GetUsername(nsString
& aUsername
, ErrorResult
& aRv
) const
321 URL_GETTER(aUsername
, GetUsername
);
325 URL::SetUsername(const nsAString
& aUsername
, ErrorResult
& aRv
)
327 mURI
->SetUsername(NS_ConvertUTF16toUTF8(aUsername
));
331 URL::GetPassword(nsString
& aPassword
, ErrorResult
& aRv
) const
333 URL_GETTER(aPassword
, GetPassword
);
337 URL::SetPassword(const nsAString
& aPassword
, ErrorResult
& aRv
)
339 mURI
->SetPassword(NS_ConvertUTF16toUTF8(aPassword
));
343 URL::GetHost(nsString
& aHost
, ErrorResult
& aRv
) const
345 URL_GETTER(aHost
, GetHostPort
);
349 URL::SetHost(const nsAString
& aHost
, ErrorResult
& aRv
)
351 mURI
->SetHostPort(NS_ConvertUTF16toUTF8(aHost
));
355 URL::URLSearchParamsUpdated(URLSearchParams
* aSearchParams
)
357 MOZ_ASSERT(mSearchParams
);
358 MOZ_ASSERT(mSearchParams
== aSearchParams
);
361 mSearchParams
->Serialize(search
);
362 SetSearchInternal(search
);
366 URL::UpdateURLSearchParams()
368 if (!mSearchParams
) {
372 nsAutoCString search
;
373 nsCOMPtr
<nsIURL
> url(do_QueryInterface(mURI
));
375 nsresult rv
= url
->GetQuery(search
);
377 NS_WARNING("Failed to get the query from a nsIURL.");
381 mSearchParams
->ParseInput(search
, this);
385 URL::GetHostname(nsString
& aHostname
, ErrorResult
& aRv
) const
387 aHostname
.Truncate();
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] != ']'));
397 CopyUTF8toUTF16(tmp
, aHostname
);
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
));
410 URL::GetPort(nsString
& aPort
, ErrorResult
& aRv
) const
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
);
424 URL::SetPort(const nsAString
& aPort
, ErrorResult
& aRv
)
427 nsAutoString
portStr(aPort
);
430 // nsIURI uses -1 as default value.
431 if (!portStr
.IsEmpty()) {
432 port
= portStr
.ToInteger(&rv
);
442 URL::GetPathname(nsString
& aPathname
, ErrorResult
& aRv
) const
444 aPathname
.Truncate();
446 nsCOMPtr
<nsIURL
> url(do_QueryInterface(mURI
));
448 // Do not throw! Not having a valid URI or URL should result in an empty
454 nsresult rv
= url
->GetFilePath(file
);
455 if (NS_SUCCEEDED(rv
)) {
456 CopyUTF8toUTF16(file
, aPathname
);
461 URL::SetPathname(const nsAString
& aPathname
, ErrorResult
& aRv
)
463 nsCOMPtr
<nsIURL
> url(do_QueryInterface(mURI
));
465 // Ignore failures to be compatible with NS4.
469 url
->SetFilePath(NS_ConvertUTF16toUTF8(aPathname
));
473 URL::GetSearch(nsString
& aSearch
, ErrorResult
& aRv
) const
477 nsCOMPtr
<nsIURL
> url(do_QueryInterface(mURI
));
479 // Do not throw! Not having a valid URI or URL should result in an empty
484 nsAutoCString search
;
485 nsresult rv
= url
->GetQuery(search
);
486 if (NS_SUCCEEDED(rv
) && !search
.IsEmpty()) {
487 CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search
, aSearch
);
492 URL::SetSearch(const nsAString
& aSearch
, ErrorResult
& aRv
)
494 SetSearchInternal(aSearch
);
495 UpdateURLSearchParams();
499 URL::SetSearchInternal(const nsAString
& aSearch
)
501 nsCOMPtr
<nsIURL
> url(do_QueryInterface(mURI
));
503 // Ignore failures to be compatible with NS4.
507 url
->SetQuery(NS_ConvertUTF16toUTF8(aSearch
));
513 CreateSearchParamsIfNeeded();
514 return mSearchParams
;
518 URL::SetSearchParams(URLSearchParams
& aSearchParams
)
521 mSearchParams
->RemoveObserver(this);
524 // the observer will be cleared using the cycle collector.
525 mSearchParams
= &aSearchParams
;
526 mSearchParams
->AddObserver(this);
529 mSearchParams
->Serialize(search
);
530 SetSearchInternal(search
);
534 URL::GetHash(nsString
& aHash
, ErrorResult
& aRv
) const
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
);
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
)))
562 URL::CreateSearchParamsIfNeeded()
564 if (!mSearchParams
) {
565 mSearchParams
= new URLSearchParams();
566 mSearchParams
->AddObserver(this);
567 UpdateURLSearchParams();