Bug 1660051 [wpt PR 25111] - Origin isolation: expand getter test coverage, a=testonly
[gecko.git] / dom / url / URL.cpp
blob612328681cdb730c62ef99154403adffd7b8792f
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 "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"
19 namespace mozilla {
20 namespace dom {
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)
30 NS_INTERFACE_MAP_END
32 JSObject* URL::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
33 return URL_Binding::Wrap(aCx, this, aGivenProto);
36 /* static */
37 already_AddRefed<URL> URL::Constructor(const GlobalObject& aGlobal,
38 const nsAString& aURL,
39 const Optional<nsAString>& aBase,
40 ErrorResult& aRv) {
41 if (aBase.WasPassed()) {
42 return Constructor(aGlobal.GetAsSupports(), aURL, aBase.Value(), aRv);
45 return Constructor(aGlobal.GetAsSupports(), aURL, nullptr, aRv);
48 /* static */
49 already_AddRefed<URL> URL::Constructor(nsISupports* aParent,
50 const nsAString& aURL,
51 const nsAString& aBase,
52 ErrorResult& aRv) {
53 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
54 nsAutoCString base;
55 if (!AppendUTF16toUTF8(aBase, base, fallible)) {
56 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
57 return nullptr;
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);
64 return nullptr;
67 return Constructor(aParent, aURL, baseUri, aRv);
70 /* static */
71 already_AddRefed<URL> URL::Constructor(nsISupports* aParent,
72 const nsAString& aURL, nsIURI* aBase,
73 ErrorResult& aRv) {
74 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
75 nsAutoCString urlStr;
76 if (!AppendUTF16toUTF8(aURL, urlStr, fallible)) {
77 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
78 return nullptr;
81 nsCOMPtr<nsIURI> uri;
82 nsresult rv = NS_NewURI(getter_AddRefs(uri), urlStr, nullptr, aBase);
83 if (NS_FAILED(rv)) {
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);
87 return nullptr;
90 RefPtr<URL> url = new URL(aParent);
91 url->SetURI(uri.forget());
92 return url.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);
99 } else {
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,
111 ErrorResult& aRv) {
112 if (aURL.Contains('#')) {
113 // Don't revoke URLs that contain fragments.
114 return;
117 if (NS_IsMainThread()) {
118 URLMainThread::RevokeObjectURL(aGlobal, aURL, aRv);
119 } else {
120 URLWorker::RevokeObjectURL(aGlobal, aURL, aRv);
124 bool URL::IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL,
125 ErrorResult& aRv) {
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);
155 nsAutoString search;
156 mSearchParams->Serialize(search);
158 SetSearchInternal(search);
161 #define URL_GETTER(value, func) \
162 MOZ_ASSERT(mURI); \
163 value.Truncate(); \
164 nsAutoCString tmp; \
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.
174 nsAutoCString href;
175 if (!AppendUTF16toUTF8(aHref, href, fallible)) {
176 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
177 return;
180 nsCOMPtr<nsIURI> uri;
181 nsresult rv = NS_NewURI(getter_AddRefs(uri), href);
182 if (NS_FAILED(rv)) {
183 aRv.ThrowTypeError<MSG_INVALID_URL>(href);
184 return;
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))) {
194 aOrigin.Truncate();
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)))
219 .Finalize(clone);
220 if (NS_WARN_IF(NS_FAILED(rv))) {
221 return;
224 nsAutoCString href;
225 rv = clone->GetSpec(href);
226 if (NS_WARN_IF(NS_FAILED(rv))) {
227 return;
230 nsCOMPtr<nsIURI> uri;
231 rv = NS_NewURI(getter_AddRefs(uri), href);
232 if (NS_WARN_IF(NS_FAILED(rv))) {
233 return;
236 mURI = std::move(uri);
239 void URL::GetUsername(nsAString& aUsername) const {
240 URL_GETTER(aUsername, GetUsername);
243 void URL::SetUsername(const nsAString& aUsername) {
244 MOZ_ASSERT(mURI);
246 Unused << NS_MutateURI(mURI)
247 .SetUsername(NS_ConvertUTF16toUTF8(aUsername))
248 .Finalize(mURI);
251 void URL::GetPassword(nsAString& aPassword) const {
252 URL_GETTER(aPassword, GetPassword);
255 void URL::SetPassword(const nsAString& aPassword) {
256 MOZ_ASSERT(mURI);
258 Unused << NS_MutateURI(mURI)
259 .SetPassword(NS_ConvertUTF16toUTF8(aPassword))
260 .Finalize(mURI);
263 void URL::GetHost(nsAString& aHost) const { URL_GETTER(aHost, GetHostPort); }
265 void URL::SetHost(const nsAString& aHost) {
266 MOZ_ASSERT(mURI);
268 Unused << NS_MutateURI(mURI)
269 .SetHostPort(NS_ConvertUTF16toUTF8(aHost))
270 .Finalize(mURI);
273 void URL::GetHostname(nsAString& aHostname) const {
274 MOZ_ASSERT(mURI);
276 aHostname.Truncate();
277 nsContentUtils::GetHostOrIPv6WithBrackets(mURI, aHostname);
280 void URL::SetHostname(const nsAString& aHostname) {
281 MOZ_ASSERT(mURI);
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))
287 .Finalize(mURI);
290 void URL::GetPort(nsAString& aPort) const {
291 MOZ_ASSERT(mURI);
293 aPort.Truncate();
295 int32_t port;
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) {
305 nsresult rv;
306 nsAutoString portStr(aPort);
307 int32_t port = -1;
309 // nsIURI uses -1 as default value.
310 if (!portStr.IsEmpty()) {
311 port = portStr.ToInteger(&rv);
312 if (NS_FAILED(rv)) {
313 return;
317 Unused << NS_MutateURI(mURI).SetPort(port).Finalize(mURI);
320 void URL::GetPathname(nsAString& aPathname) const {
321 MOZ_ASSERT(mURI);
323 aPathname.Truncate();
325 // Do not throw! Not having a valid URI or URL should result in an empty
326 // string.
328 nsAutoCString file;
329 nsresult rv = mURI->GetFilePath(file);
330 if (NS_SUCCEEDED(rv)) {
331 CopyUTF8toUTF16(file, aPathname);
335 void URL::SetPathname(const nsAString& aPathname) {
336 MOZ_ASSERT(mURI);
338 // Do not throw!
340 Unused << NS_MutateURI(mURI)
341 .SetFilePath(NS_ConvertUTF16toUTF8(aPathname))
342 .Finalize(mURI);
345 void URL::GetSearch(nsAString& aSearch) const {
346 MOZ_ASSERT(mURI);
348 aSearch.Truncate();
350 // Do not throw! Not having a valid URI or URL should result in an empty
351 // string.
353 nsAutoCString search;
354 nsresult rv;
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 {
364 MOZ_ASSERT(mURI);
366 aHash.Truncate();
368 nsAutoCString ref;
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) {
377 MOZ_ASSERT(mURI);
379 Unused
380 << NS_MutateURI(mURI).SetRef(NS_ConvertUTF16toUTF8(aHash)).Finalize(mURI);
383 void URL::SetSearchInternal(const nsAString& aSearch) {
384 MOZ_ASSERT(mURI);
386 // Ignore failures to be compatible with NS4.
388 Unused << NS_MutateURI(mURI)
389 .SetQuery(NS_ConvertUTF16toUTF8(aSearch))
390 .Finalize(mURI);
393 void URL::UpdateURLSearchParams() {
394 if (!mSearchParams) {
395 return;
398 nsAutoCString search;
399 nsresult rv = GetURI()->GetQuery(search);
400 if (NS_WARN_IF(NS_FAILED(rv))) {
401 search.Truncate();
404 mSearchParams->ParseInput(search);
407 void URL::SetURI(already_AddRefed<nsIURI> aURI) {
408 mURI = std::move(aURI);
409 MOZ_ASSERT(mURI);
412 nsIURI* URL::GetURI() const {
413 MOZ_ASSERT(mURI);
414 return mURI;
417 } // namespace dom
418 } // namespace mozilla