Bug 1850713: remove duplicated setting of early hint preloader id in `ScriptLoader...
[gecko.git] / dom / url / URL.cpp
blob799bb72cffbb0dbc11f90035cfc33ee530af31bb
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 nsAString& aURL,
40 const Optional<nsAString>& 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 nsAString& aURL,
52 const nsAString& aBase,
53 ErrorResult& aRv) {
54 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
55 nsAutoCString base;
56 if (!AppendUTF16toUTF8(aBase, base, fallible)) {
57 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
58 return nullptr;
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);
65 return nullptr;
68 return Constructor(aParent, aURL, baseUri, aRv);
71 /* static */
72 already_AddRefed<URL> URL::Constructor(nsISupports* aParent,
73 const nsAString& aURL, nsIURI* aBase,
74 ErrorResult& aRv) {
75 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
76 nsAutoCString urlStr;
77 if (!AppendUTF16toUTF8(aURL, urlStr, fallible)) {
78 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
79 return nullptr;
82 nsCOMPtr<nsIURI> uri;
83 nsresult rv = NS_NewURI(getter_AddRefs(uri), urlStr, nullptr, aBase);
84 if (NS_FAILED(rv)) {
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);
88 return nullptr;
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);
102 } else {
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,
114 ErrorResult& aRv) {
115 if (aURL.Contains('#')) {
116 // Don't revoke URLs that contain fragments.
117 return;
120 if (NS_IsMainThread()) {
121 URLMainThread::RevokeObjectURL(aGlobal, aURL, aRv);
122 } else {
123 URLWorker::RevokeObjectURL(aGlobal, aURL, aRv);
127 bool URL::IsValidObjectURL(const GlobalObject& aGlobal, const nsAString& aURL,
128 ErrorResult& aRv) {
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.
140 nsAutoCString base;
141 if (!AppendUTF16toUTF8(aBase.Value(), base, fallible)) {
142 // Just return false with OOM errors as no ErrorResult.
143 return false;
146 nsresult rv = NS_NewURI(getter_AddRefs(baseUri), base);
147 if (NS_FAILED(rv)) {
148 // Invalid base URL, return false.
149 return false;
153 nsAutoCString urlStr;
154 if (!AppendUTF16toUTF8(aURL, urlStr, fallible)) {
155 // Just return false with OOM errors as no ErrorResult.
156 return false;
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);
186 nsAutoString search;
187 mSearchParams->Serialize(search);
189 SetSearchInternal(search);
192 #define URL_GETTER(value, func) \
193 MOZ_ASSERT(mURI); \
194 value.Truncate(); \
195 nsAutoCString tmp; \
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.
205 nsAutoCString href;
206 if (!AppendUTF16toUTF8(aHref, href, fallible)) {
207 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
208 return;
211 nsCOMPtr<nsIURI> uri;
212 nsresult rv = NS_NewURI(getter_AddRefs(uri), href);
213 if (NS_FAILED(rv)) {
214 aRv.ThrowTypeError<MSG_INVALID_URL>(href);
215 return;
218 mURI = std::move(uri);
219 UpdateURLSearchParams();
222 void URL::GetOrigin(nsAString& aOrigin) const {
223 nsresult rv =
224 nsContentUtils::GetWebExposedOriginSerialization(URI(), aOrigin);
225 if (NS_WARN_IF(NS_FAILED(rv))) {
226 aOrigin.Truncate();
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());
237 if (!uri) {
238 return;
240 uri = net::TryChangeProtocol(uri, aProtocol);
241 if (!uri) {
242 return;
244 mURI = std::move(uri);
247 void URL::GetUsername(nsAString& aUsername) const {
248 URL_GETTER(aUsername, GetUsername);
251 void URL::SetUsername(const nsAString& aUsername) {
252 MOZ_ASSERT(mURI);
254 Unused << NS_MutateURI(mURI)
255 .SetUsername(NS_ConvertUTF16toUTF8(aUsername))
256 .Finalize(mURI);
259 void URL::GetPassword(nsAString& aPassword) const {
260 URL_GETTER(aPassword, GetPassword);
263 void URL::SetPassword(const nsAString& aPassword) {
264 MOZ_ASSERT(mURI);
266 Unused << NS_MutateURI(mURI)
267 .SetPassword(NS_ConvertUTF16toUTF8(aPassword))
268 .Finalize(mURI);
271 void URL::GetHost(nsAString& aHost) const { URL_GETTER(aHost, GetHostPort); }
273 void URL::SetHost(const nsAString& aHost) {
274 MOZ_ASSERT(mURI);
276 Unused << NS_MutateURI(mURI)
277 .SetHostPort(NS_ConvertUTF16toUTF8(aHost))
278 .Finalize(mURI);
281 void URL::GetHostname(nsAString& aHostname) const {
282 MOZ_ASSERT(mURI);
284 aHostname.Truncate();
285 nsContentUtils::GetHostOrIPv6WithBrackets(mURI, aHostname);
288 void URL::SetHostname(const nsAString& aHostname) {
289 MOZ_ASSERT(mURI);
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))
295 .Finalize(mURI);
298 void URL::GetPort(nsAString& aPort) const {
299 MOZ_ASSERT(mURI);
301 aPort.Truncate();
303 int32_t port;
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) {
313 nsresult rv;
314 nsAutoString portStr(aPort);
315 int32_t port = -1;
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])) {
323 return;
325 port = portStr.ToInteger(&rv);
326 if (NS_FAILED(rv)) {
327 return;
331 Unused << NS_MutateURI(mURI).SetPort(port).Finalize(mURI);
334 void URL::GetPathname(nsAString& aPathname) const {
335 MOZ_ASSERT(mURI);
337 aPathname.Truncate();
339 // Do not throw! Not having a valid URI or URL should result in an empty
340 // string.
342 nsAutoCString file;
343 nsresult rv = mURI->GetFilePath(file);
344 if (NS_SUCCEEDED(rv)) {
345 CopyUTF8toUTF16(file, aPathname);
349 void URL::SetPathname(const nsAString& aPathname) {
350 MOZ_ASSERT(mURI);
352 // Do not throw!
354 Unused << NS_MutateURI(mURI)
355 .SetFilePath(NS_ConvertUTF16toUTF8(aPathname))
356 .Finalize(mURI);
359 void URL::GetSearch(nsAString& aSearch) const {
360 MOZ_ASSERT(mURI);
362 aSearch.Truncate();
364 // Do not throw! Not having a valid URI or URL should result in an empty
365 // string.
367 nsAutoCString search;
368 nsresult rv;
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 {
378 MOZ_ASSERT(mURI);
380 aHash.Truncate();
382 nsAutoCString ref;
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) {
391 MOZ_ASSERT(mURI);
393 Unused
394 << NS_MutateURI(mURI).SetRef(NS_ConvertUTF16toUTF8(aHash)).Finalize(mURI);
397 void URL::SetSearchInternal(const nsAString& aSearch) {
398 MOZ_ASSERT(mURI);
400 // Ignore failures to be compatible with NS4.
402 Unused << NS_MutateURI(mURI)
403 .SetQuery(NS_ConvertUTF16toUTF8(aSearch))
404 .Finalize(mURI);
407 void URL::UpdateURLSearchParams() {
408 if (!mSearchParams) {
409 return;
412 nsAutoCString search;
413 nsresult rv = URI()->GetQuery(search);
414 if (NS_WARN_IF(NS_FAILED(rv))) {
415 search.Truncate();
418 mSearchParams->ParseInput(search);
421 nsIURI* URL::URI() const {
422 MOZ_ASSERT(mURI);
423 return mURI;
426 } // namespace mozilla::dom