1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 #include "WorkerPrivate.h"
10 #include "nsThreadUtils.h"
12 #include "nsPIDOMWindow.h"
13 #include "nsGlobalWindow.h"
14 #include "nsHostObjectProtocolHandler.h"
15 #include "nsServiceManagerUtils.h"
17 #include "nsIDocument.h"
18 #include "nsIDOMFile.h"
20 #include "mozilla/dom/URL.h"
21 #include "mozilla/dom/URLBinding.h"
22 #include "nsIIOService.h"
25 BEGIN_WORKERS_NAMESPACE
26 using mozilla::dom::GlobalObject
;
28 class URLProxy MOZ_FINAL
31 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLProxy
)
33 URLProxy(mozilla::dom::URL
* aURL
)
36 AssertIsOnMainThread();
44 mozilla::dom::URL
* URL()
51 return mURL
->GetURI();
56 AssertIsOnMainThread();
61 nsRefPtr
<mozilla::dom::URL
> mURL
;
64 // Base class for the URL runnable objects.
65 class URLRunnable
: public nsRunnable
68 WorkerPrivate
* mWorkerPrivate
;
69 uint32_t mSyncQueueKey
;
72 class ResponseRunnable
: public WorkerSyncRunnable
74 uint32_t mSyncQueueKey
;
77 ResponseRunnable(WorkerPrivate
* aWorkerPrivate
,
78 uint32_t aSyncQueueKey
)
79 : WorkerSyncRunnable(aWorkerPrivate
, aSyncQueueKey
, false),
80 mSyncQueueKey(aSyncQueueKey
)
82 NS_ASSERTION(aWorkerPrivate
, "Don't hand me a null WorkerPrivate!");
86 WorkerRun(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
)
88 aWorkerPrivate
->StopSyncLoop(mSyncQueueKey
, true);
93 PreDispatch(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
)
95 AssertIsOnMainThread();
100 PostDispatch(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
,
101 bool aDispatchResult
)
103 AssertIsOnMainThread();
108 URLRunnable(WorkerPrivate
* aWorkerPrivate
)
109 : mWorkerPrivate(aWorkerPrivate
)
111 mWorkerPrivate
->AssertIsOnWorkerThread();
116 Dispatch(JSContext
* aCx
)
118 mWorkerPrivate
->AssertIsOnWorkerThread();
119 AutoSyncLoopHolder
syncLoop(mWorkerPrivate
);
120 mSyncQueueKey
= syncLoop
.SyncQueueKey();
122 if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL
))) {
123 JS_ReportError(aCx
, "Failed to dispatch to main thread!");
127 return syncLoop
.RunAndForget(aCx
);
133 AssertIsOnMainThread();
137 nsRefPtr
<ResponseRunnable
> response
=
138 new ResponseRunnable(mWorkerPrivate
, mSyncQueueKey
);
139 if (!response
->Dispatch(nullptr)) {
140 NS_WARNING("Failed to dispatch response!");
151 // This class creates an URL from a DOM Blob on the main thread.
152 class CreateURLRunnable
: public URLRunnable
159 CreateURLRunnable(WorkerPrivate
* aWorkerPrivate
, nsIDOMBlob
* aBlob
,
160 const mozilla::dom::objectURLOptions
& aOptions
,
162 : URLRunnable(aWorkerPrivate
),
172 AssertIsOnMainThread();
174 nsCOMPtr
<nsIPrincipal
> principal
;
175 nsIDocument
* doc
= nullptr;
177 nsCOMPtr
<nsPIDOMWindow
> window
= mWorkerPrivate
->GetWindow();
179 doc
= window
->GetExtantDoc();
181 SetDOMStringToNull(mURL
);
185 principal
= doc
->NodePrincipal();
187 MOZ_ASSERT_IF(!mWorkerPrivate
->GetParent(), mWorkerPrivate
->IsChromeWorker());
188 principal
= mWorkerPrivate
->GetPrincipal();
192 nsresult rv
= nsHostObjectProtocolHandler::AddDataEntry(
193 NS_LITERAL_CSTRING(BLOBURI_SCHEME
),
194 mBlob
, principal
, url
);
197 NS_WARNING("Failed to add data entry for the blob!");
198 SetDOMStringToNull(mURL
);
203 doc
->RegisterHostObjectUri(url
);
205 mWorkerPrivate
->RegisterHostObjectURI(url
);
208 mURL
= NS_ConvertUTF8toUTF16(url
);
212 // This class revokes an URL on the main thread.
213 class RevokeURLRunnable
: public URLRunnable
219 RevokeURLRunnable(WorkerPrivate
* aWorkerPrivate
,
220 const nsAString
& aURL
)
221 : URLRunnable(aWorkerPrivate
),
228 AssertIsOnMainThread();
230 nsCOMPtr
<nsIPrincipal
> principal
;
231 nsIDocument
* doc
= nullptr;
233 nsCOMPtr
<nsPIDOMWindow
> window
= mWorkerPrivate
->GetWindow();
235 doc
= window
->GetExtantDoc();
240 principal
= doc
->NodePrincipal();
242 MOZ_ASSERT_IF(!mWorkerPrivate
->GetParent(), mWorkerPrivate
->IsChromeWorker());
243 principal
= mWorkerPrivate
->GetPrincipal();
246 NS_ConvertUTF16toUTF8
url(mURL
);
248 nsIPrincipal
* urlPrincipal
=
249 nsHostObjectProtocolHandler::GetDataEntryPrincipal(url
);
253 NS_SUCCEEDED(principal
->Subsumes(urlPrincipal
, &subsumes
)) &&
256 doc
->UnregisterHostObjectUri(url
);
259 nsHostObjectProtocolHandler::RemoveDataEntry(url
);
263 mWorkerPrivate
->UnregisterHostObjectURI(url
);
268 // This class creates a URL object on the main thread.
269 class ConstructorRunnable
: public URLRunnable
274 const nsString mBase
;
275 nsRefPtr
<URLProxy
> mBaseProxy
;
276 mozilla::ErrorResult
& mRv
;
278 nsRefPtr
<URLProxy
> mRetval
;
281 ConstructorRunnable(WorkerPrivate
* aWorkerPrivate
,
282 const nsAString
& aURL
, const nsAString
& aBase
,
283 mozilla::ErrorResult
& aRv
)
284 : URLRunnable(aWorkerPrivate
)
289 mWorkerPrivate
->AssertIsOnWorkerThread();
292 ConstructorRunnable(WorkerPrivate
* aWorkerPrivate
,
293 const nsAString
& aURL
, URLProxy
* aBaseProxy
,
294 mozilla::ErrorResult
& aRv
)
295 : URLRunnable(aWorkerPrivate
)
297 , mBaseProxy(aBaseProxy
)
300 mWorkerPrivate
->AssertIsOnWorkerThread();
306 AssertIsOnMainThread();
309 nsCOMPtr
<nsIIOService
> ioService(do_GetService(NS_IOSERVICE_CONTRACTID
, &rv
));
315 nsCOMPtr
<nsIURI
> baseURL
;
318 rv
= ioService
->NewURI(NS_ConvertUTF16toUTF8(mBase
), nullptr, nullptr,
319 getter_AddRefs(baseURL
));
321 mRv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
325 baseURL
= mBaseProxy
->URI();
328 nsCOMPtr
<nsIURI
> url
;
329 rv
= ioService
->NewURI(NS_ConvertUTF16toUTF8(mURL
), nullptr, baseURL
,
330 getter_AddRefs(url
));
332 mRv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
336 mRetval
= new URLProxy(new mozilla::dom::URL(url
));
346 class TeardownRunnable
: public nsRunnable
349 TeardownRunnable(URLProxy
* aURLProxy
)
350 : mURLProxy(aURLProxy
)
356 AssertIsOnMainThread();
358 mURLProxy
->ReleaseURI();
365 nsRefPtr
<URLProxy
> mURLProxy
;
368 // This class is the generic getter for any URL property.
369 class GetterRunnable
: public URLRunnable
386 GetterRunnable(WorkerPrivate
* aWorkerPrivate
,
387 GetterType aType
, nsString
& aValue
,
389 : URLRunnable(aWorkerPrivate
)
392 , mURLProxy(aURLProxy
)
394 mWorkerPrivate
->AssertIsOnWorkerThread();
400 AssertIsOnMainThread();
404 mURLProxy
->URL()->GetHref(mValue
);
408 mURLProxy
->URL()->GetOrigin(mValue
);
412 mURLProxy
->URL()->GetProtocol(mValue
);
416 mURLProxy
->URL()->GetUsername(mValue
);
420 mURLProxy
->URL()->GetPassword(mValue
);
424 mURLProxy
->URL()->GetHost(mValue
);
428 mURLProxy
->URL()->GetHostname(mValue
);
432 mURLProxy
->URL()->GetPort(mValue
);
436 mURLProxy
->URL()->GetPathname(mValue
);
440 mURLProxy
->URL()->GetSearch(mValue
);
444 mURLProxy
->URL()->GetHash(mValue
);
452 nsRefPtr
<URLProxy
> mURLProxy
;
455 // This class is the generic setter for any URL property.
456 class SetterRunnable
: public URLRunnable
472 SetterRunnable(WorkerPrivate
* aWorkerPrivate
,
473 SetterType aType
, const nsAString
& aValue
,
474 URLProxy
* aURLProxy
, mozilla::ErrorResult
& aRv
)
475 : URLRunnable(aWorkerPrivate
)
478 , mURLProxy(aURLProxy
)
481 mWorkerPrivate
->AssertIsOnWorkerThread();
487 AssertIsOnMainThread();
491 mURLProxy
->URL()->SetHref(mValue
, mRv
);
495 mURLProxy
->URL()->SetProtocol(mValue
);
499 mURLProxy
->URL()->SetUsername(mValue
);
503 mURLProxy
->URL()->SetPassword(mValue
);
507 mURLProxy
->URL()->SetHost(mValue
);
511 mURLProxy
->URL()->SetHostname(mValue
);
515 mURLProxy
->URL()->SetPort(mValue
);
519 mURLProxy
->URL()->SetPathname(mValue
);
523 mURLProxy
->URL()->SetSearch(mValue
);
527 mURLProxy
->URL()->SetHash(mValue
);
533 const nsString mValue
;
535 nsRefPtr
<URLProxy
> mURLProxy
;
536 mozilla::ErrorResult
& mRv
;
541 URL::Constructor(const GlobalObject
& aGlobal
, const nsAString
& aUrl
,
542 URL
& aBase
, ErrorResult
& aRv
)
544 JSContext
* cx
= aGlobal
.GetContext();
545 WorkerPrivate
* workerPrivate
= GetWorkerPrivateFromContext(cx
);
547 nsRefPtr
<ConstructorRunnable
> runnable
=
548 new ConstructorRunnable(workerPrivate
, aUrl
, aBase
.GetURLProxy(), aRv
);
550 if (!runnable
->Dispatch(cx
)) {
551 JS_ReportPendingException(cx
);
554 nsRefPtr
<URLProxy
> proxy
= runnable
->GetURLProxy();
556 aRv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
560 return new URL(workerPrivate
, proxy
);
565 URL::Constructor(const GlobalObject
& aGlobal
, const nsAString
& aUrl
,
566 const nsAString
& aBase
, ErrorResult
& aRv
)
568 JSContext
* cx
= aGlobal
.GetContext();
569 WorkerPrivate
* workerPrivate
= GetWorkerPrivateFromContext(cx
);
571 nsRefPtr
<ConstructorRunnable
> runnable
=
572 new ConstructorRunnable(workerPrivate
, aUrl
, aBase
, aRv
);
574 if (!runnable
->Dispatch(cx
)) {
575 JS_ReportPendingException(cx
);
578 nsRefPtr
<URLProxy
> proxy
= runnable
->GetURLProxy();
580 aRv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
584 return new URL(workerPrivate
, proxy
);
587 URL::URL(WorkerPrivate
* aWorkerPrivate
, URLProxy
* aURLProxy
)
588 : mWorkerPrivate(aWorkerPrivate
)
589 , mURLProxy(aURLProxy
)
591 MOZ_COUNT_CTOR(workers::URL
);
596 MOZ_COUNT_DTOR(workers::URL
);
599 nsRefPtr
<TeardownRunnable
> runnable
= new TeardownRunnable(mURLProxy
);
602 if (NS_FAILED(NS_DispatchToMainThread(runnable
))) {
603 NS_ERROR("Failed to dispatch teardown runnable!");
609 URL::WrapObject(JSContext
* aCx
, JS::Handle
<JSObject
*> aScope
,
610 bool* aTookOwnership
)
612 return URLBinding_workers::Wrap(aCx
, aScope
, this, aTookOwnership
);
616 URL::GetHref(nsString
& aHref
) const
618 nsRefPtr
<GetterRunnable
> runnable
=
619 new GetterRunnable(mWorkerPrivate
, GetterRunnable::GetterHref
, aHref
,
622 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
623 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
628 URL::SetHref(const nsAString
& aHref
, ErrorResult
& aRv
)
630 nsRefPtr
<SetterRunnable
> runnable
=
631 new SetterRunnable(mWorkerPrivate
, SetterRunnable::SetterHref
, aHref
,
634 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
635 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
640 URL::GetOrigin(nsString
& aOrigin
) const
642 nsRefPtr
<GetterRunnable
> runnable
=
643 new GetterRunnable(mWorkerPrivate
, GetterRunnable::GetterOrigin
, aOrigin
,
646 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
647 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
652 URL::GetProtocol(nsString
& aProtocol
) const
654 nsRefPtr
<GetterRunnable
> runnable
=
655 new GetterRunnable(mWorkerPrivate
, GetterRunnable::GetterProtocol
, aProtocol
,
658 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
659 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
664 URL::SetProtocol(const nsAString
& aProtocol
)
667 nsRefPtr
<SetterRunnable
> runnable
=
668 new SetterRunnable(mWorkerPrivate
, SetterRunnable::SetterProtocol
,
669 aProtocol
, mURLProxy
, rv
);
671 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
672 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
677 URL::GetUsername(nsString
& aUsername
) const
679 nsRefPtr
<GetterRunnable
> runnable
=
680 new GetterRunnable(mWorkerPrivate
, GetterRunnable::GetterUsername
, aUsername
,
683 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
684 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
689 URL::SetUsername(const nsAString
& aUsername
)
692 nsRefPtr
<SetterRunnable
> runnable
=
693 new SetterRunnable(mWorkerPrivate
, SetterRunnable::SetterUsername
,
694 aUsername
, mURLProxy
, rv
);
696 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
697 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
702 URL::GetPassword(nsString
& aPassword
) const
704 nsRefPtr
<GetterRunnable
> runnable
=
705 new GetterRunnable(mWorkerPrivate
, GetterRunnable::GetterPassword
, aPassword
,
708 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
709 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
714 URL::SetPassword(const nsAString
& aPassword
)
717 nsRefPtr
<SetterRunnable
> runnable
=
718 new SetterRunnable(mWorkerPrivate
, SetterRunnable::SetterPassword
,
719 aPassword
, mURLProxy
, rv
);
721 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
722 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
727 URL::GetHost(nsString
& aHost
) const
729 nsRefPtr
<GetterRunnable
> runnable
=
730 new GetterRunnable(mWorkerPrivate
, GetterRunnable::GetterHost
, aHost
,
733 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
734 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
739 URL::SetHost(const nsAString
& aHost
)
742 nsRefPtr
<SetterRunnable
> runnable
=
743 new SetterRunnable(mWorkerPrivate
, SetterRunnable::SetterHost
,
744 aHost
, mURLProxy
, rv
);
746 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
747 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
752 URL::GetHostname(nsString
& aHostname
) const
754 nsRefPtr
<GetterRunnable
> runnable
=
755 new GetterRunnable(mWorkerPrivate
, GetterRunnable::GetterHostname
, aHostname
,
758 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
759 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
764 URL::SetHostname(const nsAString
& aHostname
)
767 nsRefPtr
<SetterRunnable
> runnable
=
768 new SetterRunnable(mWorkerPrivate
, SetterRunnable::SetterHostname
,
769 aHostname
, mURLProxy
, rv
);
771 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
772 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
777 URL::GetPort(nsString
& aPort
) const
779 nsRefPtr
<GetterRunnable
> runnable
=
780 new GetterRunnable(mWorkerPrivate
, GetterRunnable::GetterPort
, aPort
,
783 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
784 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
789 URL::SetPort(const nsAString
& aPort
)
792 nsRefPtr
<SetterRunnable
> runnable
=
793 new SetterRunnable(mWorkerPrivate
, SetterRunnable::SetterPort
,
794 aPort
, mURLProxy
, rv
);
796 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
797 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
802 URL::GetPathname(nsString
& aPathname
) const
804 nsRefPtr
<GetterRunnable
> runnable
=
805 new GetterRunnable(mWorkerPrivate
, GetterRunnable::GetterPathname
, aPathname
,
808 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
809 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
814 URL::SetPathname(const nsAString
& aPathname
)
817 nsRefPtr
<SetterRunnable
> runnable
=
818 new SetterRunnable(mWorkerPrivate
, SetterRunnable::SetterPathname
,
819 aPathname
, mURLProxy
, rv
);
821 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
822 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
827 URL::GetSearch(nsString
& aSearch
) const
829 nsRefPtr
<GetterRunnable
> runnable
=
830 new GetterRunnable(mWorkerPrivate
, GetterRunnable::GetterSearch
, aSearch
,
833 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
834 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
839 URL::SetSearch(const nsAString
& aSearch
)
842 nsRefPtr
<SetterRunnable
> runnable
=
843 new SetterRunnable(mWorkerPrivate
, SetterRunnable::SetterSearch
,
844 aSearch
, mURLProxy
, rv
);
846 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
847 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
852 URL::GetHash(nsString
& aHash
) const
854 nsRefPtr
<GetterRunnable
> runnable
=
855 new GetterRunnable(mWorkerPrivate
, GetterRunnable::GetterHash
, aHash
,
858 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
859 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
864 URL::SetHash(const nsAString
& aHash
)
867 nsRefPtr
<SetterRunnable
> runnable
=
868 new SetterRunnable(mWorkerPrivate
, SetterRunnable::SetterHash
,
869 aHash
, mURLProxy
, rv
);
871 if (!runnable
->Dispatch(mWorkerPrivate
->GetJSContext())) {
872 JS_ReportPendingException(mWorkerPrivate
->GetJSContext());
878 URL::CreateObjectURL(const GlobalObject
& aGlobal
, JSObject
* aBlob
,
879 const mozilla::dom::objectURLOptions
& aOptions
,
880 nsString
& aResult
, mozilla::ErrorResult
& aRv
)
882 JSContext
* cx
= aGlobal
.GetContext();
883 WorkerPrivate
* workerPrivate
= GetWorkerPrivateFromContext(cx
);
885 nsCOMPtr
<nsIDOMBlob
> blob
= file::GetDOMBlobFromJSObject(aBlob
);
887 SetDOMStringToNull(aResult
);
889 NS_NAMED_LITERAL_STRING(argStr
, "Argument 1 of URL.createObjectURL");
890 NS_NAMED_LITERAL_STRING(blobStr
, "Blob");
891 aRv
.ThrowTypeError(MSG_DOES_NOT_IMPLEMENT_INTERFACE
, &argStr
, &blobStr
);
895 nsRefPtr
<CreateURLRunnable
> runnable
=
896 new CreateURLRunnable(workerPrivate
, blob
, aOptions
, aResult
);
898 if (!runnable
->Dispatch(cx
)) {
899 JS_ReportPendingException(cx
);
905 URL::CreateObjectURL(const GlobalObject
& aGlobal
, JSObject
& aBlob
,
906 const mozilla::dom::objectURLOptions
& aOptions
,
907 nsString
& aResult
, mozilla::ErrorResult
& aRv
)
909 return CreateObjectURL(aGlobal
, &aBlob
, aOptions
, aResult
, aRv
);
914 URL::RevokeObjectURL(const GlobalObject
& aGlobal
, const nsAString
& aUrl
)
916 JSContext
* cx
= aGlobal
.GetContext();
917 WorkerPrivate
* workerPrivate
= GetWorkerPrivateFromContext(cx
);
919 nsRefPtr
<RevokeURLRunnable
> runnable
=
920 new RevokeURLRunnable(workerPrivate
, aUrl
);
922 if (!runnable
->Dispatch(cx
)) {
923 JS_ReportPendingException(cx
);
927 END_WORKERS_NAMESPACE