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 nsACString
& aURL
,
40 const Optional
<nsACString
>& 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 nsACString
& aURL
,
52 const nsACString
& aBase
,
54 nsCOMPtr
<nsIURI
> baseUri
;
55 nsresult rv
= NS_NewURI(getter_AddRefs(baseUri
), aBase
);
56 if (NS_WARN_IF(NS_FAILED(rv
))) {
57 aRv
.ThrowTypeError
<MSG_INVALID_URL
>(aBase
);
61 return Constructor(aParent
, aURL
, baseUri
, aRv
);
65 already_AddRefed
<URL
> URL::Constructor(nsISupports
* aParent
,
66 const nsACString
& aURL
, nsIURI
* aBase
,
69 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), aURL
, nullptr, aBase
);
71 // No need to warn in this case. It's common to use the URL constructor
72 // to determine if a URL is valid and an exception will be propagated.
73 aRv
.ThrowTypeError
<MSG_INVALID_URL
>(aURL
);
77 return MakeAndAddRef
<URL
>(aParent
, std::move(uri
));
80 already_AddRefed
<URL
> URL::FromURI(GlobalObject
& aGlobal
, nsIURI
* aURI
) {
81 return MakeAndAddRef
<URL
>(aGlobal
.GetAsSupports(), aURI
);
84 void URL::CreateObjectURL(const GlobalObject
& aGlobal
, Blob
& aBlob
,
85 nsACString
& aResult
, ErrorResult
& aRv
) {
86 if (NS_IsMainThread()) {
87 URLMainThread::CreateObjectURL(aGlobal
, aBlob
, aResult
, aRv
);
89 URLWorker::CreateObjectURL(aGlobal
, aBlob
, aResult
, aRv
);
93 void URL::CreateObjectURL(const GlobalObject
& aGlobal
, MediaSource
& aSource
,
94 nsACString
& aResult
, ErrorResult
& aRv
) {
95 MOZ_ASSERT(NS_IsMainThread());
96 URLMainThread::CreateObjectURL(aGlobal
, aSource
, aResult
, aRv
);
99 void URL::RevokeObjectURL(const GlobalObject
& aGlobal
, const nsACString
& aURL
,
101 if (aURL
.Contains('#')) {
102 // Don't revoke URLs that contain fragments.
106 if (NS_IsMainThread()) {
107 URLMainThread::RevokeObjectURL(aGlobal
, aURL
, aRv
);
109 URLWorker::RevokeObjectURL(aGlobal
, aURL
, aRv
);
113 bool URL::IsValidObjectURL(const GlobalObject
& aGlobal
, const nsACString
& aURL
,
115 if (NS_IsMainThread()) {
116 return URLMainThread::IsValidObjectURL(aGlobal
, aURL
, aRv
);
118 return URLWorker::IsValidObjectURL(aGlobal
, aURL
, aRv
);
121 already_AddRefed
<nsIURI
> URL::ParseURI(const nsACString
& aURL
,
122 const Optional
<nsACString
>& aBase
) {
123 nsCOMPtr
<nsIURI
> baseUri
;
124 nsCOMPtr
<nsIURI
> uri
;
126 if (aBase
.WasPassed()) {
127 nsresult rv
= NS_NewURI(getter_AddRefs(baseUri
), aBase
.Value());
133 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), aURL
, nullptr, baseUri
);
141 already_AddRefed
<URL
> URL::Parse(const GlobalObject
& aGlobal
,
142 const nsACString
& aURL
,
143 const Optional
<nsACString
>& aBase
) {
144 nsCOMPtr
<nsIURI
> uri
= ParseURI(aURL
, aBase
);
148 return MakeAndAddRef
<URL
>(aGlobal
.GetAsSupports(), std::move(uri
));
151 bool URL::CanParse(const GlobalObject
& aGlobal
, const nsACString
& aURL
,
152 const Optional
<nsACString
>& aBase
) {
153 nsCOMPtr
<nsIURI
> uri
= ParseURI(aURL
, aBase
);
157 URLSearchParams
* URL::SearchParams() {
158 CreateSearchParamsIfNeeded();
159 return mSearchParams
;
162 bool IsChromeURI(nsIURI
* aURI
) { return aURI
->SchemeIs("chrome"); }
164 void URL::CreateSearchParamsIfNeeded() {
165 if (!mSearchParams
) {
166 mSearchParams
= new URLSearchParams(mParent
, this);
167 UpdateURLSearchParams();
171 void URL::SetSearch(const nsACString
& aSearch
) {
172 SetSearchInternal(aSearch
);
173 UpdateURLSearchParams();
176 void URL::URLSearchParamsUpdated(URLSearchParams
* aSearchParams
) {
177 MOZ_ASSERT(mSearchParams
);
178 MOZ_ASSERT(mSearchParams
== aSearchParams
);
180 nsAutoCString search
;
181 mSearchParams
->Serialize(search
);
182 SetSearchInternal(search
);
185 #define URL_GETTER(value, func) \
189 void URL::GetHref(nsACString
& aHref
) const { URL_GETTER(aHref
, GetSpec
); }
191 void URL::SetHref(const nsACString
& aHref
, ErrorResult
& aRv
) {
192 nsCOMPtr
<nsIURI
> uri
;
193 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), aHref
);
195 aRv
.ThrowTypeError
<MSG_INVALID_URL
>(aHref
);
199 mURI
= std::move(uri
);
200 UpdateURLSearchParams();
203 void URL::GetOrigin(nsACString
& aOrigin
) const {
205 nsContentUtils::GetWebExposedOriginSerialization(URI(), aOrigin
);
206 if (NS_WARN_IF(NS_FAILED(rv
))) {
211 void URL::GetProtocol(nsACString
& aProtocol
) const {
212 URL_GETTER(aProtocol
, GetScheme
);
213 aProtocol
.Append(char16_t(':'));
216 void URL::SetProtocol(const nsACString
& aProtocol
) {
217 nsCOMPtr
<nsIURI
> uri(URI());
221 uri
= net::TryChangeProtocol(uri
, aProtocol
);
225 mURI
= std::move(uri
);
228 void URL::GetUsername(nsACString
& aUsername
) const {
229 URL_GETTER(aUsername
, GetUsername
);
232 void URL::SetUsername(const nsACString
& aUsername
) {
234 Unused
<< NS_MutateURI(mURI
).SetUsername(aUsername
).Finalize(mURI
);
237 void URL::GetPassword(nsACString
& aPassword
) const {
238 URL_GETTER(aPassword
, GetPassword
);
241 void URL::SetPassword(const nsACString
& aPassword
) {
244 Unused
<< NS_MutateURI(mURI
).SetPassword(aPassword
).Finalize(mURI
);
247 void URL::GetHost(nsACString
& aHost
) const { URL_GETTER(aHost
, GetHostPort
); }
249 void URL::SetHost(const nsACString
& aHost
) {
251 Unused
<< NS_MutateURI(mURI
).SetHostPort(aHost
).Finalize(mURI
);
254 void URL::GetHostname(nsACString
& aHostname
) const {
256 aHostname
.Truncate();
257 nsContentUtils::GetHostOrIPv6WithBrackets(mURI
, aHostname
);
260 void URL::SetHostname(const nsACString
& aHostname
) {
263 // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname
264 // The return code is silently ignored
265 Unused
<< NS_MutateURI(mURI
).SetHost(aHostname
).Finalize(mURI
);
268 void URL::GetPort(nsACString
& aPort
) const {
273 nsresult rv
= mURI
->GetPort(&port
);
274 if (NS_SUCCEEDED(rv
) && port
!= -1) {
275 aPort
.AppendInt(port
, 10);
279 void URL::SetPort(const nsACString
& aPort
) {
281 nsAutoCString
portStr(aPort
);
284 // nsIURI uses -1 as default value.
285 portStr
.StripTaggedASCII(ASCIIMask::MaskCRLFTab());
286 if (!portStr
.IsEmpty()) {
287 // To be valid, the port must start with an ASCII digit.
288 // (nsACString::ToInteger ignores leading junk, so check before calling.)
289 if (!IsAsciiDigit(portStr
[0])) {
292 port
= portStr
.ToInteger(&rv
);
298 Unused
<< NS_MutateURI(mURI
).SetPort(port
).Finalize(mURI
);
301 void URL::GetPathname(nsACString
& aPathname
) const {
303 // Do not throw! Not having a valid URI or URL should result in an empty
305 mURI
->GetFilePath(aPathname
);
308 void URL::SetPathname(const nsACString
& aPathname
) {
312 Unused
<< NS_MutateURI(mURI
).SetFilePath(aPathname
).Finalize(mURI
);
315 void URL::GetSearch(nsACString
& aSearch
) const {
320 // Do not throw! Not having a valid URI or URL should result in an empty
324 rv
= mURI
->GetQuery(aSearch
);
325 if (NS_SUCCEEDED(rv
) && !aSearch
.IsEmpty()) {
326 aSearch
.Insert('?', 0);
330 void URL::GetHash(nsACString
& aHash
) const {
333 nsresult rv
= mURI
->GetRef(aHash
);
334 if (NS_SUCCEEDED(rv
) && !aHash
.IsEmpty()) {
335 aHash
.Insert('#', 0);
339 void URL::SetHash(const nsACString
& aHash
) {
342 Unused
<< NS_MutateURI(mURI
).SetRef(aHash
).Finalize(mURI
);
345 void URL::SetSearchInternal(const nsACString
& aSearch
) {
348 // Ignore failures to be compatible with NS4.
349 Unused
<< NS_MutateURI(mURI
).SetQuery(aSearch
).Finalize(mURI
);
352 void URL::UpdateURLSearchParams() {
353 if (!mSearchParams
) {
357 nsAutoCString search
;
358 nsresult rv
= URI()->GetQuery(search
);
359 if (NS_WARN_IF(NS_FAILED(rv
))) {
363 mSearchParams
->ParseInput(search
);
366 nsIURI
* URL::URI() const {
371 } // namespace mozilla::dom