Bug 1890793: Assert CallArgs::newTarget is not gray. r=spidermonkey-reviewers,sfink...
[gecko.git] / dom / url / URL.cpp
blob1011eda2102af238e444eb4146b696174c4abaa6
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/. */
7 #include "URL.h"
8 #include "URLMainThread.h"
9 #include "URLWorker.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)
31 NS_INTERFACE_MAP_END
33 JSObject* URL::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
34 return URL_Binding::Wrap(aCx, this, aGivenProto);
37 /* static */
38 already_AddRefed<URL> URL::Constructor(const GlobalObject& aGlobal,
39 const nsACString& aURL,
40 const Optional<nsACString>& aBase,
41 ErrorResult& aRv) {
42 if (aBase.WasPassed()) {
43 return Constructor(aGlobal.GetAsSupports(), aURL, aBase.Value(), aRv);
46 return Constructor(aGlobal.GetAsSupports(), aURL, nullptr, aRv);
49 /* static */
50 already_AddRefed<URL> URL::Constructor(nsISupports* aParent,
51 const nsACString& aURL,
52 const nsACString& aBase,
53 ErrorResult& aRv) {
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);
58 return nullptr;
61 return Constructor(aParent, aURL, baseUri, aRv);
64 /* static */
65 already_AddRefed<URL> URL::Constructor(nsISupports* aParent,
66 const nsACString& aURL, nsIURI* aBase,
67 ErrorResult& aRv) {
68 nsCOMPtr<nsIURI> uri;
69 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, aBase);
70 if (NS_FAILED(rv)) {
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);
74 return nullptr;
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);
88 } else {
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,
100 ErrorResult& aRv) {
101 if (aURL.Contains('#')) {
102 // Don't revoke URLs that contain fragments.
103 return;
106 if (NS_IsMainThread()) {
107 URLMainThread::RevokeObjectURL(aGlobal, aURL, aRv);
108 } else {
109 URLWorker::RevokeObjectURL(aGlobal, aURL, aRv);
113 bool URL::IsValidObjectURL(const GlobalObject& aGlobal, const nsACString& aURL,
114 ErrorResult& aRv) {
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());
128 if (NS_FAILED(rv)) {
129 return nullptr;
133 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, baseUri);
134 if (NS_FAILED(rv)) {
135 return nullptr;
138 return uri.forget();
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);
145 if (!uri) {
146 return nullptr;
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);
154 return !!uri;
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) \
186 MOZ_ASSERT(mURI); \
187 mURI->func(value);
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);
194 if (NS_FAILED(rv)) {
195 aRv.ThrowTypeError<MSG_INVALID_URL>(aHref);
196 return;
199 mURI = std::move(uri);
200 UpdateURLSearchParams();
203 void URL::GetOrigin(nsACString& aOrigin) const {
204 nsresult rv =
205 nsContentUtils::GetWebExposedOriginSerialization(URI(), aOrigin);
206 if (NS_WARN_IF(NS_FAILED(rv))) {
207 aOrigin.Truncate();
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());
218 if (!uri) {
219 return;
221 uri = net::TryChangeProtocol(uri, aProtocol);
222 if (!uri) {
223 return;
225 mURI = std::move(uri);
228 void URL::GetUsername(nsACString& aUsername) const {
229 URL_GETTER(aUsername, GetUsername);
232 void URL::SetUsername(const nsACString& aUsername) {
233 MOZ_ASSERT(mURI);
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) {
242 MOZ_ASSERT(mURI);
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) {
250 MOZ_ASSERT(mURI);
251 Unused << NS_MutateURI(mURI).SetHostPort(aHost).Finalize(mURI);
254 void URL::GetHostname(nsACString& aHostname) const {
255 MOZ_ASSERT(mURI);
256 aHostname.Truncate();
257 nsContentUtils::GetHostOrIPv6WithBrackets(mURI, aHostname);
260 void URL::SetHostname(const nsACString& aHostname) {
261 MOZ_ASSERT(mURI);
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 {
269 MOZ_ASSERT(mURI);
270 aPort.Truncate();
272 int32_t port;
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) {
280 nsresult rv;
281 nsAutoCString portStr(aPort);
282 int32_t port = -1;
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])) {
290 return;
292 port = portStr.ToInteger(&rv);
293 if (NS_FAILED(rv)) {
294 return;
298 Unused << NS_MutateURI(mURI).SetPort(port).Finalize(mURI);
301 void URL::GetPathname(nsACString& aPathname) const {
302 MOZ_ASSERT(mURI);
303 // Do not throw! Not having a valid URI or URL should result in an empty
304 // string.
305 mURI->GetFilePath(aPathname);
308 void URL::SetPathname(const nsACString& aPathname) {
309 MOZ_ASSERT(mURI);
311 // Do not throw!
312 Unused << NS_MutateURI(mURI).SetFilePath(aPathname).Finalize(mURI);
315 void URL::GetSearch(nsACString& aSearch) const {
316 MOZ_ASSERT(mURI);
318 aSearch.Truncate();
320 // Do not throw! Not having a valid URI or URL should result in an empty
321 // string.
323 nsresult rv;
324 rv = mURI->GetQuery(aSearch);
325 if (NS_SUCCEEDED(rv) && !aSearch.IsEmpty()) {
326 aSearch.Insert('?', 0);
330 void URL::GetHash(nsACString& aHash) const {
331 MOZ_ASSERT(mURI);
332 aHash.Truncate();
333 nsresult rv = mURI->GetRef(aHash);
334 if (NS_SUCCEEDED(rv) && !aHash.IsEmpty()) {
335 aHash.Insert('#', 0);
339 void URL::SetHash(const nsACString& aHash) {
340 MOZ_ASSERT(mURI);
342 Unused << NS_MutateURI(mURI).SetRef(aHash).Finalize(mURI);
345 void URL::SetSearchInternal(const nsACString& aSearch) {
346 MOZ_ASSERT(mURI);
348 // Ignore failures to be compatible with NS4.
349 Unused << NS_MutateURI(mURI).SetQuery(aSearch).Finalize(mURI);
352 void URL::UpdateURLSearchParams() {
353 if (!mSearchParams) {
354 return;
357 nsAutoCString search;
358 nsresult rv = URI()->GetQuery(search);
359 if (NS_WARN_IF(NS_FAILED(rv))) {
360 search.Truncate();
363 mSearchParams->ParseInput(search);
366 nsIURI* URL::URI() const {
367 MOZ_ASSERT(mURI);
368 return mURI;
371 } // namespace mozilla::dom