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/. */
6 
7 #include "URL.h"
8 
9 #include "DOMMediaStream.h"
10 #include "mozilla/dom/File.h"
11 #include "mozilla/dom/MediaSource.h"
12 #include "mozilla/dom/URLBinding.h"
13 #include "mozilla/dom/ipc/BlobChild.h"
14 #include "mozilla/dom/ipc/nsIRemoteBlob.h"
15 #include "mozilla/ipc/BackgroundChild.h"
16 #include "nsContentUtils.h"
17 #include "nsEscape.h"
18 #include "nsHostObjectProtocolHandler.h"
19 #include "nsIIOService.h"
20 #include "nsIURIWithQuery.h"
21 #include "nsIURL.h"
22 #include "nsNetCID.h"
23 #include "nsNetUtil.h"
24 #include "nsServiceManagerUtils.h"
25 #include "WorkerPrivate.h"
26 #include "WorkerRunnable.h"
27 #include "WorkerScope.h"
28 
29 namespace mozilla {
30 namespace dom {
31 
32 ///////////////////////////////////////////////////////////////////////////////
33 // URL for main-thread
34 ///////////////////////////////////////////////////////////////////////////////
35 
36 namespace {
37 
38 template<typename T>
39 void
CreateObjectURLInternal(const GlobalObject & aGlobal,T aObject,nsAString & aResult,ErrorResult & aRv)40 CreateObjectURLInternal(const GlobalObject& aGlobal, T aObject,
41                         nsAString& aResult, ErrorResult& aRv)
42 {
43   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
44   if (NS_WARN_IF(!global)) {
45     aRv.Throw(NS_ERROR_FAILURE);
46     return;
47   }
48 
49   nsCOMPtr<nsIPrincipal> principal =
50     nsContentUtils::ObjectPrincipal(aGlobal.Get());
51 
52   nsAutoCString url;
53   aRv = nsHostObjectProtocolHandler::AddDataEntry(aObject, principal, url);
54   if (NS_WARN_IF(aRv.Failed())) {
55     return;
56   }
57 
58   global->RegisterHostObjectURI(url);
59   CopyASCIItoUTF16(url, aResult);
60 }
61 
62 // The URL implementation for the main-thread
63 class URLMainThread final : public URL
64 {
65 public:
66   static already_AddRefed<URLMainThread>
67   Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
68               URL& aBase, ErrorResult& aRv);
69 
70   static already_AddRefed<URLMainThread>
71   Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
72               const Optional<nsAString>& aBase, ErrorResult& aRv);
73 
74   static already_AddRefed<URLMainThread>
75   Constructor(nsISupports* aParent, const nsAString& aURL,
76               const nsAString& aBase, ErrorResult& aRv);
77 
78   static already_AddRefed<URLMainThread>
79   Constructor(nsISupports* aParent, const nsAString& aURL, nsIURI* aBase,
80               ErrorResult& aRv);
81 
82   static void
CreateObjectURL(const GlobalObject & aGlobal,Blob & aBlob,const objectURLOptions & aOptions,nsAString & aResult,ErrorResult & aRv)83   CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
84                   const objectURLOptions& aOptions, nsAString& aResult,
85                   ErrorResult& aRv)
86   {
87     MOZ_ASSERT(NS_IsMainThread());
88     CreateObjectURLInternal(aGlobal, aBlob.Impl(), aResult, aRv);
89   }
90 
91   static void
CreateObjectURL(const GlobalObject & aGlobal,DOMMediaStream & aStream,const objectURLOptions & aOptions,nsAString & aResult,ErrorResult & aRv)92   CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
93                   const objectURLOptions& aOptions, nsAString& aResult,
94                   ErrorResult& aRv)
95   {
96     MOZ_ASSERT(NS_IsMainThread());
97     CreateObjectURLInternal(aGlobal, &aStream, aResult, aRv);
98   }
99 
100   static void
101   CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource,
102                   const objectURLOptions& aOptions, nsAString& aResult,
103                   ErrorResult& aRv);
104 
105   static void
106   RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL,
107                   ErrorResult& aRv);
108 
109   static bool
110   IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL,
111              ErrorResult& aRv);
112 
URLMainThread(nsISupports * aParent,already_AddRefed<nsIURI> aURI)113   URLMainThread(nsISupports* aParent, already_AddRefed<nsIURI> aURI)
114     : URL(aParent)
115     , mURI(aURI)
116   {
117     MOZ_ASSERT(NS_IsMainThread());
118   }
119 
120   virtual void
121   GetHref(nsAString& aHref, ErrorResult& aRv) const override;
122 
123   virtual void
124   SetHref(const nsAString& aHref, ErrorResult& aRv) override;
125 
126   virtual void
127   GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const override;
128 
129   virtual void
130   GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const override;
131 
132   virtual void
133   SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) override;
134 
135   virtual void
136   GetUsername(nsAString& aUsername, ErrorResult& aRv) const override;
137 
138   virtual void
139   SetUsername(const nsAString& aUsername, ErrorResult& aRv) override;
140 
141   virtual void
142   GetPassword(nsAString& aPassword, ErrorResult& aRv) const override;
143 
144   virtual void
145   SetPassword(const nsAString& aPassword, ErrorResult& aRv) override;
146 
147   virtual void
148   GetHost(nsAString& aHost, ErrorResult& aRv) const override;
149 
150   virtual void
151   SetHost(const nsAString& aHost, ErrorResult& aRv) override;
152 
153   virtual void
154   GetHostname(nsAString& aHostname, ErrorResult& aRv) const override;
155 
156   virtual void
157   SetHostname(const nsAString& aHostname, ErrorResult& aRv) override;
158 
159   virtual void
160   GetPort(nsAString& aPort, ErrorResult& aRv) const override;
161 
162   virtual void
163   SetPort(const nsAString& aPort, ErrorResult& aRv) override;
164 
165   virtual void
166   GetPathname(nsAString& aPathname, ErrorResult& aRv) const override;
167 
168   virtual void
169   SetPathname(const nsAString& aPathname, ErrorResult& aRv) override;
170 
171   virtual void
172   GetSearch(nsAString& aSearch, ErrorResult& aRv) const override;
173 
174   virtual void
175   GetHash(nsAString& aHost, ErrorResult& aRv) const override;
176 
177   virtual void
178   SetHash(const nsAString& aHash, ErrorResult& aRv) override;
179 
180   virtual void UpdateURLSearchParams() override;
181 
182   virtual void
183   SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) override;
184 
185   nsIURI*
GetURI() const186   GetURI() const
187   {
188     MOZ_ASSERT(NS_IsMainThread());
189     return mURI;
190   }
191 
192 private:
~URLMainThread()193   ~URLMainThread()
194   {
195     MOZ_ASSERT(NS_IsMainThread());
196   }
197 
198   nsCOMPtr<nsIURI> mURI;
199 };
200 
201 /* static */ already_AddRefed<URLMainThread>
Constructor(const GlobalObject & aGlobal,const nsAString & aURL,URL & aBase,ErrorResult & aRv)202 URLMainThread::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
203                            URL& aBase, ErrorResult& aRv)
204 {
205   MOZ_ASSERT(NS_IsMainThread());
206   URLMainThread& base = static_cast<URLMainThread&>(aBase);
207   return Constructor(aGlobal.GetAsSupports(), aURL, base.GetURI(), aRv);
208 }
209 
210 /* static */ already_AddRefed<URLMainThread>
Constructor(const GlobalObject & aGlobal,const nsAString & aURL,const Optional<nsAString> & aBase,ErrorResult & aRv)211 URLMainThread::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
212                            const Optional<nsAString>& aBase, ErrorResult& aRv)
213 {
214   if (aBase.WasPassed()) {
215     return Constructor(aGlobal.GetAsSupports(), aURL, aBase.Value(), aRv);
216   }
217 
218   return Constructor(aGlobal.GetAsSupports(), aURL, nullptr, aRv);
219 }
220 
221 /* static */ already_AddRefed<URLMainThread>
Constructor(nsISupports * aParent,const nsAString & aURL,const nsAString & aBase,ErrorResult & aRv)222 URLMainThread::Constructor(nsISupports* aParent, const nsAString& aURL,
223                            const nsAString& aBase, ErrorResult& aRv)
224 {
225   MOZ_ASSERT(NS_IsMainThread());
226 
227   nsCOMPtr<nsIURI> baseUri;
228   nsresult rv = NS_NewURI(getter_AddRefs(baseUri), aBase, nullptr, nullptr,
229                           nsContentUtils::GetIOService());
230   if (NS_WARN_IF(NS_FAILED(rv))) {
231     aRv.ThrowTypeError<MSG_INVALID_URL>(aBase);
232     return nullptr;
233   }
234 
235   return Constructor(aParent, aURL, baseUri, aRv);
236 }
237 
238 /* static */ already_AddRefed<URLMainThread>
Constructor(nsISupports * aParent,const nsAString & aURL,nsIURI * aBase,ErrorResult & aRv)239 URLMainThread::Constructor(nsISupports* aParent, const nsAString& aURL,
240                            nsIURI* aBase, ErrorResult& aRv)
241 {
242   MOZ_ASSERT(NS_IsMainThread());
243 
244   nsCOMPtr<nsIURI> uri;
245   nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, aBase,
246                           nsContentUtils::GetIOService());
247   if (NS_FAILED(rv)) {
248     // No need to warn in this case. It's common to use the URL constructor
249     // to determine if a URL is valid and an exception will be propagated.
250     aRv.ThrowTypeError<MSG_INVALID_URL>(aURL);
251     return nullptr;
252   }
253 
254   RefPtr<URLMainThread> url = new URLMainThread(aParent, uri.forget());
255   return url.forget();
256 }
257 
258 /* static */ void
CreateObjectURL(const GlobalObject & aGlobal,MediaSource & aSource,const objectURLOptions & aOptions,nsAString & aResult,ErrorResult & aRv)259 URLMainThread::CreateObjectURL(const GlobalObject& aGlobal,
260                                MediaSource& aSource,
261                                const objectURLOptions& aOptions,
262                                nsAString& aResult, ErrorResult& aRv)
263 {
264   MOZ_ASSERT(NS_IsMainThread());
265 
266   nsCOMPtr<nsIPrincipal> principal =
267     nsContentUtils::ObjectPrincipal(aGlobal.Get());
268 
269   nsAutoCString url;
270   aRv = nsHostObjectProtocolHandler::AddDataEntry(&aSource, principal, url);
271   if (NS_WARN_IF(aRv.Failed())) {
272     return;
273   }
274 
275   nsCOMPtr<nsIRunnable> revocation = NS_NewRunnableFunction(
276     [url] {
277       nsHostObjectProtocolHandler::RemoveDataEntry(url);
278     });
279 
280   nsContentUtils::RunInStableState(revocation.forget());
281 
282   CopyASCIItoUTF16(url, aResult);
283 }
284 
285 /* static */ void
RevokeObjectURL(const GlobalObject & aGlobal,const nsAString & aURL,ErrorResult & aRv)286 URLMainThread::RevokeObjectURL(const GlobalObject& aGlobal,
287                                const nsAString& aURL, ErrorResult& aRv)
288 {
289   MOZ_ASSERT(NS_IsMainThread());
290   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
291   if (!global) {
292     aRv.Throw(NS_ERROR_FAILURE);
293     return;
294   }
295 
296   nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal.Get());
297 
298   NS_LossyConvertUTF16toASCII asciiurl(aURL);
299 
300   nsIPrincipal* urlPrincipal =
301     nsHostObjectProtocolHandler::GetDataEntryPrincipal(asciiurl);
302 
303   if (urlPrincipal && principal->Subsumes(urlPrincipal)) {
304     global->UnregisterHostObjectURI(asciiurl);
305     nsHostObjectProtocolHandler::RemoveDataEntry(asciiurl);
306   }
307 }
308 
309 /* static */ bool
IsValidURL(const GlobalObject & aGlobal,const nsAString & aURL,ErrorResult & aRv)310 URLMainThread::IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL,
311                           ErrorResult& aRv)
312 {
313   MOZ_ASSERT(NS_IsMainThread());
314   NS_LossyConvertUTF16toASCII asciiurl(aURL);
315   return nsHostObjectProtocolHandler::HasDataEntry(asciiurl);
316 }
317 
318 void
GetHref(nsAString & aHref,ErrorResult & aRv) const319 URLMainThread::GetHref(nsAString& aHref, ErrorResult& aRv) const
320 {
321   aHref.Truncate();
322 
323   nsAutoCString href;
324   nsresult rv = mURI->GetSpec(href);
325   if (NS_SUCCEEDED(rv)) {
326     CopyUTF8toUTF16(href, aHref);
327   }
328 }
329 
330 void
SetHref(const nsAString & aHref,ErrorResult & aRv)331 URLMainThread::SetHref(const nsAString& aHref, ErrorResult& aRv)
332 {
333   NS_ConvertUTF16toUTF8 href(aHref);
334 
335   nsresult rv;
336   nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
337   if (NS_FAILED(rv)) {
338     aRv.Throw(rv);
339     return;
340   }
341 
342   nsCOMPtr<nsIURI> uri;
343   rv = ioService->NewURI(href, nullptr, nullptr, getter_AddRefs(uri));
344   if (NS_FAILED(rv)) {
345     aRv.ThrowTypeError<MSG_INVALID_URL>(aHref);
346     return;
347   }
348 
349   mURI = uri;
350   UpdateURLSearchParams();
351 }
352 
353 void
GetOrigin(nsAString & aOrigin,ErrorResult & aRv) const354 URLMainThread::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const
355 {
356   nsContentUtils::GetUTFOrigin(mURI, aOrigin);
357 }
358 
359 void
GetProtocol(nsAString & aProtocol,ErrorResult & aRv) const360 URLMainThread::GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const
361 {
362   nsAutoCString protocol;
363   if (NS_SUCCEEDED(mURI->GetScheme(protocol))) {
364     aProtocol.Truncate();
365   }
366 
367   CopyASCIItoUTF16(protocol, aProtocol);
368   aProtocol.Append(char16_t(':'));
369 }
370 
371 void
SetProtocol(const nsAString & aProtocol,ErrorResult & aRv)372 URLMainThread::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv)
373 {
374   nsAString::const_iterator start, end;
375   aProtocol.BeginReading(start);
376   aProtocol.EndReading(end);
377   nsAString::const_iterator iter(start);
378 
379   FindCharInReadable(':', iter, end);
380 
381   // Changing the protocol of a URL, changes the "nature" of the URI
382   // implementation. In order to do this properly, we have to serialize the
383   // existing URL and reparse it in a new object.
384   nsCOMPtr<nsIURI> clone;
385   nsresult rv = mURI->Clone(getter_AddRefs(clone));
386   if (NS_WARN_IF(NS_FAILED(rv)) || !clone) {
387     return;
388   }
389 
390   rv = clone->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)));
391   if (NS_WARN_IF(NS_FAILED(rv))) {
392     return;
393   }
394 
395   nsAutoCString href;
396   rv = clone->GetSpec(href);
397   if (NS_WARN_IF(NS_FAILED(rv))) {
398     return;
399   }
400 
401   nsCOMPtr<nsIURI> uri;
402   rv = NS_NewURI(getter_AddRefs(uri), href);
403   if (NS_WARN_IF(NS_FAILED(rv))) {
404     return;
405   }
406 
407   mURI = uri;
408 }
409 
410 #define URL_GETTER( value, func ) \
411   value.Truncate();               \
412   nsAutoCString tmp;              \
413   nsresult rv = mURI->func(tmp);  \
414   if (NS_SUCCEEDED(rv)) {         \
415     CopyUTF8toUTF16(tmp, value);  \
416   }
417 
418 void
GetUsername(nsAString & aUsername,ErrorResult & aRv) const419 URLMainThread::GetUsername(nsAString& aUsername, ErrorResult& aRv) const
420 {
421   URL_GETTER(aUsername, GetUsername);
422 }
423 
424 void
SetUsername(const nsAString & aUsername,ErrorResult & aRv)425 URLMainThread::SetUsername(const nsAString& aUsername, ErrorResult& aRv)
426 {
427   mURI->SetUsername(NS_ConvertUTF16toUTF8(aUsername));
428 }
429 
430 void
GetPassword(nsAString & aPassword,ErrorResult & aRv) const431 URLMainThread::GetPassword(nsAString& aPassword, ErrorResult& aRv) const
432 {
433   URL_GETTER(aPassword, GetPassword);
434 }
435 
436 void
SetPassword(const nsAString & aPassword,ErrorResult & aRv)437 URLMainThread::SetPassword(const nsAString& aPassword, ErrorResult& aRv)
438 {
439   mURI->SetPassword(NS_ConvertUTF16toUTF8(aPassword));
440 }
441 
442 void
GetHost(nsAString & aHost,ErrorResult & aRv) const443 URLMainThread::GetHost(nsAString& aHost, ErrorResult& aRv) const
444 {
445   URL_GETTER(aHost, GetHostPort);
446 }
447 
448 void
SetHost(const nsAString & aHost,ErrorResult & aRv)449 URLMainThread::SetHost(const nsAString& aHost, ErrorResult& aRv)
450 {
451   mURI->SetHostPort(NS_ConvertUTF16toUTF8(aHost));
452 }
453 
454 void
UpdateURLSearchParams()455 URLMainThread::UpdateURLSearchParams()
456 {
457   if (!mSearchParams) {
458     return;
459   }
460 
461   nsAutoCString search;
462   nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
463   if (url) {
464     nsresult rv = url->GetQuery(search);
465     if (NS_WARN_IF(NS_FAILED(rv))) {
466       search.Truncate();
467     }
468   }
469 
470   mSearchParams->ParseInput(search);
471 }
472 
473 void
GetHostname(nsAString & aHostname,ErrorResult & aRv) const474 URLMainThread::GetHostname(nsAString& aHostname, ErrorResult& aRv) const
475 {
476   aHostname.Truncate();
477   nsContentUtils::GetHostOrIPv6WithBrackets(mURI, aHostname);
478 }
479 
480 void
SetHostname(const nsAString & aHostname,ErrorResult & aRv)481 URLMainThread::SetHostname(const nsAString& aHostname, ErrorResult& aRv)
482 {
483   // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname
484   // The return code is silently ignored
485   mURI->SetHost(NS_ConvertUTF16toUTF8(aHostname));
486 }
487 
488 void
GetPort(nsAString & aPort,ErrorResult & aRv) const489 URLMainThread::GetPort(nsAString& aPort, ErrorResult& aRv) const
490 {
491   aPort.Truncate();
492 
493   int32_t port;
494   nsresult rv = mURI->GetPort(&port);
495   if (NS_SUCCEEDED(rv) && port != -1) {
496     nsAutoString portStr;
497     portStr.AppendInt(port, 10);
498     aPort.Assign(portStr);
499   }
500 }
501 
502 void
SetPort(const nsAString & aPort,ErrorResult & aRv)503 URLMainThread::SetPort(const nsAString& aPort, ErrorResult& aRv)
504 {
505   nsresult rv;
506   nsAutoString portStr(aPort);
507   int32_t port = -1;
508 
509   // nsIURI uses -1 as default value.
510   if (!portStr.IsEmpty()) {
511     port = portStr.ToInteger(&rv);
512     if (NS_FAILED(rv)) {
513       return;
514     }
515   }
516 
517   mURI->SetPort(port);
518 }
519 
520 void
GetPathname(nsAString & aPathname,ErrorResult & aRv) const521 URLMainThread::GetPathname(nsAString& aPathname, ErrorResult& aRv) const
522 {
523   aPathname.Truncate();
524 
525   // Do not throw!  Not having a valid URI or URL should result in an empty
526   // string.
527 
528   nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI));
529   if (url) {
530     nsAutoCString file;
531     nsresult rv = url->GetFilePath(file);
532     if (NS_SUCCEEDED(rv)) {
533       CopyUTF8toUTF16(file, aPathname);
534     }
535 
536     return;
537   }
538 
539   nsAutoCString path;
540   nsresult rv = mURI->GetPath(path);
541   if (NS_SUCCEEDED(rv)) {
542     CopyUTF8toUTF16(path, aPathname);
543   }
544 }
545 
546 void
SetPathname(const nsAString & aPathname,ErrorResult & aRv)547 URLMainThread::SetPathname(const nsAString& aPathname, ErrorResult& aRv)
548 {
549   // Do not throw!
550 
551   nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI));
552   if (url) {
553     url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
554     return;
555   }
556 }
557 
558 void
GetSearch(nsAString & aSearch,ErrorResult & aRv) const559 URLMainThread::GetSearch(nsAString& aSearch, ErrorResult& aRv) const
560 {
561   aSearch.Truncate();
562 
563   // Do not throw!  Not having a valid URI or URL should result in an empty
564   // string.
565 
566   nsAutoCString search;
567   nsresult rv;
568 
569   nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI));
570   if (url) {
571     rv = url->GetQuery(search);
572     if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
573       CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
574     }
575     return;
576   }
577 }
578 
579 void
GetHash(nsAString & aHash,ErrorResult & aRv) const580 URLMainThread::GetHash(nsAString& aHash, ErrorResult& aRv) const
581 {
582   aHash.Truncate();
583 
584   nsAutoCString ref;
585   nsresult rv = mURI->GetRef(ref);
586   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
587     aHash.Assign(char16_t('#'));
588     if (nsContentUtils::GettersDecodeURLHash()) {
589       NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
590     }
591     AppendUTF8toUTF16(ref, aHash);
592   }
593 }
594 
595 void
SetHash(const nsAString & aHash,ErrorResult & aRv)596 URLMainThread::SetHash(const nsAString& aHash, ErrorResult& aRv)
597 {
598   mURI->SetRef(NS_ConvertUTF16toUTF8(aHash));
599 }
600 
601 void
SetSearchInternal(const nsAString & aSearch,ErrorResult & aRv)602 URLMainThread::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv)
603 {
604   // Ignore failures to be compatible with NS4.
605 
606   nsCOMPtr<nsIURIWithQuery> uriWithQuery(do_QueryInterface(mURI));
607   if (uriWithQuery) {
608     uriWithQuery->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
609     return;
610   }
611 }
612 
613 } // anonymous namespace
614 
615 ///////////////////////////////////////////////////////////////////////////////
616 // URL for Workers
617 ///////////////////////////////////////////////////////////////////////////////
618 
619 namespace {
620 
621 using namespace workers;
622 
623 // Proxy class to forward all the requests to a URLMainThread object.
624 class URLProxy final
625 {
626 public:
627   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLProxy)
628 
URLProxy(already_AddRefed<URLMainThread> aURL)629   explicit URLProxy(already_AddRefed<URLMainThread> aURL)
630     : mURL(aURL)
631   {
632     MOZ_ASSERT(NS_IsMainThread());
633   }
634 
URL()635   URLMainThread* URL()
636   {
637     MOZ_ASSERT(NS_IsMainThread());
638     return mURL;
639   }
640 
URI()641   nsIURI* URI()
642   {
643     MOZ_ASSERT(NS_IsMainThread());
644     return mURL->GetURI();
645   }
646 
ReleaseURI()647   void ReleaseURI()
648   {
649     MOZ_ASSERT(NS_IsMainThread());
650     mURL = nullptr;
651   }
652 
653 private:
654   // Private destructor, to discourage deletion outside of Release():
~URLProxy()655   ~URLProxy()
656   {
657      MOZ_ASSERT(!mURL);
658   }
659 
660   RefPtr<URLMainThread> mURL;
661 };
662 
663 // URLWorker implements the URL object in workers.
664 class URLWorker final : public URL
665 {
666 public:
667   static already_AddRefed<URLWorker>
668   Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
669               URL& aBase, ErrorResult& aRv);
670 
671   static already_AddRefed<URLWorker>
672   Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
673               const Optional<nsAString>& aBase, ErrorResult& aRv);
674 
675   static already_AddRefed<URLWorker>
676   Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
677               const nsAString& aBase, ErrorResult& aRv);
678 
679   static void
680   CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
681                   const mozilla::dom::objectURLOptions& aOptions,
682                   nsAString& aResult, mozilla::ErrorResult& aRv);
683 
684   static void
685   RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl,
686                   ErrorResult& aRv);
687 
688   static bool
689   IsValidURL(const GlobalObject& aGlobal, const nsAString& aUrl,
690              ErrorResult& aRv);
691 
692   URLWorker(WorkerPrivate* aWorkerPrivate, URLProxy* aURLProxy);
693 
694   virtual void
695   GetHref(nsAString& aHref, ErrorResult& aRv) const override;
696 
697   virtual void
698   SetHref(const nsAString& aHref, ErrorResult& aRv) override;
699 
700   virtual void
701   GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const override;
702 
703   virtual void
704   GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const override;
705 
706   virtual void
707   SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) override;
708 
709   virtual void
710   GetUsername(nsAString& aUsername, ErrorResult& aRv) const override;
711 
712   virtual void
713   SetUsername(const nsAString& aUsername, ErrorResult& aRv) override;
714 
715   virtual void
716   GetPassword(nsAString& aPassword, ErrorResult& aRv) const override;
717 
718   virtual void
719   SetPassword(const nsAString& aPassword, ErrorResult& aRv) override;
720 
721   virtual void
722   GetHost(nsAString& aHost, ErrorResult& aRv) const override;
723 
724   virtual void
725   SetHost(const nsAString& aHost, ErrorResult& aRv) override;
726 
727   virtual void
728   GetHostname(nsAString& aHostname, ErrorResult& aRv) const override;
729 
730   virtual void
731   SetHostname(const nsAString& aHostname, ErrorResult& aRv) override;
732 
733   virtual void
734   GetPort(nsAString& aPort, ErrorResult& aRv) const override;
735 
736   virtual void
737   SetPort(const nsAString& aPort, ErrorResult& aRv) override;
738 
739   virtual void
740   GetPathname(nsAString& aPathname, ErrorResult& aRv) const override;
741 
742   virtual void
743   SetPathname(const nsAString& aPathname, ErrorResult& aRv) override;
744 
745   virtual void
746   GetSearch(nsAString& aSearch, ErrorResult& aRv) const override;
747 
748   virtual void
749   GetHash(nsAString& aHost, ErrorResult& aRv) const override;
750 
751   virtual void
752   SetHash(const nsAString& aHash, ErrorResult& aRv) override;
753 
754   virtual void UpdateURLSearchParams() override;
755 
756   virtual void
757   SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) override;
758 
759   URLProxy*
GetURLProxy() const760   GetURLProxy() const
761   {
762     mWorkerPrivate->AssertIsOnWorkerThread();
763     return mURLProxy;
764   }
765 
766 private:
767   ~URLWorker();
768 
769   workers::WorkerPrivate* mWorkerPrivate;
770   RefPtr<URLProxy> mURLProxy;
771 };
772 
773 // This class creates an URL from a DOM Blob on the main thread.
774 class CreateURLRunnable : public WorkerMainThreadRunnable
775 {
776 private:
777   BlobImpl* mBlobImpl;
778   nsAString& mURL;
779 
780 public:
CreateURLRunnable(WorkerPrivate * aWorkerPrivate,BlobImpl * aBlobImpl,const objectURLOptions & aOptions,nsAString & aURL)781   CreateURLRunnable(WorkerPrivate* aWorkerPrivate, BlobImpl* aBlobImpl,
782                     const objectURLOptions& aOptions,
783                     nsAString& aURL)
784   : WorkerMainThreadRunnable(aWorkerPrivate,
785                              NS_LITERAL_CSTRING("URL :: CreateURL"))
786   , mBlobImpl(aBlobImpl)
787   , mURL(aURL)
788   {
789     MOZ_ASSERT(aBlobImpl);
790 
791     DebugOnly<bool> isMutable;
792     MOZ_ASSERT(NS_SUCCEEDED(aBlobImpl->GetMutable(&isMutable)));
793     MOZ_ASSERT(!isMutable);
794   }
795 
796   bool
MainThreadRun()797   MainThreadRun()
798   {
799     using namespace mozilla::ipc;
800 
801     AssertIsOnMainThread();
802 
803     RefPtr<BlobImpl> newBlobImplHolder;
804 
805     if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(mBlobImpl)) {
806       if (BlobChild* blobChild = remoteBlob->GetBlobChild()) {
807         if (PBackgroundChild* blobManager = blobChild->GetBackgroundManager()) {
808           PBackgroundChild* backgroundManager =
809             BackgroundChild::GetForCurrentThread();
810           MOZ_ASSERT(backgroundManager);
811 
812           if (blobManager != backgroundManager) {
813             // Always make sure we have a blob from an actor we can use on this
814             // thread.
815             blobChild = BlobChild::GetOrCreate(backgroundManager, mBlobImpl);
816             MOZ_ASSERT(blobChild);
817 
818             newBlobImplHolder = blobChild->GetBlobImpl();
819             MOZ_ASSERT(newBlobImplHolder);
820 
821             mBlobImpl = newBlobImplHolder;
822           }
823         }
824       }
825     }
826 
827     DebugOnly<bool> isMutable;
828     MOZ_ASSERT(NS_SUCCEEDED(mBlobImpl->GetMutable(&isMutable)));
829     MOZ_ASSERT(!isMutable);
830 
831     nsCOMPtr<nsIPrincipal> principal = mWorkerPrivate->GetPrincipal();
832 
833     nsAutoCString url;
834     nsresult rv =
835       nsHostObjectProtocolHandler::AddDataEntry(mBlobImpl, principal, url);
836 
837     if (NS_FAILED(rv)) {
838       NS_WARNING("Failed to add data entry for the blob!");
839       SetDOMStringToNull(mURL);
840       return false;
841     }
842 
843     if (!mWorkerPrivate->IsSharedWorker() &&
844         !mWorkerPrivate->IsServiceWorker()) {
845       // Walk up to top worker object.
846       WorkerPrivate* wp = mWorkerPrivate;
847       while (WorkerPrivate* parent = wp->GetParent()) {
848         wp = parent;
849       }
850 
851       nsCOMPtr<nsIScriptContext> sc = wp->GetScriptContext();
852       // We could not have a ScriptContext in JSM code. In this case, we leak.
853       if (sc) {
854         nsCOMPtr<nsIGlobalObject> global = sc->GetGlobalObject();
855         MOZ_ASSERT(global);
856 
857         global->RegisterHostObjectURI(url);
858       }
859     }
860 
861     mURL = NS_ConvertUTF8toUTF16(url);
862     return true;
863   }
864 };
865 
866 // This class revokes an URL on the main thread.
867 class RevokeURLRunnable : public WorkerMainThreadRunnable
868 {
869 private:
870   const nsString mURL;
871 
872 public:
RevokeURLRunnable(WorkerPrivate * aWorkerPrivate,const nsAString & aURL)873   RevokeURLRunnable(WorkerPrivate* aWorkerPrivate,
874                     const nsAString& aURL)
875   : WorkerMainThreadRunnable(aWorkerPrivate,
876                              NS_LITERAL_CSTRING("URL :: RevokeURL"))
877   , mURL(aURL)
878   {}
879 
880   bool
MainThreadRun()881   MainThreadRun()
882   {
883     AssertIsOnMainThread();
884 
885     NS_ConvertUTF16toUTF8 url(mURL);
886 
887     nsIPrincipal* urlPrincipal =
888       nsHostObjectProtocolHandler::GetDataEntryPrincipal(url);
889 
890     nsCOMPtr<nsIPrincipal> principal = mWorkerPrivate->GetPrincipal();
891 
892     bool subsumes;
893     if (urlPrincipal &&
894         NS_SUCCEEDED(principal->Subsumes(urlPrincipal, &subsumes)) &&
895         subsumes) {
896       nsHostObjectProtocolHandler::RemoveDataEntry(url);
897     }
898 
899     if (!mWorkerPrivate->IsSharedWorker() &&
900         !mWorkerPrivate->IsServiceWorker()) {
901       // Walk up to top worker object.
902       WorkerPrivate* wp = mWorkerPrivate;
903       while (WorkerPrivate* parent = wp->GetParent()) {
904         wp = parent;
905       }
906 
907       nsCOMPtr<nsIScriptContext> sc = wp->GetScriptContext();
908       // We could not have a ScriptContext in JSM code. In this case, we leak.
909       if (sc) {
910         nsCOMPtr<nsIGlobalObject> global = sc->GetGlobalObject();
911         MOZ_ASSERT(global);
912 
913         global->UnregisterHostObjectURI(url);
914       }
915     }
916 
917     return true;
918   }
919 };
920 
921 // This class checks if an URL is valid on the main thread.
922 class IsValidURLRunnable : public WorkerMainThreadRunnable
923 {
924 private:
925   const nsString mURL;
926   bool mValid;
927 
928 public:
IsValidURLRunnable(WorkerPrivate * aWorkerPrivate,const nsAString & aURL)929   IsValidURLRunnable(WorkerPrivate* aWorkerPrivate,
930                      const nsAString& aURL)
931   : WorkerMainThreadRunnable(aWorkerPrivate,
932                              NS_LITERAL_CSTRING("URL :: IsValidURL"))
933   , mURL(aURL)
934   , mValid(false)
935   {}
936 
937   bool
MainThreadRun()938   MainThreadRun()
939   {
940     AssertIsOnMainThread();
941 
942     NS_ConvertUTF16toUTF8 url(mURL);
943     mValid = nsHostObjectProtocolHandler::HasDataEntry(url);
944 
945     return true;
946   }
947 
948   bool
IsValidURL() const949   IsValidURL() const
950   {
951     return mValid;
952   }
953 };
954 
955 // This class creates a URL object on the main thread.
956 class ConstructorRunnable : public WorkerMainThreadRunnable
957 {
958 private:
959   const nsString mURL;
960 
961   nsString mBase; // IsVoid() if we have no base URI string.
962   RefPtr<URLProxy> mBaseProxy;
963 
964   RefPtr<URLProxy> mRetval;
965 
966 public:
ConstructorRunnable(WorkerPrivate * aWorkerPrivate,const nsAString & aURL,const Optional<nsAString> & aBase)967   ConstructorRunnable(WorkerPrivate* aWorkerPrivate,
968                       const nsAString& aURL, const Optional<nsAString>& aBase)
969   : WorkerMainThreadRunnable(aWorkerPrivate,
970                              NS_LITERAL_CSTRING("URL :: Constructor"))
971   , mURL(aURL)
972   {
973     if (aBase.WasPassed()) {
974       mBase = aBase.Value();
975     } else {
976       mBase.SetIsVoid(true);
977     }
978     mWorkerPrivate->AssertIsOnWorkerThread();
979   }
980 
ConstructorRunnable(WorkerPrivate * aWorkerPrivate,const nsAString & aURL,URLProxy * aBaseProxy)981   ConstructorRunnable(WorkerPrivate* aWorkerPrivate,
982                       const nsAString& aURL, URLProxy* aBaseProxy)
983   : WorkerMainThreadRunnable(aWorkerPrivate,
984                              NS_LITERAL_CSTRING("URL :: Constructor with BaseURL"))
985   , mURL(aURL)
986   , mBaseProxy(aBaseProxy)
987   {
988     mBase.SetIsVoid(true);
989     mWorkerPrivate->AssertIsOnWorkerThread();
990   }
991 
992   bool
MainThreadRun()993   MainThreadRun()
994   {
995     AssertIsOnMainThread();
996 
997     ErrorResult rv;
998     RefPtr<URLMainThread> url;
999     if (mBaseProxy) {
1000       url = URLMainThread::Constructor(nullptr, mURL, mBaseProxy->URI(), rv);
1001     } else if (!mBase.IsVoid()) {
1002       url = URLMainThread::Constructor(nullptr, mURL, mBase, rv);
1003     } else {
1004       url = URLMainThread::Constructor(nullptr, mURL, nullptr, rv);
1005     }
1006 
1007     if (rv.Failed()) {
1008       rv.SuppressException();
1009       return true;
1010     }
1011 
1012     mRetval = new URLProxy(url.forget());
1013     return true;
1014   }
1015 
1016   URLProxy*
GetURLProxy(ErrorResult & aRv) const1017   GetURLProxy(ErrorResult& aRv) const
1018   {
1019     MOZ_ASSERT(mWorkerPrivate);
1020     mWorkerPrivate->AssertIsOnWorkerThread();
1021 
1022     if (!mRetval) {
1023       aRv.ThrowTypeError<MSG_INVALID_URL>(mURL);
1024     }
1025 
1026     return mRetval;
1027   }
1028 };
1029 
1030 class TeardownURLRunnable : public Runnable
1031 {
1032 public:
TeardownURLRunnable(URLProxy * aURLProxy)1033   explicit TeardownURLRunnable(URLProxy* aURLProxy)
1034     : mURLProxy(aURLProxy)
1035   {
1036   }
1037 
Run()1038   NS_IMETHOD Run()
1039   {
1040     AssertIsOnMainThread();
1041 
1042     mURLProxy->ReleaseURI();
1043     mURLProxy = nullptr;
1044 
1045     return NS_OK;
1046   }
1047 
1048 private:
1049   RefPtr<URLProxy> mURLProxy;
1050 };
1051 
1052 // This class is the generic getter for any URL property.
1053 class GetterRunnable : public WorkerMainThreadRunnable
1054 {
1055 public:
1056   enum GetterType {
1057     GetterHref,
1058     GetterOrigin,
1059     GetterProtocol,
1060     GetterUsername,
1061     GetterPassword,
1062     GetterHost,
1063     GetterHostname,
1064     GetterPort,
1065     GetterPathname,
1066     GetterSearch,
1067     GetterHash,
1068   };
1069 
GetterRunnable(WorkerPrivate * aWorkerPrivate,GetterType aType,nsAString & aValue,URLProxy * aURLProxy)1070   GetterRunnable(WorkerPrivate* aWorkerPrivate,
1071                  GetterType aType, nsAString& aValue,
1072                  URLProxy* aURLProxy)
1073   : WorkerMainThreadRunnable(aWorkerPrivate,
1074                              // We can have telemetry keys for each getter when
1075                              // needed.
1076                              NS_LITERAL_CSTRING("URL :: getter"))
1077   , mValue(aValue)
1078   , mType(aType)
1079   , mURLProxy(aURLProxy)
1080   {
1081     mWorkerPrivate->AssertIsOnWorkerThread();
1082   }
1083 
1084   bool
MainThreadRun()1085   MainThreadRun()
1086   {
1087     AssertIsOnMainThread();
1088     ErrorResult rv;
1089 
1090     switch (mType) {
1091       case GetterHref:
1092         mURLProxy->URL()->GetHref(mValue, rv);
1093         break;
1094 
1095       case GetterOrigin:
1096         mURLProxy->URL()->GetOrigin(mValue, rv);
1097         break;
1098 
1099       case GetterProtocol:
1100         mURLProxy->URL()->GetProtocol(mValue, rv);
1101         break;
1102 
1103       case GetterUsername:
1104         mURLProxy->URL()->GetUsername(mValue, rv);
1105         break;
1106 
1107       case GetterPassword:
1108         mURLProxy->URL()->GetPassword(mValue, rv);
1109         break;
1110 
1111       case GetterHost:
1112         mURLProxy->URL()->GetHost(mValue, rv);
1113         break;
1114 
1115       case GetterHostname:
1116         mURLProxy->URL()->GetHostname(mValue, rv);
1117         break;
1118 
1119       case GetterPort:
1120         mURLProxy->URL()->GetPort(mValue, rv);
1121         break;
1122 
1123       case GetterPathname:
1124         mURLProxy->URL()->GetPathname(mValue, rv);
1125         break;
1126 
1127       case GetterSearch:
1128         mURLProxy->URL()->GetSearch(mValue, rv);
1129         break;
1130 
1131       case GetterHash:
1132         mURLProxy->URL()->GetHash(mValue, rv);
1133         break;
1134     }
1135 
1136     MOZ_ASSERT(!rv.Failed(), "Main-thread getters do not fail.");
1137     return true;
1138   }
1139 
1140 private:
1141   nsAString& mValue;
1142   GetterType mType;
1143   RefPtr<URLProxy> mURLProxy;
1144 };
1145 
1146 // This class is the generic setter for any URL property.
1147 class SetterRunnable : public WorkerMainThreadRunnable
1148 {
1149 public:
1150   enum SetterType {
1151     SetterHref,
1152     SetterProtocol,
1153     SetterUsername,
1154     SetterPassword,
1155     SetterHost,
1156     SetterHostname,
1157     SetterPort,
1158     SetterPathname,
1159     SetterSearch,
1160     SetterHash,
1161   };
1162 
SetterRunnable(WorkerPrivate * aWorkerPrivate,SetterType aType,const nsAString & aValue,URLProxy * aURLProxy)1163   SetterRunnable(WorkerPrivate* aWorkerPrivate,
1164                  SetterType aType, const nsAString& aValue,
1165                  URLProxy* aURLProxy)
1166   : WorkerMainThreadRunnable(aWorkerPrivate,
1167                              // We can have telemetry keys for each setter when
1168                              // needed.
1169                              NS_LITERAL_CSTRING("URL :: setter"))
1170   , mValue(aValue)
1171   , mType(aType)
1172   , mURLProxy(aURLProxy)
1173   , mFailed(false)
1174   {
1175     mWorkerPrivate->AssertIsOnWorkerThread();
1176   }
1177 
1178   bool
MainThreadRun()1179   MainThreadRun()
1180   {
1181     AssertIsOnMainThread();
1182     ErrorResult rv;
1183 
1184     switch (mType) {
1185       case SetterHref: {
1186         mURLProxy->URL()->SetHref(mValue, rv);
1187         break;
1188       }
1189 
1190       case SetterProtocol:
1191         mURLProxy->URL()->SetProtocol(mValue, rv);
1192         break;
1193 
1194       case SetterUsername:
1195         mURLProxy->URL()->SetUsername(mValue, rv);
1196         break;
1197 
1198       case SetterPassword:
1199         mURLProxy->URL()->SetPassword(mValue, rv);
1200         break;
1201 
1202       case SetterHost:
1203         mURLProxy->URL()->SetHost(mValue, rv);
1204         break;
1205 
1206       case SetterHostname:
1207         mURLProxy->URL()->SetHostname(mValue, rv);
1208         break;
1209 
1210       case SetterPort:
1211         mURLProxy->URL()->SetPort(mValue, rv);
1212         break;
1213 
1214       case SetterPathname:
1215         mURLProxy->URL()->SetPathname(mValue, rv);
1216         break;
1217 
1218       case SetterSearch:
1219         mURLProxy->URL()->SetSearch(mValue, rv);
1220         break;
1221 
1222       case SetterHash:
1223         mURLProxy->URL()->SetHash(mValue, rv);
1224         break;
1225     }
1226 
1227     if (NS_WARN_IF(rv.Failed())) {
1228       rv.SuppressException();
1229       mFailed = true;
1230     }
1231 
1232     return true;
1233   }
1234 
Failed() const1235   bool Failed() const
1236   {
1237     return mFailed;
1238   }
1239 
1240 private:
1241   const nsString mValue;
1242   SetterType mType;
1243   RefPtr<URLProxy> mURLProxy;
1244   bool mFailed;
1245 };
1246 
1247 already_AddRefed<URLWorker>
FinishConstructor(JSContext * aCx,WorkerPrivate * aPrivate,ConstructorRunnable * aRunnable,ErrorResult & aRv)1248 FinishConstructor(JSContext* aCx, WorkerPrivate* aPrivate,
1249                   ConstructorRunnable* aRunnable, ErrorResult& aRv)
1250 {
1251   aRunnable->Dispatch(aRv);
1252   if (NS_WARN_IF(aRv.Failed())) {
1253     return nullptr;
1254   }
1255 
1256   RefPtr<URLProxy> proxy = aRunnable->GetURLProxy(aRv);
1257   if (NS_WARN_IF(aRv.Failed())) {
1258     return nullptr;
1259   }
1260 
1261   RefPtr<URLWorker> url = new URLWorker(aPrivate, proxy);
1262   return url.forget();
1263 }
1264 
1265 /* static */ already_AddRefed<URLWorker>
Constructor(const GlobalObject & aGlobal,const nsAString & aURL,URL & aBase,ErrorResult & aRv)1266 URLWorker::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
1267                        URL& aBase, ErrorResult& aRv)
1268 {
1269   MOZ_ASSERT(!NS_IsMainThread());
1270 
1271   JSContext* cx = aGlobal.Context();
1272   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
1273 
1274   URLWorker& base = static_cast<URLWorker&>(aBase);
1275   RefPtr<ConstructorRunnable> runnable =
1276     new ConstructorRunnable(workerPrivate, aURL, base.GetURLProxy());
1277 
1278   return FinishConstructor(cx, workerPrivate, runnable, aRv);
1279 }
1280 
1281 /* static */ already_AddRefed<URLWorker>
Constructor(const GlobalObject & aGlobal,const nsAString & aURL,const Optional<nsAString> & aBase,ErrorResult & aRv)1282 URLWorker::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
1283                        const Optional<nsAString>& aBase, ErrorResult& aRv)
1284 {
1285   JSContext* cx = aGlobal.Context();
1286   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
1287 
1288   RefPtr<ConstructorRunnable> runnable =
1289     new ConstructorRunnable(workerPrivate, aURL, aBase);
1290 
1291   return FinishConstructor(cx, workerPrivate, runnable, aRv);
1292 }
1293 
1294 /* static */ already_AddRefed<URLWorker>
Constructor(const GlobalObject & aGlobal,const nsAString & aURL,const nsAString & aBase,ErrorResult & aRv)1295 URLWorker::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
1296                        const nsAString& aBase, ErrorResult& aRv)
1297 {
1298   JSContext* cx = aGlobal.Context();
1299   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
1300 
1301   Optional<nsAString> base;
1302   base = &aBase;
1303 
1304   RefPtr<ConstructorRunnable> runnable =
1305     new ConstructorRunnable(workerPrivate, aURL, base);
1306 
1307   return FinishConstructor(cx, workerPrivate, runnable, aRv);
1308 }
1309 
1310 /* static */ void
CreateObjectURL(const GlobalObject & aGlobal,Blob & aBlob,const mozilla::dom::objectURLOptions & aOptions,nsAString & aResult,mozilla::ErrorResult & aRv)1311 URLWorker::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
1312                            const mozilla::dom::objectURLOptions& aOptions,
1313                            nsAString& aResult, mozilla::ErrorResult& aRv)
1314 {
1315   JSContext* cx = aGlobal.Context();
1316   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
1317 
1318   RefPtr<BlobImpl> blobImpl = aBlob.Impl();
1319   MOZ_ASSERT(blobImpl);
1320 
1321   aRv = blobImpl->SetMutable(false);
1322   if (NS_WARN_IF(aRv.Failed())) {
1323     return;
1324   }
1325 
1326   RefPtr<CreateURLRunnable> runnable =
1327     new CreateURLRunnable(workerPrivate, blobImpl, aOptions, aResult);
1328 
1329   runnable->Dispatch(aRv);
1330   if (NS_WARN_IF(aRv.Failed())) {
1331     return;
1332   }
1333 
1334   if (workerPrivate->IsSharedWorker() || workerPrivate->IsServiceWorker()) {
1335     WorkerGlobalScope* scope = workerPrivate->GlobalScope();
1336     MOZ_ASSERT(scope);
1337 
1338     scope->RegisterHostObjectURI(NS_ConvertUTF16toUTF8(aResult));
1339   }
1340 }
1341 
1342 /* static */ void
RevokeObjectURL(const GlobalObject & aGlobal,const nsAString & aUrl,ErrorResult & aRv)1343 URLWorker::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl,
1344                            ErrorResult& aRv)
1345 {
1346   JSContext* cx = aGlobal.Context();
1347   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
1348 
1349   RefPtr<RevokeURLRunnable> runnable =
1350     new RevokeURLRunnable(workerPrivate, aUrl);
1351 
1352   runnable->Dispatch(aRv);
1353   if (NS_WARN_IF(aRv.Failed())) {
1354     return;
1355   }
1356 
1357   if (workerPrivate->IsSharedWorker() || workerPrivate->IsServiceWorker()) {
1358     WorkerGlobalScope* scope = workerPrivate->GlobalScope();
1359     MOZ_ASSERT(scope);
1360 
1361     scope->UnregisterHostObjectURI(NS_ConvertUTF16toUTF8(aUrl));
1362   }
1363 }
1364 
1365 /* static */ bool
IsValidURL(const GlobalObject & aGlobal,const nsAString & aUrl,ErrorResult & aRv)1366 URLWorker::IsValidURL(const GlobalObject& aGlobal, const nsAString& aUrl,
1367                       ErrorResult& aRv)
1368 {
1369   JSContext* cx = aGlobal.Context();
1370   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
1371 
1372   RefPtr<IsValidURLRunnable> runnable =
1373     new IsValidURLRunnable(workerPrivate, aUrl);
1374 
1375   runnable->Dispatch(aRv);
1376   if (NS_WARN_IF(aRv.Failed())) {
1377     return false;
1378   }
1379 
1380   return runnable->IsValidURL();
1381 }
1382 
URLWorker(WorkerPrivate * aWorkerPrivate,URLProxy * aURLProxy)1383 URLWorker::URLWorker(WorkerPrivate* aWorkerPrivate, URLProxy* aURLProxy)
1384   : URL(nullptr)
1385   , mWorkerPrivate(aWorkerPrivate)
1386   , mURLProxy(aURLProxy)
1387 {}
1388 
~URLWorker()1389 URLWorker::~URLWorker()
1390 {
1391   if (mURLProxy) {
1392     mWorkerPrivate->AssertIsOnWorkerThread();
1393 
1394     RefPtr<TeardownURLRunnable> runnable =
1395       new TeardownURLRunnable(mURLProxy);
1396     mURLProxy = nullptr;
1397 
1398     if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
1399       NS_ERROR("Failed to dispatch teardown runnable!");
1400     }
1401   }
1402 }
1403 
1404 void
GetHref(nsAString & aHref,ErrorResult & aRv) const1405 URLWorker::GetHref(nsAString& aHref, ErrorResult& aRv) const
1406 {
1407   RefPtr<GetterRunnable> runnable =
1408     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHref, aHref,
1409                        mURLProxy);
1410 
1411   runnable->Dispatch(aRv);
1412 }
1413 
1414 void
SetHref(const nsAString & aHref,ErrorResult & aRv)1415 URLWorker::SetHref(const nsAString& aHref, ErrorResult& aRv)
1416 {
1417   RefPtr<SetterRunnable> runnable =
1418     new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHref, aHref,
1419                        mURLProxy);
1420 
1421   runnable->Dispatch(aRv);
1422   if (NS_WARN_IF(aRv.Failed())) {
1423     return;
1424   }
1425 
1426   if (runnable->Failed()) {
1427     aRv.ThrowTypeError<MSG_INVALID_URL>(aHref);
1428     return;
1429   }
1430 
1431   UpdateURLSearchParams();
1432 }
1433 
1434 void
GetOrigin(nsAString & aOrigin,ErrorResult & aRv) const1435 URLWorker::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const
1436 {
1437   RefPtr<GetterRunnable> runnable =
1438     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterOrigin, aOrigin,
1439                        mURLProxy);
1440 
1441   runnable->Dispatch(aRv);
1442 }
1443 
1444 void
GetProtocol(nsAString & aProtocol,ErrorResult & aRv) const1445 URLWorker::GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const
1446 {
1447   RefPtr<GetterRunnable> runnable =
1448     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterProtocol, aProtocol,
1449                        mURLProxy);
1450 
1451   runnable->Dispatch(aRv);
1452 }
1453 
1454 void
SetProtocol(const nsAString & aProtocol,ErrorResult & aRv)1455 URLWorker::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv)
1456 {
1457   RefPtr<SetterRunnable> runnable =
1458     new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterProtocol,
1459                        aProtocol, mURLProxy);
1460 
1461   runnable->Dispatch(aRv);
1462 
1463   MOZ_ASSERT(!runnable->Failed());
1464 }
1465 
1466 void
GetUsername(nsAString & aUsername,ErrorResult & aRv) const1467 URLWorker::GetUsername(nsAString& aUsername, ErrorResult& aRv) const
1468 {
1469   RefPtr<GetterRunnable> runnable =
1470     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterUsername, aUsername,
1471                        mURLProxy);
1472 
1473   runnable->Dispatch(aRv);
1474 }
1475 
1476 void
SetUsername(const nsAString & aUsername,ErrorResult & aRv)1477 URLWorker::SetUsername(const nsAString& aUsername, ErrorResult& aRv)
1478 {
1479   RefPtr<SetterRunnable> runnable =
1480     new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterUsername,
1481                        aUsername, mURLProxy);
1482 
1483   runnable->Dispatch(aRv);
1484   if (NS_WARN_IF(aRv.Failed())) {
1485     return;
1486   }
1487 
1488   MOZ_ASSERT(!runnable->Failed());
1489 }
1490 
1491 void
GetPassword(nsAString & aPassword,ErrorResult & aRv) const1492 URLWorker::GetPassword(nsAString& aPassword, ErrorResult& aRv) const
1493 {
1494   RefPtr<GetterRunnable> runnable =
1495     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPassword, aPassword,
1496                        mURLProxy);
1497 
1498   runnable->Dispatch(aRv);
1499 }
1500 
1501 void
SetPassword(const nsAString & aPassword,ErrorResult & aRv)1502 URLWorker::SetPassword(const nsAString& aPassword, ErrorResult& aRv)
1503 {
1504   RefPtr<SetterRunnable> runnable =
1505     new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPassword,
1506                        aPassword, mURLProxy);
1507 
1508   runnable->Dispatch(aRv);
1509   if (NS_WARN_IF(aRv.Failed())) {
1510     return;
1511   }
1512 
1513   MOZ_ASSERT(!runnable->Failed());
1514 }
1515 
1516 void
GetHost(nsAString & aHost,ErrorResult & aRv) const1517 URLWorker::GetHost(nsAString& aHost, ErrorResult& aRv) const
1518 {
1519   RefPtr<GetterRunnable> runnable =
1520     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHost, aHost,
1521                        mURLProxy);
1522 
1523   runnable->Dispatch(aRv);
1524 }
1525 
1526 void
SetHost(const nsAString & aHost,ErrorResult & aRv)1527 URLWorker::SetHost(const nsAString& aHost, ErrorResult& aRv)
1528 {
1529   RefPtr<SetterRunnable> runnable =
1530     new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHost,
1531                        aHost, mURLProxy);
1532 
1533   runnable->Dispatch(aRv);
1534   if (NS_WARN_IF(aRv.Failed())) {
1535     return;
1536   }
1537 
1538   MOZ_ASSERT(!runnable->Failed());
1539 }
1540 
1541 void
GetHostname(nsAString & aHostname,ErrorResult & aRv) const1542 URLWorker::GetHostname(nsAString& aHostname, ErrorResult& aRv) const
1543 {
1544   RefPtr<GetterRunnable> runnable =
1545     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHostname, aHostname,
1546                        mURLProxy);
1547 
1548   runnable->Dispatch(aRv);
1549 }
1550 
1551 void
SetHostname(const nsAString & aHostname,ErrorResult & aRv)1552 URLWorker::SetHostname(const nsAString& aHostname, ErrorResult& aRv)
1553 {
1554   RefPtr<SetterRunnable> runnable =
1555     new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHostname,
1556                        aHostname, mURLProxy);
1557 
1558   runnable->Dispatch(aRv);
1559   if (NS_WARN_IF(aRv.Failed())) {
1560     return;
1561   }
1562 
1563   MOZ_ASSERT(!runnable->Failed());
1564 }
1565 
1566 void
GetPort(nsAString & aPort,ErrorResult & aRv) const1567 URLWorker::GetPort(nsAString& aPort, ErrorResult& aRv) const
1568 {
1569   RefPtr<GetterRunnable> runnable =
1570     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPort, aPort,
1571                        mURLProxy);
1572 
1573   runnable->Dispatch(aRv);
1574 }
1575 
1576 void
SetPort(const nsAString & aPort,ErrorResult & aRv)1577 URLWorker::SetPort(const nsAString& aPort, ErrorResult& aRv)
1578 {
1579   RefPtr<SetterRunnable> runnable =
1580     new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPort,
1581                        aPort, mURLProxy);
1582 
1583   runnable->Dispatch(aRv);
1584   if (NS_WARN_IF(aRv.Failed())) {
1585     return;
1586   }
1587 
1588   MOZ_ASSERT(!runnable->Failed());
1589 }
1590 
1591 void
GetPathname(nsAString & aPathname,ErrorResult & aRv) const1592 URLWorker::GetPathname(nsAString& aPathname, ErrorResult& aRv) const
1593 {
1594   RefPtr<GetterRunnable> runnable =
1595     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPathname,
1596                        aPathname, mURLProxy);
1597 
1598   runnable->Dispatch(aRv);
1599 }
1600 
1601 void
SetPathname(const nsAString & aPathname,ErrorResult & aRv)1602 URLWorker::SetPathname(const nsAString& aPathname, ErrorResult& aRv)
1603 {
1604   RefPtr<SetterRunnable> runnable =
1605     new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPathname,
1606                        aPathname, mURLProxy);
1607 
1608   runnable->Dispatch(aRv);
1609   if (NS_WARN_IF(aRv.Failed())) {
1610     return;
1611   }
1612 
1613   MOZ_ASSERT(!runnable->Failed());
1614 }
1615 
1616 void
GetSearch(nsAString & aSearch,ErrorResult & aRv) const1617 URLWorker::GetSearch(nsAString& aSearch, ErrorResult& aRv) const
1618 {
1619   RefPtr<GetterRunnable> runnable =
1620     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterSearch, aSearch,
1621                        mURLProxy);
1622 
1623   runnable->Dispatch(aRv);
1624 }
1625 
1626 void
GetHash(nsAString & aHash,ErrorResult & aRv) const1627 URLWorker::GetHash(nsAString& aHash, ErrorResult& aRv) const
1628 {
1629   RefPtr<GetterRunnable> runnable =
1630     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHash, aHash,
1631                        mURLProxy);
1632 
1633   runnable->Dispatch(aRv);
1634 }
1635 
1636 void
SetHash(const nsAString & aHash,ErrorResult & aRv)1637 URLWorker::SetHash(const nsAString& aHash, ErrorResult& aRv)
1638 {
1639   RefPtr<SetterRunnable> runnable =
1640     new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHash,
1641                        aHash, mURLProxy);
1642 
1643   runnable->Dispatch(aRv);
1644   if (NS_WARN_IF(aRv.Failed())) {
1645     return;
1646   }
1647 
1648   MOZ_ASSERT(!runnable->Failed());
1649 }
1650 
1651 void
SetSearchInternal(const nsAString & aSearch,ErrorResult & aRv)1652 URLWorker::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv)
1653 {
1654   RefPtr<SetterRunnable> runnable =
1655     new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterSearch,
1656                        aSearch, mURLProxy);
1657 
1658   runnable->Dispatch(aRv);
1659   if (NS_WARN_IF(aRv.Failed())) {
1660     return;
1661   }
1662 
1663   MOZ_ASSERT(!runnable->Failed());
1664 }
1665 
1666 void
UpdateURLSearchParams()1667 URLWorker::UpdateURLSearchParams()
1668 {
1669   if (mSearchParams) {
1670     nsAutoString search;
1671 
1672     ErrorResult rv;
1673     GetSearch(search, rv);
1674     if (NS_WARN_IF(rv.Failed())) {
1675       rv.SuppressException();
1676     }
1677 
1678     mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(Substring(search, 1)));
1679   }
1680 }
1681 
1682 } // anonymous namespace
1683 
1684 ///////////////////////////////////////////////////////////////////////////////
1685 // Base class for URL
1686 ///////////////////////////////////////////////////////////////////////////////
1687 
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URL,mParent,mSearchParams)1688 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URL, mParent, mSearchParams)
1689 
1690 NS_IMPL_CYCLE_COLLECTING_ADDREF(URL)
1691 NS_IMPL_CYCLE_COLLECTING_RELEASE(URL)
1692 
1693 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URL)
1694   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1695   NS_INTERFACE_MAP_ENTRY(nsISupports)
1696 NS_INTERFACE_MAP_END
1697 
1698 JSObject*
1699 URL::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
1700 {
1701   return URLBinding::Wrap(aCx, this, aGivenProto);
1702 }
1703 
1704 /* static */ already_AddRefed<URL>
Constructor(const GlobalObject & aGlobal,const nsAString & aURL,URL & aBase,ErrorResult & aRv)1705 URL::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
1706                  URL& aBase, ErrorResult& aRv)
1707 {
1708   if (NS_IsMainThread()) {
1709     return URLMainThread::Constructor(aGlobal, aURL, aBase, aRv);
1710   }
1711 
1712   return URLWorker::Constructor(aGlobal, aURL, aBase, aRv);
1713 }
1714 
1715 /* static */ already_AddRefed<URL>
Constructor(const GlobalObject & aGlobal,const nsAString & aURL,const Optional<nsAString> & aBase,ErrorResult & aRv)1716 URL::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
1717                  const Optional<nsAString>& aBase, ErrorResult& aRv)
1718 {
1719   if (NS_IsMainThread()) {
1720     return URLMainThread::Constructor(aGlobal, aURL, aBase, aRv);
1721   }
1722 
1723   return URLWorker::Constructor(aGlobal, aURL, aBase, aRv);
1724 }
1725 
1726 /* static */ already_AddRefed<URL>
WorkerConstructor(const GlobalObject & aGlobal,const nsAString & aURL,const nsAString & aBase,ErrorResult & aRv)1727 URL::WorkerConstructor(const GlobalObject& aGlobal, const nsAString& aURL,
1728                        const nsAString& aBase, ErrorResult& aRv)
1729 {
1730   return URLWorker::Constructor(aGlobal, aURL, aBase, aRv);
1731 }
1732 
1733 void
CreateObjectURL(const GlobalObject & aGlobal,Blob & aBlob,const objectURLOptions & aOptions,nsAString & aResult,ErrorResult & aRv)1734 URL::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
1735                      const objectURLOptions& aOptions, nsAString& aResult,
1736                      ErrorResult& aRv)
1737 {
1738   if (NS_IsMainThread()) {
1739     URLMainThread::CreateObjectURL(aGlobal, aBlob, aOptions, aResult, aRv);
1740   } else {
1741     URLWorker::CreateObjectURL(aGlobal, aBlob, aOptions, aResult, aRv);
1742   }
1743 }
1744 
1745 void
CreateObjectURL(const GlobalObject & aGlobal,DOMMediaStream & aStream,const objectURLOptions & aOptions,nsAString & aResult,ErrorResult & aRv)1746 URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
1747                      const objectURLOptions& aOptions, nsAString& aResult,
1748                      ErrorResult& aRv)
1749 {
1750   MOZ_ASSERT(NS_IsMainThread());
1751   URLMainThread::CreateObjectURL(aGlobal, aStream, aOptions, aResult, aRv);
1752 }
1753 
1754 void
CreateObjectURL(const GlobalObject & aGlobal,MediaSource & aSource,const objectURLOptions & aOptions,nsAString & aResult,ErrorResult & aRv)1755 URL::CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource,
1756                      const objectURLOptions& aOptions,
1757                      nsAString& aResult,
1758                      ErrorResult& aRv)
1759 {
1760   MOZ_ASSERT(NS_IsMainThread());
1761   URLMainThread::CreateObjectURL(aGlobal, aSource, aOptions, aResult, aRv);
1762 }
1763 
1764 void
RevokeObjectURL(const GlobalObject & aGlobal,const nsAString & aURL,ErrorResult & aRv)1765 URL::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL,
1766                      ErrorResult& aRv)
1767 {
1768   if (NS_IsMainThread()) {
1769     URLMainThread::RevokeObjectURL(aGlobal, aURL, aRv);
1770   } else {
1771     URLWorker::RevokeObjectURL(aGlobal, aURL, aRv);
1772   }
1773 }
1774 
1775 bool
IsValidURL(const GlobalObject & aGlobal,const nsAString & aURL,ErrorResult & aRv)1776 URL::IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL,
1777                 ErrorResult& aRv)
1778 {
1779   if (NS_IsMainThread()) {
1780     return URLMainThread::IsValidURL(aGlobal, aURL, aRv);
1781   }
1782   return URLWorker::IsValidURL(aGlobal, aURL, aRv);
1783 }
1784 
1785 URLSearchParams*
SearchParams()1786 URL::SearchParams()
1787 {
1788   CreateSearchParamsIfNeeded();
1789   return mSearchParams;
1790 }
1791 
IsChromeURI(nsIURI * aURI)1792 bool IsChromeURI(nsIURI* aURI)
1793 {
1794   bool isChrome = false;
1795   if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)))
1796       return isChrome;
1797   return false;
1798 }
1799 
1800 void
CreateSearchParamsIfNeeded()1801 URL::CreateSearchParamsIfNeeded()
1802 {
1803   if (!mSearchParams) {
1804     mSearchParams = new URLSearchParams(mParent, this);
1805     UpdateURLSearchParams();
1806   }
1807 }
1808 
1809 void
SetSearch(const nsAString & aSearch,ErrorResult & aRv)1810 URL::SetSearch(const nsAString& aSearch, ErrorResult& aRv)
1811 {
1812   SetSearchInternal(aSearch, aRv);
1813   UpdateURLSearchParams();
1814 }
1815 
1816 void
URLSearchParamsUpdated(URLSearchParams * aSearchParams)1817 URL::URLSearchParamsUpdated(URLSearchParams* aSearchParams)
1818 {
1819   MOZ_ASSERT(mSearchParams);
1820   MOZ_ASSERT(mSearchParams == aSearchParams);
1821 
1822   nsAutoString search;
1823   mSearchParams->Serialize(search);
1824 
1825   ErrorResult rv;
1826   SetSearchInternal(search, rv);
1827   NS_WARNING_ASSERTION(!rv.Failed(), "SetSearchInternal failed");
1828   rv.SuppressException();
1829 }
1830 
1831 } // namespace dom
1832 } // namespace mozilla
1833