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 "nsASCIIMask.h"
12 #include "MainThreadUtils.h"
13 #include "mozilla/RefPtr.h"
14 #include "mozilla/dom/URLBinding.h"
15 #include "mozilla/dom/BindingUtils.h"
16 #include "nsContentUtils.h"
17 #include "mozilla/dom/Document.h"
18 #include "nsIURIMutator.h"
19 #include "nsNetUtil.h"
21 namespace mozilla::dom
{
23 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URL
, mParent
, mSearchParams
)
25 NS_IMPL_CYCLE_COLLECTING_ADDREF(URL
)
26 NS_IMPL_CYCLE_COLLECTING_RELEASE(URL
)
28 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URL
)
29 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
30 NS_INTERFACE_MAP_ENTRY(nsISupports
)
33 JSObject
* URL::WrapObject(JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
34 return URL_Binding::Wrap(aCx
, this, aGivenProto
);
38 already_AddRefed
<URL
> URL::Constructor(const GlobalObject
& aGlobal
,
39 const nsAString
& aURL
,
40 const Optional
<nsAString
>& aBase
,
42 if (aBase
.WasPassed()) {
43 return Constructor(aGlobal
.GetAsSupports(), aURL
, aBase
.Value(), aRv
);
46 return Constructor(aGlobal
.GetAsSupports(), aURL
, nullptr, aRv
);
50 already_AddRefed
<URL
> URL::Constructor(nsISupports
* aParent
,
51 const nsAString
& aURL
,
52 const nsAString
& aBase
,
54 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
56 if (!AppendUTF16toUTF8(aBase
, base
, fallible
)) {
57 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
61 nsCOMPtr
<nsIURI
> baseUri
;
62 nsresult rv
= NS_NewURI(getter_AddRefs(baseUri
), base
);
63 if (NS_WARN_IF(NS_FAILED(rv
))) {
64 aRv
.ThrowTypeError
<MSG_INVALID_URL
>(base
);
68 return Constructor(aParent
, aURL
, baseUri
, aRv
);
72 already_AddRefed
<URL
> URL::Constructor(nsISupports
* aParent
,
73 const nsAString
& aURL
, nsIURI
* aBase
,
75 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
77 if (!AppendUTF16toUTF8(aURL
, urlStr
, fallible
)) {
78 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
83 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), urlStr
, nullptr, aBase
);
85 // No need to warn in this case. It's common to use the URL constructor
86 // to determine if a URL is valid and an exception will be propagated.
87 aRv
.ThrowTypeError
<MSG_INVALID_URL
>(urlStr
);
91 return MakeAndAddRef
<URL
>(aParent
, std::move(uri
));
94 already_AddRefed
<URL
> URL::FromURI(GlobalObject
& aGlobal
, nsIURI
* aURI
) {
95 return MakeAndAddRef
<URL
>(aGlobal
.GetAsSupports(), aURI
);
98 void URL::CreateObjectURL(const GlobalObject
& aGlobal
, Blob
& aBlob
,
99 nsAString
& aResult
, ErrorResult
& aRv
) {
100 if (NS_IsMainThread()) {
101 URLMainThread::CreateObjectURL(aGlobal
, aBlob
, aResult
, aRv
);
103 URLWorker::CreateObjectURL(aGlobal
, aBlob
, aResult
, aRv
);
107 void URL::CreateObjectURL(const GlobalObject
& aGlobal
, MediaSource
& aSource
,
108 nsAString
& aResult
, ErrorResult
& aRv
) {
109 MOZ_ASSERT(NS_IsMainThread());
110 URLMainThread::CreateObjectURL(aGlobal
, aSource
, aResult
, aRv
);
113 void URL::RevokeObjectURL(const GlobalObject
& aGlobal
, const nsAString
& aURL
,
115 if (aURL
.Contains('#')) {
116 // Don't revoke URLs that contain fragments.
120 if (NS_IsMainThread()) {
121 URLMainThread::RevokeObjectURL(aGlobal
, aURL
, aRv
);
123 URLWorker::RevokeObjectURL(aGlobal
, aURL
, aRv
);
127 bool URL::IsValidObjectURL(const GlobalObject
& aGlobal
, const nsAString
& aURL
,
129 if (NS_IsMainThread()) {
130 return URLMainThread::IsValidObjectURL(aGlobal
, aURL
, aRv
);
132 return URLWorker::IsValidObjectURL(aGlobal
, aURL
, aRv
);
135 bool URL::CanParse(const GlobalObject
& aGlobal
, const nsAString
& aURL
,
136 const Optional
<nsAString
>& aBase
) {
137 nsCOMPtr
<nsIURI
> baseUri
;
138 if (aBase
.WasPassed()) {
139 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
141 if (!AppendUTF16toUTF8(aBase
.Value(), base
, fallible
)) {
142 // Just return false with OOM errors as no ErrorResult.
146 nsresult rv
= NS_NewURI(getter_AddRefs(baseUri
), base
);
148 // Invalid base URL, return false.
153 nsAutoCString urlStr
;
154 if (!AppendUTF16toUTF8(aURL
, urlStr
, fallible
)) {
155 // Just return false with OOM errors as no ErrorResult.
159 nsCOMPtr
<nsIURI
> uri
;
160 return NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri
), urlStr
, nullptr, baseUri
));
163 URLSearchParams
* URL::SearchParams() {
164 CreateSearchParamsIfNeeded();
165 return mSearchParams
;
168 bool IsChromeURI(nsIURI
* aURI
) { return aURI
->SchemeIs("chrome"); }
170 void URL::CreateSearchParamsIfNeeded() {
171 if (!mSearchParams
) {
172 mSearchParams
= new URLSearchParams(mParent
, this);
173 UpdateURLSearchParams();
177 void URL::SetSearch(const nsAString
& aSearch
) {
178 SetSearchInternal(aSearch
);
179 UpdateURLSearchParams();
182 void URL::URLSearchParamsUpdated(URLSearchParams
* aSearchParams
) {
183 MOZ_ASSERT(mSearchParams
);
184 MOZ_ASSERT(mSearchParams
== aSearchParams
);
187 mSearchParams
->Serialize(search
);
189 SetSearchInternal(search
);
192 #define URL_GETTER(value, func) \
196 nsresult rv = mURI->func(tmp); \
197 if (NS_SUCCEEDED(rv)) { \
198 CopyUTF8toUTF16(tmp, value); \
201 void URL::GetHref(nsAString
& aHref
) const { URL_GETTER(aHref
, GetSpec
); }
203 void URL::SetHref(const nsAString
& aHref
, ErrorResult
& aRv
) {
204 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
206 if (!AppendUTF16toUTF8(aHref
, href
, fallible
)) {
207 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
211 nsCOMPtr
<nsIURI
> uri
;
212 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), href
);
214 aRv
.ThrowTypeError
<MSG_INVALID_URL
>(href
);
218 mURI
= std::move(uri
);
219 UpdateURLSearchParams();
222 void URL::GetOrigin(nsAString
& aOrigin
) const {
224 nsContentUtils::GetWebExposedOriginSerialization(URI(), aOrigin
);
225 if (NS_WARN_IF(NS_FAILED(rv
))) {
230 void URL::GetProtocol(nsAString
& aProtocol
) const {
231 URL_GETTER(aProtocol
, GetScheme
);
232 aProtocol
.Append(char16_t(':'));
235 void URL::SetProtocol(const nsAString
& aProtocol
) {
236 nsCOMPtr
<nsIURI
> uri(URI());
240 uri
= net::TryChangeProtocol(uri
, aProtocol
);
244 mURI
= std::move(uri
);
247 void URL::GetUsername(nsAString
& aUsername
) const {
248 URL_GETTER(aUsername
, GetUsername
);
251 void URL::SetUsername(const nsAString
& aUsername
) {
254 Unused
<< NS_MutateURI(mURI
)
255 .SetUsername(NS_ConvertUTF16toUTF8(aUsername
))
259 void URL::GetPassword(nsAString
& aPassword
) const {
260 URL_GETTER(aPassword
, GetPassword
);
263 void URL::SetPassword(const nsAString
& aPassword
) {
266 Unused
<< NS_MutateURI(mURI
)
267 .SetPassword(NS_ConvertUTF16toUTF8(aPassword
))
271 void URL::GetHost(nsAString
& aHost
) const { URL_GETTER(aHost
, GetHostPort
); }
273 void URL::SetHost(const nsAString
& aHost
) {
276 Unused
<< NS_MutateURI(mURI
)
277 .SetHostPort(NS_ConvertUTF16toUTF8(aHost
))
281 void URL::GetHostname(nsAString
& aHostname
) const {
284 aHostname
.Truncate();
285 nsContentUtils::GetHostOrIPv6WithBrackets(mURI
, aHostname
);
288 void URL::SetHostname(const nsAString
& aHostname
) {
291 // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname
292 // The return code is silently ignored
293 mozilla::Unused
<< NS_MutateURI(mURI
)
294 .SetHost(NS_ConvertUTF16toUTF8(aHostname
))
298 void URL::GetPort(nsAString
& aPort
) const {
304 nsresult rv
= mURI
->GetPort(&port
);
305 if (NS_SUCCEEDED(rv
) && port
!= -1) {
306 nsAutoString portStr
;
307 portStr
.AppendInt(port
, 10);
308 aPort
.Assign(portStr
);
312 void URL::SetPort(const nsAString
& aPort
) {
314 nsAutoString
portStr(aPort
);
317 // nsIURI uses -1 as default value.
318 portStr
.StripTaggedASCII(ASCIIMask::MaskCRLFTab());
319 if (!portStr
.IsEmpty()) {
320 // To be valid, the port must start with an ASCII digit.
321 // (nsAString::ToInteger ignores leading junk, so check before calling.)
322 if (!IsAsciiDigit(portStr
[0])) {
325 port
= portStr
.ToInteger(&rv
);
331 Unused
<< NS_MutateURI(mURI
).SetPort(port
).Finalize(mURI
);
334 void URL::GetPathname(nsAString
& aPathname
) const {
337 aPathname
.Truncate();
339 // Do not throw! Not having a valid URI or URL should result in an empty
343 nsresult rv
= mURI
->GetFilePath(file
);
344 if (NS_SUCCEEDED(rv
)) {
345 CopyUTF8toUTF16(file
, aPathname
);
349 void URL::SetPathname(const nsAString
& aPathname
) {
354 Unused
<< NS_MutateURI(mURI
)
355 .SetFilePath(NS_ConvertUTF16toUTF8(aPathname
))
359 void URL::GetSearch(nsAString
& aSearch
) const {
364 // Do not throw! Not having a valid URI or URL should result in an empty
367 nsAutoCString search
;
370 rv
= mURI
->GetQuery(search
);
371 if (NS_SUCCEEDED(rv
) && !search
.IsEmpty()) {
372 aSearch
.Assign(u
'?');
373 AppendUTF8toUTF16(search
, aSearch
);
377 void URL::GetHash(nsAString
& aHash
) const {
383 nsresult rv
= mURI
->GetRef(ref
);
384 if (NS_SUCCEEDED(rv
) && !ref
.IsEmpty()) {
385 aHash
.Assign(char16_t('#'));
386 AppendUTF8toUTF16(ref
, aHash
);
390 void URL::SetHash(const nsAString
& aHash
) {
394 << NS_MutateURI(mURI
).SetRef(NS_ConvertUTF16toUTF8(aHash
)).Finalize(mURI
);
397 void URL::SetSearchInternal(const nsAString
& aSearch
) {
400 // Ignore failures to be compatible with NS4.
402 Unused
<< NS_MutateURI(mURI
)
403 .SetQuery(NS_ConvertUTF16toUTF8(aSearch
))
407 void URL::UpdateURLSearchParams() {
408 if (!mSearchParams
) {
412 nsAutoCString search
;
413 nsresult rv
= URI()->GetQuery(search
);
414 if (NS_WARN_IF(NS_FAILED(rv
))) {
418 mSearchParams
->ParseInput(search
);
421 nsIURI
* URL::URI() const {
426 } // namespace mozilla::dom