1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "URLMainThread.h"
11 #include "MainThreadUtils.h"
12 #include "mozilla/dom/URLBinding.h"
13 #include "mozilla/dom/BindingUtils.h"
14 #include "nsContentUtils.h"
15 #include "mozilla/dom/Document.h"
16 #include "nsIURIMutator.h"
17 #include "nsNetUtil.h"
22 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URL
, mParent
, mSearchParams
)
24 NS_IMPL_CYCLE_COLLECTING_ADDREF(URL
)
25 NS_IMPL_CYCLE_COLLECTING_RELEASE(URL
)
27 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URL
)
28 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
29 NS_INTERFACE_MAP_ENTRY(nsISupports
)
32 JSObject
* URL::WrapObject(JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
33 return URL_Binding::Wrap(aCx
, this, aGivenProto
);
37 already_AddRefed
<URL
> URL::Constructor(const GlobalObject
& aGlobal
,
38 const nsAString
& aURL
,
39 const Optional
<nsAString
>& aBase
,
41 if (aBase
.WasPassed()) {
42 return Constructor(aGlobal
.GetAsSupports(), aURL
, aBase
.Value(), aRv
);
45 return Constructor(aGlobal
.GetAsSupports(), aURL
, nullptr, aRv
);
49 already_AddRefed
<URL
> URL::Constructor(nsISupports
* aParent
,
50 const nsAString
& aURL
,
51 const nsAString
& aBase
,
53 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
55 if (!AppendUTF16toUTF8(aBase
, base
, fallible
)) {
56 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
60 nsCOMPtr
<nsIURI
> baseUri
;
61 nsresult rv
= NS_NewURI(getter_AddRefs(baseUri
), base
);
62 if (NS_WARN_IF(NS_FAILED(rv
))) {
63 aRv
.ThrowTypeError
<MSG_INVALID_URL
>(base
);
67 return Constructor(aParent
, aURL
, baseUri
, aRv
);
71 already_AddRefed
<URL
> URL::Constructor(nsISupports
* aParent
,
72 const nsAString
& aURL
, nsIURI
* aBase
,
74 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
76 if (!AppendUTF16toUTF8(aURL
, urlStr
, fallible
)) {
77 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
82 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), urlStr
, nullptr, aBase
);
84 // No need to warn in this case. It's common to use the URL constructor
85 // to determine if a URL is valid and an exception will be propagated.
86 aRv
.ThrowTypeError
<MSG_INVALID_URL
>(urlStr
);
90 RefPtr
<URL
> url
= new URL(aParent
);
91 url
->SetURI(uri
.forget());
95 void URL::CreateObjectURL(const GlobalObject
& aGlobal
, Blob
& aBlob
,
96 nsAString
& aResult
, ErrorResult
& aRv
) {
97 if (NS_IsMainThread()) {
98 URLMainThread::CreateObjectURL(aGlobal
, aBlob
, aResult
, aRv
);
100 URLWorker::CreateObjectURL(aGlobal
, aBlob
, aResult
, aRv
);
104 void URL::CreateObjectURL(const GlobalObject
& aGlobal
, MediaSource
& aSource
,
105 nsAString
& aResult
, ErrorResult
& aRv
) {
106 MOZ_ASSERT(NS_IsMainThread());
107 URLMainThread::CreateObjectURL(aGlobal
, aSource
, aResult
, aRv
);
110 void URL::RevokeObjectURL(const GlobalObject
& aGlobal
, const nsAString
& aURL
,
112 if (aURL
.Contains('#')) {
113 // Don't revoke URLs that contain fragments.
117 if (NS_IsMainThread()) {
118 URLMainThread::RevokeObjectURL(aGlobal
, aURL
, aRv
);
120 URLWorker::RevokeObjectURL(aGlobal
, aURL
, aRv
);
124 bool URL::IsValidURL(const GlobalObject
& aGlobal
, const nsAString
& aURL
,
126 if (NS_IsMainThread()) {
127 return URLMainThread::IsValidURL(aGlobal
, aURL
, aRv
);
129 return URLWorker::IsValidURL(aGlobal
, aURL
, aRv
);
132 URLSearchParams
* URL::SearchParams() {
133 CreateSearchParamsIfNeeded();
134 return mSearchParams
;
137 bool IsChromeURI(nsIURI
* aURI
) { return aURI
->SchemeIs("chrome"); }
139 void URL::CreateSearchParamsIfNeeded() {
140 if (!mSearchParams
) {
141 mSearchParams
= new URLSearchParams(mParent
, this);
142 UpdateURLSearchParams();
146 void URL::SetSearch(const nsAString
& aSearch
) {
147 SetSearchInternal(aSearch
);
148 UpdateURLSearchParams();
151 void URL::URLSearchParamsUpdated(URLSearchParams
* aSearchParams
) {
152 MOZ_ASSERT(mSearchParams
);
153 MOZ_ASSERT(mSearchParams
== aSearchParams
);
156 mSearchParams
->Serialize(search
);
158 SetSearchInternal(search
);
161 #define URL_GETTER(value, func) \
165 nsresult rv = mURI->func(tmp); \
166 if (NS_SUCCEEDED(rv)) { \
167 CopyUTF8toUTF16(tmp, value); \
170 void URL::GetHref(nsAString
& aHref
) const { URL_GETTER(aHref
, GetSpec
); }
172 void URL::SetHref(const nsAString
& aHref
, ErrorResult
& aRv
) {
173 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
175 if (!AppendUTF16toUTF8(aHref
, href
, fallible
)) {
176 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
180 nsCOMPtr
<nsIURI
> uri
;
181 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), href
);
183 aRv
.ThrowTypeError
<MSG_INVALID_URL
>(href
);
187 mURI
= std::move(uri
);
188 UpdateURLSearchParams();
191 void URL::GetOrigin(nsAString
& aOrigin
, ErrorResult
& aRv
) const {
192 nsresult rv
= nsContentUtils::GetUTFOrigin(GetURI(), aOrigin
);
193 if (NS_WARN_IF(NS_FAILED(rv
))) {
198 void URL::GetProtocol(nsAString
& aProtocol
) const {
199 URL_GETTER(aProtocol
, GetScheme
);
200 aProtocol
.Append(char16_t(':'));
203 void URL::SetProtocol(const nsAString
& aProtocol
, ErrorResult
& aRv
) {
204 nsAString::const_iterator start
;
205 aProtocol
.BeginReading(start
);
207 nsAString::const_iterator end
;
208 aProtocol
.EndReading(end
);
210 nsAString::const_iterator
iter(start
);
211 FindCharInReadable(':', iter
, end
);
213 // Changing the protocol of a URL, changes the "nature" of the URI
214 // implementation. In order to do this properly, we have to serialize the
215 // existing URL and reparse it in a new object.
216 nsCOMPtr
<nsIURI
> clone
;
217 nsresult rv
= NS_MutateURI(GetURI())
218 .SetScheme(NS_ConvertUTF16toUTF8(Substring(start
, iter
)))
220 if (NS_WARN_IF(NS_FAILED(rv
))) {
225 rv
= clone
->GetSpec(href
);
226 if (NS_WARN_IF(NS_FAILED(rv
))) {
230 nsCOMPtr
<nsIURI
> uri
;
231 rv
= NS_NewURI(getter_AddRefs(uri
), href
);
232 if (NS_WARN_IF(NS_FAILED(rv
))) {
236 mURI
= std::move(uri
);
239 void URL::GetUsername(nsAString
& aUsername
) const {
240 URL_GETTER(aUsername
, GetUsername
);
243 void URL::SetUsername(const nsAString
& aUsername
) {
246 Unused
<< NS_MutateURI(mURI
)
247 .SetUsername(NS_ConvertUTF16toUTF8(aUsername
))
251 void URL::GetPassword(nsAString
& aPassword
) const {
252 URL_GETTER(aPassword
, GetPassword
);
255 void URL::SetPassword(const nsAString
& aPassword
) {
258 Unused
<< NS_MutateURI(mURI
)
259 .SetPassword(NS_ConvertUTF16toUTF8(aPassword
))
263 void URL::GetHost(nsAString
& aHost
) const { URL_GETTER(aHost
, GetHostPort
); }
265 void URL::SetHost(const nsAString
& aHost
) {
268 Unused
<< NS_MutateURI(mURI
)
269 .SetHostPort(NS_ConvertUTF16toUTF8(aHost
))
273 void URL::GetHostname(nsAString
& aHostname
) const {
276 aHostname
.Truncate();
277 nsContentUtils::GetHostOrIPv6WithBrackets(mURI
, aHostname
);
280 void URL::SetHostname(const nsAString
& aHostname
) {
283 // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname
284 // The return code is silently ignored
285 mozilla::Unused
<< NS_MutateURI(mURI
)
286 .SetHost(NS_ConvertUTF16toUTF8(aHostname
))
290 void URL::GetPort(nsAString
& aPort
) const {
296 nsresult rv
= mURI
->GetPort(&port
);
297 if (NS_SUCCEEDED(rv
) && port
!= -1) {
298 nsAutoString portStr
;
299 portStr
.AppendInt(port
, 10);
300 aPort
.Assign(portStr
);
304 void URL::SetPort(const nsAString
& aPort
) {
306 nsAutoString
portStr(aPort
);
309 // nsIURI uses -1 as default value.
310 if (!portStr
.IsEmpty()) {
311 port
= portStr
.ToInteger(&rv
);
317 Unused
<< NS_MutateURI(mURI
).SetPort(port
).Finalize(mURI
);
320 void URL::GetPathname(nsAString
& aPathname
) const {
323 aPathname
.Truncate();
325 // Do not throw! Not having a valid URI or URL should result in an empty
329 nsresult rv
= mURI
->GetFilePath(file
);
330 if (NS_SUCCEEDED(rv
)) {
331 CopyUTF8toUTF16(file
, aPathname
);
335 void URL::SetPathname(const nsAString
& aPathname
) {
340 Unused
<< NS_MutateURI(mURI
)
341 .SetFilePath(NS_ConvertUTF16toUTF8(aPathname
))
345 void URL::GetSearch(nsAString
& aSearch
) const {
350 // Do not throw! Not having a valid URI or URL should result in an empty
353 nsAutoCString search
;
356 rv
= mURI
->GetQuery(search
);
357 if (NS_SUCCEEDED(rv
) && !search
.IsEmpty()) {
358 aSearch
.Assign(u
'?');
359 AppendUTF8toUTF16(search
, aSearch
);
363 void URL::GetHash(nsAString
& aHash
) const {
369 nsresult rv
= mURI
->GetRef(ref
);
370 if (NS_SUCCEEDED(rv
) && !ref
.IsEmpty()) {
371 aHash
.Assign(char16_t('#'));
372 AppendUTF8toUTF16(ref
, aHash
);
376 void URL::SetHash(const nsAString
& aHash
) {
380 << NS_MutateURI(mURI
).SetRef(NS_ConvertUTF16toUTF8(aHash
)).Finalize(mURI
);
383 void URL::SetSearchInternal(const nsAString
& aSearch
) {
386 // Ignore failures to be compatible with NS4.
388 Unused
<< NS_MutateURI(mURI
)
389 .SetQuery(NS_ConvertUTF16toUTF8(aSearch
))
393 void URL::UpdateURLSearchParams() {
394 if (!mSearchParams
) {
398 nsAutoCString search
;
399 nsresult rv
= GetURI()->GetQuery(search
);
400 if (NS_WARN_IF(NS_FAILED(rv
))) {
404 mSearchParams
->ParseInput(search
);
407 void URL::SetURI(already_AddRefed
<nsIURI
> aURI
) {
408 mURI
= std::move(aURI
);
412 nsIURI
* URL::GetURI() const {
418 } // namespace mozilla