Line data Source code
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 "URLWorker.h"
8 :
9 : #include "mozilla/dom/Blob.h"
10 : #include "nsHostObjectProtocolHandler.h"
11 : #include "WorkerPrivate.h"
12 : #include "WorkerRunnable.h"
13 : #include "WorkerScope.h"
14 : #include "nsStandardURL.h"
15 : #include "nsURLHelper.h"
16 :
17 : namespace mozilla {
18 :
19 : using net::nsStandardURL;
20 :
21 : namespace dom {
22 :
23 : using namespace workers;
24 :
25 : // Proxy class to forward all the requests to a URLMainThread object.
26 : class URLWorker::URLProxy final
27 : {
28 : public:
29 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLProxy)
30 :
31 0 : explicit URLProxy(already_AddRefed<URLMainThread> aURL)
32 0 : : mURL(aURL)
33 : {
34 0 : MOZ_ASSERT(NS_IsMainThread());
35 0 : }
36 :
37 0 : URLMainThread* URL()
38 : {
39 0 : MOZ_ASSERT(NS_IsMainThread());
40 0 : return mURL;
41 : }
42 :
43 : nsIURI* URI()
44 : {
45 : MOZ_ASSERT(NS_IsMainThread());
46 : return mURL->GetURI();
47 : }
48 :
49 0 : void ReleaseURI()
50 : {
51 0 : MOZ_ASSERT(NS_IsMainThread());
52 0 : mURL = nullptr;
53 0 : }
54 :
55 : private:
56 : // Private destructor, to discourage deletion outside of Release():
57 0 : ~URLProxy()
58 0 : {
59 0 : MOZ_ASSERT(!mURL);
60 0 : }
61 :
62 : RefPtr<URLMainThread> mURL;
63 : };
64 :
65 : // This class creates an URL from a DOM Blob on the main thread.
66 0 : class CreateURLRunnable : public WorkerMainThreadRunnable
67 : {
68 : private:
69 : BlobImpl* mBlobImpl;
70 : nsAString& mURL;
71 :
72 : public:
73 0 : CreateURLRunnable(WorkerPrivate* aWorkerPrivate, BlobImpl* aBlobImpl,
74 : nsAString& aURL)
75 0 : : WorkerMainThreadRunnable(aWorkerPrivate,
76 0 : NS_LITERAL_CSTRING("URL :: CreateURL"))
77 : , mBlobImpl(aBlobImpl)
78 0 : , mURL(aURL)
79 : {
80 0 : MOZ_ASSERT(aBlobImpl);
81 :
82 0 : DebugOnly<bool> isMutable;
83 0 : MOZ_ASSERT(NS_SUCCEEDED(aBlobImpl->GetMutable(&isMutable)));
84 0 : MOZ_ASSERT(!isMutable);
85 0 : }
86 :
87 : bool
88 0 : MainThreadRun()
89 : {
90 : using namespace mozilla::ipc;
91 :
92 0 : AssertIsOnMainThread();
93 :
94 0 : DebugOnly<bool> isMutable;
95 0 : MOZ_ASSERT(NS_SUCCEEDED(mBlobImpl->GetMutable(&isMutable)));
96 0 : MOZ_ASSERT(!isMutable);
97 :
98 0 : nsCOMPtr<nsIPrincipal> principal = mWorkerPrivate->GetPrincipal();
99 :
100 0 : nsAutoCString url;
101 : nsresult rv =
102 0 : nsHostObjectProtocolHandler::AddDataEntry(mBlobImpl, principal, url);
103 :
104 0 : if (NS_FAILED(rv)) {
105 0 : NS_WARNING("Failed to add data entry for the blob!");
106 0 : SetDOMStringToNull(mURL);
107 0 : return false;
108 : }
109 :
110 0 : if (!mWorkerPrivate->IsSharedWorker() &&
111 0 : !mWorkerPrivate->IsServiceWorker()) {
112 : // Walk up to top worker object.
113 0 : WorkerPrivate* wp = mWorkerPrivate;
114 0 : while (WorkerPrivate* parent = wp->GetParent()) {
115 0 : wp = parent;
116 0 : }
117 :
118 0 : nsCOMPtr<nsIScriptContext> sc = wp->GetScriptContext();
119 : // We could not have a ScriptContext in JSM code. In this case, we leak.
120 0 : if (sc) {
121 0 : nsCOMPtr<nsIGlobalObject> global = sc->GetGlobalObject();
122 0 : MOZ_ASSERT(global);
123 :
124 0 : global->RegisterHostObjectURI(url);
125 : }
126 : }
127 :
128 0 : mURL = NS_ConvertUTF8toUTF16(url);
129 0 : return true;
130 : }
131 : };
132 :
133 : // This class revokes an URL on the main thread.
134 0 : class RevokeURLRunnable : public WorkerMainThreadRunnable
135 : {
136 : private:
137 : const nsString mURL;
138 :
139 : public:
140 0 : RevokeURLRunnable(WorkerPrivate* aWorkerPrivate,
141 : const nsAString& aURL)
142 0 : : WorkerMainThreadRunnable(aWorkerPrivate,
143 0 : NS_LITERAL_CSTRING("URL :: RevokeURL"))
144 0 : , mURL(aURL)
145 0 : {}
146 :
147 : bool
148 0 : MainThreadRun()
149 : {
150 0 : AssertIsOnMainThread();
151 :
152 0 : NS_ConvertUTF16toUTF8 url(mURL);
153 :
154 : nsIPrincipal* urlPrincipal =
155 0 : nsHostObjectProtocolHandler::GetDataEntryPrincipal(url);
156 :
157 0 : nsCOMPtr<nsIPrincipal> principal = mWorkerPrivate->GetPrincipal();
158 :
159 : bool subsumes;
160 0 : if (urlPrincipal &&
161 0 : NS_SUCCEEDED(principal->Subsumes(urlPrincipal, &subsumes)) &&
162 : subsumes) {
163 0 : nsHostObjectProtocolHandler::RemoveDataEntry(url);
164 : }
165 :
166 0 : if (!mWorkerPrivate->IsSharedWorker() &&
167 0 : !mWorkerPrivate->IsServiceWorker()) {
168 : // Walk up to top worker object.
169 0 : WorkerPrivate* wp = mWorkerPrivate;
170 0 : while (WorkerPrivate* parent = wp->GetParent()) {
171 0 : wp = parent;
172 0 : }
173 :
174 0 : nsCOMPtr<nsIScriptContext> sc = wp->GetScriptContext();
175 : // We could not have a ScriptContext in JSM code. In this case, we leak.
176 0 : if (sc) {
177 0 : nsCOMPtr<nsIGlobalObject> global = sc->GetGlobalObject();
178 0 : MOZ_ASSERT(global);
179 :
180 0 : global->UnregisterHostObjectURI(url);
181 : }
182 : }
183 :
184 0 : return true;
185 : }
186 : };
187 :
188 : // This class checks if an URL is valid on the main thread.
189 0 : class IsValidURLRunnable : public WorkerMainThreadRunnable
190 : {
191 : private:
192 : const nsString mURL;
193 : bool mValid;
194 :
195 : public:
196 0 : IsValidURLRunnable(WorkerPrivate* aWorkerPrivate,
197 : const nsAString& aURL)
198 0 : : WorkerMainThreadRunnable(aWorkerPrivate,
199 0 : NS_LITERAL_CSTRING("URL :: IsValidURL"))
200 : , mURL(aURL)
201 0 : , mValid(false)
202 0 : {}
203 :
204 : bool
205 0 : MainThreadRun()
206 : {
207 0 : AssertIsOnMainThread();
208 :
209 0 : NS_ConvertUTF16toUTF8 url(mURL);
210 0 : mValid = nsHostObjectProtocolHandler::HasDataEntry(url);
211 :
212 0 : return true;
213 : }
214 :
215 : bool
216 0 : IsValidURL() const
217 : {
218 0 : return mValid;
219 : }
220 : };
221 :
222 : // This class creates a URL object on the main thread.
223 0 : class ConstructorRunnable : public WorkerMainThreadRunnable
224 : {
225 : private:
226 : const nsString mURL;
227 :
228 : nsString mBase; // IsVoid() if we have no base URI string.
229 :
230 : RefPtr<URLWorker::URLProxy> mRetval;
231 :
232 : public:
233 0 : ConstructorRunnable(WorkerPrivate* aWorkerPrivate,
234 : const nsAString& aURL, const Optional<nsAString>& aBase)
235 0 : : WorkerMainThreadRunnable(aWorkerPrivate,
236 0 : NS_LITERAL_CSTRING("URL :: Constructor"))
237 0 : , mURL(aURL)
238 : {
239 0 : if (aBase.WasPassed()) {
240 0 : mBase = aBase.Value();
241 : } else {
242 0 : mBase.SetIsVoid(true);
243 : }
244 0 : mWorkerPrivate->AssertIsOnWorkerThread();
245 0 : }
246 :
247 : bool
248 0 : MainThreadRun()
249 : {
250 0 : AssertIsOnMainThread();
251 :
252 0 : ErrorResult rv;
253 0 : RefPtr<URLMainThread> url;
254 0 : if (!mBase.IsVoid()) {
255 0 : url = URLMainThread::Constructor(nullptr, mURL, mBase, rv);
256 : } else {
257 0 : url = URLMainThread::Constructor(nullptr, mURL, nullptr, rv);
258 : }
259 :
260 0 : if (rv.Failed()) {
261 0 : rv.SuppressException();
262 0 : return true;
263 : }
264 :
265 0 : mRetval = new URLWorker::URLProxy(url.forget());
266 0 : return true;
267 : }
268 :
269 : URLWorker::URLProxy*
270 0 : GetURLProxy(ErrorResult& aRv) const
271 : {
272 0 : MOZ_ASSERT(mWorkerPrivate);
273 0 : mWorkerPrivate->AssertIsOnWorkerThread();
274 :
275 0 : if (!mRetval) {
276 0 : aRv.ThrowTypeError<MSG_INVALID_URL>(mURL);
277 : }
278 :
279 0 : return mRetval;
280 : }
281 : };
282 :
283 0 : class TeardownURLRunnable : public Runnable
284 : {
285 : public:
286 0 : explicit TeardownURLRunnable(URLWorker::URLProxy* aURLProxy)
287 0 : : Runnable("dom::TeardownURLRunnable")
288 0 : , mURLProxy(aURLProxy)
289 : {
290 0 : }
291 :
292 0 : NS_IMETHOD Run()
293 : {
294 0 : AssertIsOnMainThread();
295 :
296 0 : mURLProxy->ReleaseURI();
297 0 : mURLProxy = nullptr;
298 :
299 0 : return NS_OK;
300 : }
301 :
302 : private:
303 : RefPtr<URLWorker::URLProxy> mURLProxy;
304 : };
305 :
306 : // This class is the generic getter for any URL property.
307 0 : class GetterRunnable : public WorkerMainThreadRunnable
308 : {
309 : public:
310 : enum GetterType {
311 : GetterHref,
312 : GetterOrigin,
313 : GetterProtocol,
314 : GetterUsername,
315 : GetterPassword,
316 : GetterHost,
317 : GetterHostname,
318 : GetterPort,
319 : GetterPathname,
320 : GetterSearch,
321 : GetterHash,
322 : };
323 :
324 0 : GetterRunnable(WorkerPrivate* aWorkerPrivate,
325 : GetterType aType, nsAString& aValue,
326 : URLWorker::URLProxy* aURLProxy)
327 0 : : WorkerMainThreadRunnable(aWorkerPrivate,
328 : // We can have telemetry keys for each getter when
329 : // needed.
330 0 : NS_LITERAL_CSTRING("URL :: getter"))
331 : , mValue(aValue)
332 : , mType(aType)
333 0 : , mURLProxy(aURLProxy)
334 : {
335 0 : mWorkerPrivate->AssertIsOnWorkerThread();
336 0 : }
337 :
338 : bool
339 0 : MainThreadRun()
340 : {
341 0 : AssertIsOnMainThread();
342 0 : ErrorResult rv;
343 :
344 0 : switch (mType) {
345 : case GetterHref:
346 0 : mURLProxy->URL()->GetHref(mValue, rv);
347 0 : break;
348 :
349 : case GetterOrigin:
350 0 : mURLProxy->URL()->GetOrigin(mValue, rv);
351 0 : break;
352 :
353 : case GetterProtocol:
354 0 : mURLProxy->URL()->GetProtocol(mValue, rv);
355 0 : break;
356 :
357 : case GetterUsername:
358 0 : mURLProxy->URL()->GetUsername(mValue, rv);
359 0 : break;
360 :
361 : case GetterPassword:
362 0 : mURLProxy->URL()->GetPassword(mValue, rv);
363 0 : break;
364 :
365 : case GetterHost:
366 0 : mURLProxy->URL()->GetHost(mValue, rv);
367 0 : break;
368 :
369 : case GetterHostname:
370 0 : mURLProxy->URL()->GetHostname(mValue, rv);
371 0 : break;
372 :
373 : case GetterPort:
374 0 : mURLProxy->URL()->GetPort(mValue, rv);
375 0 : break;
376 :
377 : case GetterPathname:
378 0 : mURLProxy->URL()->GetPathname(mValue, rv);
379 0 : break;
380 :
381 : case GetterSearch:
382 0 : mURLProxy->URL()->GetSearch(mValue, rv);
383 0 : break;
384 :
385 : case GetterHash:
386 0 : mURLProxy->URL()->GetHash(mValue, rv);
387 0 : break;
388 : }
389 :
390 0 : MOZ_ASSERT(!rv.Failed(), "Main-thread getters do not fail.");
391 0 : return true;
392 : }
393 :
394 : void
395 0 : Dispatch(ErrorResult& aRv)
396 : {
397 0 : WorkerMainThreadRunnable::Dispatch(Terminating, aRv);
398 0 : }
399 :
400 : private:
401 : nsAString& mValue;
402 : GetterType mType;
403 : RefPtr<URLWorker::URLProxy> mURLProxy;
404 : };
405 :
406 : // This class is the generic setter for any URL property.
407 0 : class SetterRunnable : public WorkerMainThreadRunnable
408 : {
409 : public:
410 : enum SetterType {
411 : SetterHref,
412 : SetterProtocol,
413 : SetterUsername,
414 : SetterPassword,
415 : SetterHost,
416 : SetterHostname,
417 : SetterPort,
418 : SetterPathname,
419 : SetterSearch,
420 : SetterHash,
421 : };
422 :
423 0 : SetterRunnable(WorkerPrivate* aWorkerPrivate,
424 : SetterType aType, const nsAString& aValue,
425 : URLWorker::URLProxy* aURLProxy)
426 0 : : WorkerMainThreadRunnable(aWorkerPrivate,
427 : // We can have telemetry keys for each setter when
428 : // needed.
429 0 : NS_LITERAL_CSTRING("URL :: setter"))
430 : , mValue(aValue)
431 : , mType(aType)
432 : , mURLProxy(aURLProxy)
433 0 : , mFailed(false)
434 : {
435 0 : mWorkerPrivate->AssertIsOnWorkerThread();
436 0 : }
437 :
438 : bool
439 0 : MainThreadRun()
440 : {
441 0 : AssertIsOnMainThread();
442 0 : ErrorResult rv;
443 :
444 0 : switch (mType) {
445 : case SetterHref: {
446 0 : mURLProxy->URL()->SetHref(mValue, rv);
447 0 : break;
448 : }
449 :
450 : case SetterProtocol:
451 0 : mURLProxy->URL()->SetProtocol(mValue, rv);
452 0 : break;
453 :
454 : case SetterUsername:
455 0 : mURLProxy->URL()->SetUsername(mValue, rv);
456 0 : break;
457 :
458 : case SetterPassword:
459 0 : mURLProxy->URL()->SetPassword(mValue, rv);
460 0 : break;
461 :
462 : case SetterHost:
463 0 : mURLProxy->URL()->SetHost(mValue, rv);
464 0 : break;
465 :
466 : case SetterHostname:
467 0 : mURLProxy->URL()->SetHostname(mValue, rv);
468 0 : break;
469 :
470 : case SetterPort:
471 0 : mURLProxy->URL()->SetPort(mValue, rv);
472 0 : break;
473 :
474 : case SetterPathname:
475 0 : mURLProxy->URL()->SetPathname(mValue, rv);
476 0 : break;
477 :
478 : case SetterSearch:
479 0 : mURLProxy->URL()->SetSearch(mValue, rv);
480 0 : break;
481 :
482 : case SetterHash:
483 0 : mURLProxy->URL()->SetHash(mValue, rv);
484 0 : break;
485 : }
486 :
487 0 : if (NS_WARN_IF(rv.Failed())) {
488 0 : rv.SuppressException();
489 0 : mFailed = true;
490 : }
491 :
492 0 : return true;
493 : }
494 :
495 0 : bool Failed() const
496 : {
497 0 : return mFailed;
498 : }
499 :
500 : void
501 0 : Dispatch(ErrorResult& aRv)
502 : {
503 0 : WorkerMainThreadRunnable::Dispatch(Terminating, aRv);
504 0 : }
505 :
506 : private:
507 : const nsString mValue;
508 : SetterType mType;
509 : RefPtr<URLWorker::URLProxy> mURLProxy;
510 : bool mFailed;
511 : };
512 :
513 : /* static */ already_AddRefed<URLWorker>
514 0 : URLWorker::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
515 : const Optional<nsAString>& aBase, ErrorResult& aRv)
516 : {
517 0 : JSContext* cx = aGlobal.Context();
518 0 : WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
519 :
520 0 : RefPtr<URLWorker> url = new URLWorker(workerPrivate);
521 0 : url->Init(aURL, aBase, aRv);
522 :
523 0 : return aRv.Failed() ? nullptr : url.forget();
524 : }
525 :
526 : /* static */ already_AddRefed<URLWorker>
527 0 : URLWorker::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
528 : const nsAString& aBase, ErrorResult& aRv)
529 : {
530 0 : Optional<nsAString> base;
531 0 : base = &aBase;
532 :
533 0 : return Constructor(aGlobal, aURL, base, aRv);
534 : }
535 :
536 : /* static */ void
537 0 : URLWorker::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
538 : nsAString& aResult, mozilla::ErrorResult& aRv)
539 : {
540 0 : JSContext* cx = aGlobal.Context();
541 0 : WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
542 :
543 0 : RefPtr<BlobImpl> blobImpl = aBlob.Impl();
544 0 : MOZ_ASSERT(blobImpl);
545 :
546 0 : aRv = blobImpl->SetMutable(false);
547 0 : if (NS_WARN_IF(aRv.Failed())) {
548 0 : return;
549 : }
550 :
551 : RefPtr<CreateURLRunnable> runnable =
552 0 : new CreateURLRunnable(workerPrivate, blobImpl, aResult);
553 :
554 0 : runnable->Dispatch(Terminating, aRv);
555 0 : if (NS_WARN_IF(aRv.Failed())) {
556 0 : return;
557 : }
558 :
559 0 : if (workerPrivate->IsSharedWorker() || workerPrivate->IsServiceWorker()) {
560 0 : WorkerGlobalScope* scope = workerPrivate->GlobalScope();
561 0 : MOZ_ASSERT(scope);
562 :
563 0 : scope->RegisterHostObjectURI(NS_ConvertUTF16toUTF8(aResult));
564 : }
565 : }
566 :
567 : /* static */ void
568 0 : URLWorker::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl,
569 : ErrorResult& aRv)
570 : {
571 0 : JSContext* cx = aGlobal.Context();
572 0 : WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
573 :
574 : RefPtr<RevokeURLRunnable> runnable =
575 0 : new RevokeURLRunnable(workerPrivate, aUrl);
576 :
577 0 : runnable->Dispatch(Terminating, aRv);
578 0 : if (NS_WARN_IF(aRv.Failed())) {
579 0 : return;
580 : }
581 :
582 0 : if (workerPrivate->IsSharedWorker() || workerPrivate->IsServiceWorker()) {
583 0 : WorkerGlobalScope* scope = workerPrivate->GlobalScope();
584 0 : MOZ_ASSERT(scope);
585 :
586 0 : scope->UnregisterHostObjectURI(NS_ConvertUTF16toUTF8(aUrl));
587 : }
588 : }
589 :
590 : /* static */ bool
591 0 : URLWorker::IsValidURL(const GlobalObject& aGlobal, const nsAString& aUrl,
592 : ErrorResult& aRv)
593 : {
594 0 : JSContext* cx = aGlobal.Context();
595 0 : WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
596 :
597 : RefPtr<IsValidURLRunnable> runnable =
598 0 : new IsValidURLRunnable(workerPrivate, aUrl);
599 :
600 0 : runnable->Dispatch(Terminating, aRv);
601 0 : if (NS_WARN_IF(aRv.Failed())) {
602 0 : return false;
603 : }
604 :
605 0 : return runnable->IsValidURL();
606 : }
607 :
608 0 : URLWorker::URLWorker(WorkerPrivate* aWorkerPrivate)
609 : : URL(nullptr)
610 0 : , mWorkerPrivate(aWorkerPrivate)
611 0 : {}
612 :
613 : void
614 0 : URLWorker::Init(const nsAString& aURL, const Optional<nsAString>& aBase,
615 : ErrorResult& aRv)
616 : {
617 0 : nsAutoCString scheme;
618 0 : nsresult rv = net_ExtractURLScheme(NS_ConvertUTF16toUTF8(aURL), scheme);
619 0 : if (NS_FAILED(rv)) {
620 : // this may be a relative URL, check baseURL
621 0 : if (!aBase.WasPassed()) {
622 0 : aRv.ThrowTypeError<MSG_INVALID_URL>(aURL);
623 0 : return;
624 : }
625 0 : rv = net_ExtractURLScheme(NS_ConvertUTF16toUTF8(aBase.Value()), scheme);
626 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
627 0 : aRv.ThrowTypeError<MSG_INVALID_URL>(aURL);
628 0 : return;
629 : }
630 : }
631 :
632 0 : if (scheme.Equals(NS_LITERAL_CSTRING("http")) ||
633 0 : scheme.Equals(NS_LITERAL_CSTRING("https"))) {
634 0 : RefPtr<nsStandardURL> baseURL;
635 0 : if (aBase.WasPassed()) {
636 0 : baseURL = new nsStandardURL();
637 :
638 : // XXXcatalinb: SetSpec only writes a warning to the console on urls
639 : // without a valid scheme. I can't fix that because we've come to rely
640 : // on that behaviour in a bunch of different places.
641 0 : nsresult rv = baseURL->SetSpec(NS_ConvertUTF16toUTF8(aBase.Value()));
642 0 : nsAutoCString baseScheme;
643 0 : baseURL->GetScheme(baseScheme);
644 0 : if (NS_WARN_IF(NS_FAILED(rv)) || baseScheme.IsEmpty()) {
645 0 : aRv.ThrowTypeError<MSG_INVALID_URL>(aBase.Value());
646 0 : return;
647 : }
648 : }
649 0 : mStdURL = new nsStandardURL();
650 0 : aRv = mStdURL->Init(nsIStandardURL::URLTYPE_STANDARD, -1,
651 0 : NS_ConvertUTF16toUTF8(aURL), nullptr, baseURL);
652 0 : return;
653 : }
654 :
655 : // create url proxy
656 : RefPtr<ConstructorRunnable> runnable =
657 0 : new ConstructorRunnable(mWorkerPrivate, aURL, aBase);
658 0 : runnable->Dispatch(Terminating, aRv);
659 0 : if (NS_WARN_IF(aRv.Failed())) {
660 0 : return;
661 : }
662 0 : mURLProxy = runnable->GetURLProxy(aRv);
663 : }
664 :
665 0 : URLWorker::~URLWorker()
666 : {
667 0 : if (mURLProxy) {
668 0 : mWorkerPrivate->AssertIsOnWorkerThread();
669 :
670 : RefPtr<TeardownURLRunnable> runnable =
671 0 : new TeardownURLRunnable(mURLProxy);
672 0 : mURLProxy = nullptr;
673 :
674 0 : if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
675 0 : NS_ERROR("Failed to dispatch teardown runnable!");
676 : }
677 : }
678 0 : }
679 :
680 : void
681 0 : URLWorker::GetHref(nsAString& aHref, ErrorResult& aRv) const
682 : {
683 0 : aHref.Truncate();
684 0 : if (mStdURL) {
685 0 : nsAutoCString href;
686 0 : aRv = mStdURL->GetSpec(href);
687 0 : if (!aRv.Failed()) {
688 0 : CopyUTF8toUTF16(href, aHref);
689 : }
690 0 : return;
691 : }
692 :
693 0 : MOZ_ASSERT(mURLProxy);
694 : RefPtr<GetterRunnable> runnable =
695 0 : new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHref, aHref,
696 0 : mURLProxy);
697 0 : runnable->Dispatch(aRv);
698 : }
699 :
700 : void
701 0 : URLWorker::SetHref(const nsAString& aHref, ErrorResult& aRv)
702 : {
703 0 : nsAutoCString scheme;
704 0 : nsresult rv = net_ExtractURLScheme(NS_ConvertUTF16toUTF8(aHref), scheme);
705 0 : if (NS_FAILED(rv)) {
706 0 : aRv.ThrowTypeError<MSG_INVALID_URL>(aHref);
707 0 : return;
708 : }
709 :
710 0 : if (scheme.Equals(NS_LITERAL_CSTRING("http")) ||
711 0 : scheme.Equals(NS_LITERAL_CSTRING("https"))) {
712 0 : mStdURL = new nsStandardURL();
713 0 : aRv = mStdURL->SetSpec(NS_ConvertUTF16toUTF8(aHref));
714 0 : if (mURLProxy) {
715 0 : mWorkerPrivate->AssertIsOnWorkerThread();
716 :
717 : RefPtr<TeardownURLRunnable> runnable =
718 0 : new TeardownURLRunnable(mURLProxy);
719 0 : mURLProxy = nullptr;
720 :
721 0 : if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)))) {
722 0 : return;
723 : }
724 : }
725 :
726 0 : UpdateURLSearchParams();
727 0 : return;
728 : }
729 :
730 0 : mStdURL = nullptr;
731 : // fallback to using a main thread url proxy
732 0 : if (mURLProxy) {
733 : RefPtr<SetterRunnable> runnable =
734 : new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHref, aHref,
735 0 : mURLProxy);
736 :
737 0 : runnable->Dispatch(aRv);
738 0 : if (NS_WARN_IF(aRv.Failed())) {
739 0 : return;
740 : }
741 :
742 0 : UpdateURLSearchParams();
743 0 : return;
744 : }
745 :
746 : // create the proxy now
747 : RefPtr<ConstructorRunnable> runnable =
748 0 : new ConstructorRunnable(mWorkerPrivate, aHref, Optional<nsAString>());
749 0 : runnable->Dispatch(Terminating, aRv);
750 0 : if (NS_WARN_IF(aRv.Failed())) {
751 0 : return;
752 : }
753 0 : mURLProxy = runnable->GetURLProxy(aRv);
754 :
755 0 : UpdateURLSearchParams();
756 : }
757 :
758 : void
759 0 : URLWorker::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const
760 : {
761 0 : if (mStdURL) {
762 0 : nsContentUtils::GetUTFOrigin(mStdURL, aOrigin);
763 0 : return;
764 : }
765 :
766 0 : MOZ_ASSERT(mURLProxy);
767 : RefPtr<GetterRunnable> runnable =
768 0 : new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterOrigin, aOrigin,
769 0 : mURLProxy);
770 :
771 0 : runnable->Dispatch(aRv);
772 : }
773 :
774 : void
775 0 : URLWorker::GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const
776 : {
777 0 : aProtocol.Truncate();
778 0 : nsAutoCString protocol;
779 0 : if (mStdURL) {
780 0 : if (NS_SUCCEEDED(mStdURL->GetScheme(protocol))) {
781 0 : CopyASCIItoUTF16(protocol, aProtocol);
782 0 : aProtocol.Append(char16_t(':'));
783 : }
784 :
785 0 : return;
786 : }
787 :
788 0 : MOZ_ASSERT(mURLProxy);
789 : RefPtr<GetterRunnable> runnable =
790 0 : new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterProtocol, aProtocol,
791 0 : mURLProxy);
792 :
793 0 : runnable->Dispatch(aRv);
794 : }
795 :
796 : void
797 0 : URLWorker::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv)
798 : {
799 0 : if (mStdURL) {
800 0 : nsAString::const_iterator start, end;
801 0 : aProtocol.BeginReading(start);
802 0 : aProtocol.EndReading(end);
803 0 : nsAString::const_iterator iter(start);
804 :
805 0 : FindCharInReadable(':', iter, end);
806 :
807 0 : nsresult rv = mStdURL->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)));
808 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
809 0 : return;
810 : }
811 :
812 0 : nsAutoCString href;
813 0 : rv = mStdURL->GetSpec(href);
814 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
815 0 : return;
816 : }
817 :
818 0 : SetHref(NS_ConvertUTF8toUTF16(href), aRv);
819 0 : return;
820 : }
821 :
822 0 : MOZ_ASSERT(mURLProxy);
823 : RefPtr<SetterRunnable> runnable =
824 : new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterProtocol,
825 0 : aProtocol, mURLProxy);
826 :
827 0 : runnable->Dispatch(aRv);
828 :
829 0 : MOZ_ASSERT(!runnable->Failed());
830 : }
831 :
832 : #define STDURL_GETTER(value, method) \
833 : if (mStdURL) { \
834 : value.Truncate(); \
835 : nsAutoCString tmp; \
836 : nsresult rv = mStdURL->method(tmp); \
837 : if (NS_SUCCEEDED(rv)) { \
838 : CopyUTF8toUTF16(tmp, value); \
839 : } \
840 : return; \
841 : }
842 :
843 : #define STDURL_SETTER(value, method) \
844 : if (mStdURL) { \
845 : aRv = mStdURL->method(NS_ConvertUTF16toUTF8(value)); \
846 : return; \
847 : }
848 :
849 : void
850 0 : URLWorker::GetUsername(nsAString& aUsername, ErrorResult& aRv) const
851 : {
852 0 : STDURL_GETTER(aUsername, GetUsername);
853 :
854 0 : MOZ_ASSERT(mURLProxy);
855 : RefPtr<GetterRunnable> runnable =
856 0 : new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterUsername, aUsername,
857 0 : mURLProxy);
858 :
859 0 : runnable->Dispatch(aRv);
860 : }
861 :
862 : void
863 0 : URLWorker::SetUsername(const nsAString& aUsername, ErrorResult& aRv)
864 : {
865 0 : STDURL_SETTER(aUsername, SetUsername);
866 :
867 0 : MOZ_ASSERT(mURLProxy);
868 : RefPtr<SetterRunnable> runnable =
869 : new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterUsername,
870 0 : aUsername, mURLProxy);
871 :
872 0 : runnable->Dispatch(aRv);
873 0 : if (NS_WARN_IF(aRv.Failed())) {
874 0 : return;
875 : }
876 :
877 0 : MOZ_ASSERT(!runnable->Failed());
878 : }
879 :
880 : void
881 0 : URLWorker::GetPassword(nsAString& aPassword, ErrorResult& aRv) const
882 : {
883 0 : STDURL_GETTER(aPassword, GetPassword);
884 :
885 0 : MOZ_ASSERT(mURLProxy);
886 : RefPtr<GetterRunnable> runnable =
887 0 : new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPassword, aPassword,
888 0 : mURLProxy);
889 :
890 0 : runnable->Dispatch(aRv);
891 : }
892 :
893 : void
894 0 : URLWorker::SetPassword(const nsAString& aPassword, ErrorResult& aRv)
895 : {
896 0 : STDURL_SETTER(aPassword, SetPassword);
897 :
898 0 : MOZ_ASSERT(mURLProxy);
899 : RefPtr<SetterRunnable> runnable =
900 : new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPassword,
901 0 : aPassword, mURLProxy);
902 :
903 0 : runnable->Dispatch(aRv);
904 0 : if (NS_WARN_IF(aRv.Failed())) {
905 0 : return;
906 : }
907 :
908 0 : MOZ_ASSERT(!runnable->Failed());
909 : }
910 :
911 : void
912 0 : URLWorker::GetHost(nsAString& aHost, ErrorResult& aRv) const
913 : {
914 0 : STDURL_GETTER(aHost, GetHostPort);
915 :
916 0 : MOZ_ASSERT(mURLProxy);
917 : RefPtr<GetterRunnable> runnable =
918 0 : new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHost, aHost,
919 0 : mURLProxy);
920 :
921 0 : runnable->Dispatch(aRv);
922 : }
923 :
924 : void
925 0 : URLWorker::SetHost(const nsAString& aHost, ErrorResult& aRv)
926 : {
927 0 : STDURL_SETTER(aHost, SetHostPort);
928 :
929 0 : MOZ_ASSERT(mURLProxy);
930 : RefPtr<SetterRunnable> runnable =
931 : new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHost,
932 0 : aHost, mURLProxy);
933 :
934 0 : runnable->Dispatch(aRv);
935 0 : if (NS_WARN_IF(aRv.Failed())) {
936 0 : return;
937 : }
938 :
939 0 : MOZ_ASSERT(!runnable->Failed());
940 : }
941 :
942 : void
943 0 : URLWorker::GetHostname(nsAString& aHostname, ErrorResult& aRv) const
944 : {
945 0 : aHostname.Truncate();
946 0 : if (mStdURL) {
947 0 : aRv = nsContentUtils::GetHostOrIPv6WithBrackets(mStdURL, aHostname);
948 0 : return;
949 : }
950 :
951 0 : MOZ_ASSERT(mURLProxy);
952 : RefPtr<GetterRunnable> runnable =
953 0 : new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHostname, aHostname,
954 0 : mURLProxy);
955 :
956 0 : runnable->Dispatch(aRv);
957 : }
958 :
959 : void
960 0 : URLWorker::SetHostname(const nsAString& aHostname, ErrorResult& aRv)
961 : {
962 0 : STDURL_SETTER(aHostname, SetHost);
963 :
964 0 : MOZ_ASSERT(mURLProxy);
965 : RefPtr<SetterRunnable> runnable =
966 : new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHostname,
967 0 : aHostname, mURLProxy);
968 :
969 0 : runnable->Dispatch(aRv);
970 0 : if (NS_WARN_IF(aRv.Failed())) {
971 0 : return;
972 : }
973 :
974 0 : MOZ_ASSERT(!runnable->Failed());
975 : }
976 :
977 : void
978 0 : URLWorker::GetPort(nsAString& aPort, ErrorResult& aRv) const
979 : {
980 0 : aPort.Truncate();
981 :
982 0 : if (mStdURL) {
983 : int32_t port;
984 0 : nsresult rv = mStdURL->GetPort(&port);
985 0 : if (NS_SUCCEEDED(rv) && port != -1) {
986 0 : nsAutoString portStr;
987 0 : portStr.AppendInt(port, 10);
988 0 : aPort.Assign(portStr);
989 : }
990 0 : return;
991 : }
992 :
993 0 : MOZ_ASSERT(mURLProxy);
994 : RefPtr<GetterRunnable> runnable =
995 0 : new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPort, aPort,
996 0 : mURLProxy);
997 :
998 0 : runnable->Dispatch(aRv);
999 : }
1000 :
1001 : void
1002 0 : URLWorker::SetPort(const nsAString& aPort, ErrorResult& aRv)
1003 : {
1004 0 : if (mStdURL) {
1005 : nsresult rv;
1006 0 : nsAutoString portStr(aPort);
1007 0 : int32_t port = -1;
1008 :
1009 : // nsIURI uses -1 as default value.
1010 0 : if (!portStr.IsEmpty()) {
1011 0 : port = portStr.ToInteger(&rv);
1012 0 : if (NS_FAILED(rv)) {
1013 0 : return;
1014 : }
1015 : }
1016 :
1017 0 : mStdURL->SetPort(port);
1018 0 : return;
1019 : }
1020 :
1021 0 : MOZ_ASSERT(mURLProxy);
1022 : RefPtr<SetterRunnable> runnable =
1023 : new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPort,
1024 0 : aPort, mURLProxy);
1025 :
1026 0 : runnable->Dispatch(aRv);
1027 0 : if (NS_WARN_IF(aRv.Failed())) {
1028 0 : return;
1029 : }
1030 :
1031 0 : MOZ_ASSERT(!runnable->Failed());
1032 : }
1033 :
1034 : void
1035 0 : URLWorker::GetPathname(nsAString& aPathname, ErrorResult& aRv) const
1036 : {
1037 0 : aPathname.Truncate();
1038 :
1039 0 : if (mStdURL) {
1040 0 : nsAutoCString file;
1041 0 : nsresult rv = mStdURL->GetFilePath(file);
1042 0 : if (NS_SUCCEEDED(rv)) {
1043 0 : CopyUTF8toUTF16(file, aPathname);
1044 : }
1045 0 : return;
1046 : }
1047 :
1048 0 : MOZ_ASSERT(mURLProxy);
1049 : RefPtr<GetterRunnable> runnable =
1050 0 : new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPathname,
1051 0 : aPathname, mURLProxy);
1052 :
1053 0 : runnable->Dispatch(aRv);
1054 : }
1055 :
1056 : void
1057 0 : URLWorker::SetPathname(const nsAString& aPathname, ErrorResult& aRv)
1058 : {
1059 0 : STDURL_SETTER(aPathname, SetFilePath);
1060 :
1061 0 : MOZ_ASSERT(mURLProxy);
1062 : RefPtr<SetterRunnable> runnable =
1063 : new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPathname,
1064 0 : aPathname, mURLProxy);
1065 :
1066 0 : runnable->Dispatch(aRv);
1067 0 : if (NS_WARN_IF(aRv.Failed())) {
1068 0 : return;
1069 : }
1070 :
1071 0 : MOZ_ASSERT(!runnable->Failed());
1072 : }
1073 :
1074 : void
1075 0 : URLWorker::GetSearch(nsAString& aSearch, ErrorResult& aRv) const
1076 : {
1077 0 : aSearch.Truncate();
1078 :
1079 0 : if (mStdURL) {
1080 0 : nsAutoCString search;
1081 : nsresult rv;
1082 :
1083 0 : rv = mStdURL->GetQuery(search);
1084 0 : if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
1085 0 : CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
1086 : }
1087 0 : return;
1088 : }
1089 :
1090 0 : MOZ_ASSERT(mURLProxy);
1091 : RefPtr<GetterRunnable> runnable =
1092 0 : new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterSearch, aSearch,
1093 0 : mURLProxy);
1094 :
1095 0 : runnable->Dispatch(aRv);
1096 : }
1097 :
1098 : void
1099 0 : URLWorker::GetHash(nsAString& aHash, ErrorResult& aRv) const
1100 : {
1101 0 : aHash.Truncate();
1102 0 : if (mStdURL) {
1103 0 : nsAutoCString ref;
1104 0 : nsresult rv = mStdURL->GetRef(ref);
1105 0 : if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
1106 0 : aHash.Assign(char16_t('#'));
1107 0 : AppendUTF8toUTF16(ref, aHash);
1108 : }
1109 0 : return;
1110 : }
1111 :
1112 0 : MOZ_ASSERT(mURLProxy);
1113 : RefPtr<GetterRunnable> runnable =
1114 0 : new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHash, aHash,
1115 0 : mURLProxy);
1116 :
1117 0 : runnable->Dispatch(aRv);
1118 : }
1119 :
1120 : void
1121 0 : URLWorker::SetHash(const nsAString& aHash, ErrorResult& aRv)
1122 : {
1123 0 : STDURL_SETTER(aHash, SetRef);
1124 :
1125 0 : MOZ_ASSERT(mURLProxy);
1126 : RefPtr<SetterRunnable> runnable =
1127 : new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHash,
1128 0 : aHash, mURLProxy);
1129 :
1130 0 : runnable->Dispatch(aRv);
1131 0 : if (NS_WARN_IF(aRv.Failed())) {
1132 0 : return;
1133 : }
1134 :
1135 0 : MOZ_ASSERT(!runnable->Failed());
1136 : }
1137 :
1138 : void
1139 0 : URLWorker::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv)
1140 : {
1141 0 : if (mStdURL) {
1142 : // URLMainThread ignores failures here.
1143 0 : mStdURL->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
1144 0 : return;
1145 : }
1146 :
1147 0 : MOZ_ASSERT(mURLProxy);
1148 : RefPtr<SetterRunnable> runnable =
1149 : new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterSearch,
1150 0 : aSearch, mURLProxy);
1151 :
1152 0 : runnable->Dispatch(aRv);
1153 0 : if (NS_WARN_IF(aRv.Failed())) {
1154 0 : return;
1155 : }
1156 :
1157 0 : MOZ_ASSERT(!runnable->Failed());
1158 : }
1159 :
1160 : void
1161 0 : URLWorker::UpdateURLSearchParams()
1162 : {
1163 0 : if (mSearchParams) {
1164 0 : nsAutoString search;
1165 :
1166 0 : ErrorResult rv;
1167 0 : GetSearch(search, rv);
1168 0 : if (NS_WARN_IF(rv.Failed())) {
1169 0 : rv.SuppressException();
1170 : }
1171 :
1172 0 : mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(Substring(search, 1)));
1173 : }
1174 0 : }
1175 :
1176 : } // namespace dom
1177 : } // namespace mozilla
|