From 8e2da98d46fea760e0dc84319dde01d498454efd Mon Sep 17 00:00:00 2001 From: Narcis Beleuzu Date: Thu, 13 Jun 2019 20:59:33 +0300 Subject: [PATCH] Backed out 2 changesets (bug 1558923) for mochitest crashes on AssertIsOnMainThread(). CLOSED TREE Backed out changeset 643de99320a8 (bug 1558923) Backed out changeset f758b5ccd0c0 (bug 1558923) --- dom/base/nsContentUtils.cpp | 83 ++++++++++ dom/base/nsContentUtils.h | 2 + dom/fetch/Request.cpp | 3 +- dom/fetch/Response.cpp | 3 +- dom/url/URL.cpp | 102 +------------ dom/url/URL.h | 33 ++-- dom/url/URLMainThread.cpp | 114 ++++++++++++++ dom/url/URLMainThread.h | 29 +++- dom/url/URLWorker.cpp | 297 ++++++++++++++++++++++++++++++++++++ dom/url/URLWorker.h | 22 ++- 10 files changed, 570 insertions(+), 118 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 362fab1f1436..41ce20e0a674 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -5745,6 +5745,7 @@ nsresult nsContentUtils::GetASCIIOrigin(nsIPrincipal* aPrincipal, /* static */ nsresult nsContentUtils::GetASCIIOrigin(nsIURI* aURI, nsACString& aOrigin) { MOZ_ASSERT(aURI, "missing uri"); + MOZ_ASSERT(NS_IsMainThread()); bool isBlobURL = false; nsresult rv = aURI->SchemeIs(BLOBURI_SCHEME, &isBlobURL); @@ -5795,6 +5796,69 @@ nsresult nsContentUtils::GetASCIIOrigin(nsIURI* aURI, nsACString& aOrigin) { return NS_OK; } +/* static */ +nsresult nsContentUtils::GetThreadSafeASCIIOrigin(nsIURI* aURI, + nsACString& aOrigin) { + MOZ_ASSERT(aURI, "missing uri"); + + bool isBlobURL = false; + nsresult rv = aURI->SchemeIs(BLOBURI_SCHEME, &isBlobURL); + NS_ENSURE_SUCCESS(rv, rv); + + // For Blob URI, the path is the URL of the owning page. + if (isBlobURL) { + nsAutoCString path; + rv = aURI->GetPathQueryRef(path); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), path); + if (rv == NS_ERROR_UNKNOWN_PROTOCOL) { + return NS_ERROR_UNKNOWN_PROTOCOL; + } + + if (NS_FAILED(rv)) { + aOrigin.AssignLiteral("null"); + return NS_OK; + } + + return GetThreadSafeASCIIOrigin(uri, aOrigin); + } + + aOrigin.Truncate(); + + // This is not supported yet. + nsCOMPtr nestedURI(do_QueryInterface(aURI)); + if (nestedURI) { + return NS_ERROR_UNKNOWN_PROTOCOL; + } + + nsAutoCString host; + rv = aURI->GetAsciiHost(host); + + if (NS_SUCCEEDED(rv) && !host.IsEmpty()) { + nsAutoCString userPass; + aURI->GetUserPass(userPass); + + nsCOMPtr uri = aURI; + + nsAutoCString prePath; + if (!userPass.IsEmpty()) { + rv = NS_MutateURI(uri).SetUserPass(EmptyCString()).Finalize(uri); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = uri->GetPrePath(prePath); + NS_ENSURE_SUCCESS(rv, rv); + + aOrigin = prePath; + } else { + aOrigin.AssignLiteral("null"); + } + + return NS_OK; +} + /* static */ nsresult nsContentUtils::GetUTFOrigin(nsIPrincipal* aPrincipal, nsAString& aOrigin) { @@ -5813,6 +5877,7 @@ nsresult nsContentUtils::GetUTFOrigin(nsIPrincipal* aPrincipal, /* static */ nsresult nsContentUtils::GetUTFOrigin(nsIURI* aURI, nsAString& aOrigin) { MOZ_ASSERT(aURI, "missing uri"); + MOZ_ASSERT(NS_IsMainThread()); nsresult rv; #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) @@ -5836,6 +5901,24 @@ nsresult nsContentUtils::GetUTFOrigin(nsIURI* aURI, nsAString& aOrigin) { return NS_OK; } +/* static */ +nsresult nsContentUtils::GetThreadSafeUTFOrigin(nsIURI* aURI, + nsAString& aOrigin) { +#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) + return NS_ERROR_UNKNOWN_PROTOCOL; +#endif + + MOZ_ASSERT(aURI, "missing uri"); + nsresult rv; + + nsAutoCString asciiOrigin; + rv = GetThreadSafeASCIIOrigin(aURI, asciiOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + aOrigin = NS_ConvertUTF8toUTF16(asciiOrigin); + return NS_OK; +} + /* static */ bool nsContentUtils::CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel, diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 351510a92604..d665c159f6dc 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2141,8 +2141,10 @@ class nsContentUtils { */ static nsresult GetASCIIOrigin(nsIPrincipal* aPrincipal, nsACString& aOrigin); static nsresult GetASCIIOrigin(nsIURI* aURI, nsACString& aOrigin); + static nsresult GetThreadSafeASCIIOrigin(nsIURI* aURI, nsACString& aOrigin); static nsresult GetUTFOrigin(nsIPrincipal* aPrincipal, nsAString& aOrigin); static nsresult GetUTFOrigin(nsIURI* aURI, nsAString& aOrigin); + static nsresult GetThreadSafeUTFOrigin(nsIURI* aURI, nsAString& aOrigin); /** * This method creates and dispatches "command" event, which implements diff --git a/dom/fetch/Request.cpp b/dom/fetch/Request.cpp index ce29bb411870..fe65bf59ba0e 100644 --- a/dom/fetch/Request.cpp +++ b/dom/fetch/Request.cpp @@ -178,8 +178,7 @@ already_AddRefed ParseURLFromWorker(const GlobalObject& aGlobal, worker->AssertIsOnWorkerThread(); NS_ConvertUTF8toUTF16 baseURL(worker->GetLocationInfo().mHref); - RefPtr url = - URL::Constructor(aGlobal.GetAsSupports(), aInput, baseURL, aRv); + RefPtr url = URL::WorkerConstructor(aGlobal, aInput, baseURL, aRv); if (NS_WARN_IF(aRv.Failed())) { aRv.ThrowTypeError(aInput); } diff --git a/dom/fetch/Response.cpp b/dom/fetch/Response.cpp index 5b4de05174f6..b27a8d4dd561 100644 --- a/dom/fetch/Response.cpp +++ b/dom/fetch/Response.cpp @@ -126,8 +126,7 @@ already_AddRefed Response::Redirect(const GlobalObject& aGlobal, worker->AssertIsOnWorkerThread(); NS_ConvertUTF8toUTF16 baseURL(worker->GetLocationInfo().mHref); - RefPtr url = - URL::Constructor(aGlobal.GetAsSupports(), aUrl, baseURL, aRv); + RefPtr url = URL::WorkerConstructor(aGlobal, aUrl, baseURL, aRv); if (aRv.Failed()) { return nullptr; } diff --git a/dom/url/URL.cpp b/dom/url/URL.cpp index 3be07c8e638a..b06c9b9fa278 100644 --- a/dom/url/URL.cpp +++ b/dom/url/URL.cpp @@ -14,7 +14,6 @@ #include "nsContentUtils.h" #include "mozilla/dom/Document.h" #include "nsIURIMutator.h" -#include "nsNetUtil.h" namespace mozilla { namespace dom { @@ -38,46 +37,19 @@ already_AddRefed URL::Constructor(const GlobalObject& aGlobal, const nsAString& aURL, const Optional& aBase, ErrorResult& aRv) { - if (aBase.WasPassed()) { - return Constructor(aGlobal.GetAsSupports(), aURL, aBase.Value(), aRv); + if (NS_IsMainThread()) { + return URLMainThread::Constructor(aGlobal, aURL, aBase, aRv); } - return Constructor(aGlobal.GetAsSupports(), aURL, nullptr, aRv); + return URLWorker::Constructor(aGlobal, aURL, aBase, aRv); } /* static */ -already_AddRefed URL::Constructor(nsISupports* aParent, - const nsAString& aURL, - const nsAString& aBase, - ErrorResult& aRv) { - nsCOMPtr baseUri; - nsresult rv = NS_NewURI(getter_AddRefs(baseUri), aBase, nullptr, nullptr, - nsContentUtils::GetIOService()); - if (NS_WARN_IF(NS_FAILED(rv))) { - aRv.ThrowTypeError(aBase); - return nullptr; - } - - return Constructor(aParent, aURL, baseUri, aRv); -} - -/* static */ -already_AddRefed URL::Constructor(nsISupports* aParent, - const nsAString& aURL, nsIURI* aBase, - ErrorResult& aRv) { - nsCOMPtr uri; - nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, aBase, - nsContentUtils::GetIOService()); - if (NS_FAILED(rv)) { - // No need to warn in this case. It's common to use the URL constructor - // to determine if a URL is valid and an exception will be propagated. - aRv.ThrowTypeError(aURL); - return nullptr; - } - - RefPtr url = new URL(aParent); - url->SetURI(uri.forget()); - return url.forget(); +already_AddRefed URL::WorkerConstructor(const GlobalObject& aGlobal, + const nsAString& aURL, + const nsAString& aBase, + ErrorResult& aRv) { + return URLWorker::Constructor(aGlobal, aURL, aBase, aRv); } void URL::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, @@ -156,69 +128,11 @@ void URL::URLSearchParamsUpdated(URLSearchParams* aSearchParams) { void URL::GetHref(nsAString& aHref) const { URL_GETTER(aHref, GetSpec); } -void URL::SetHref(const nsAString& aHref, ErrorResult& aRv) { - AssertIsOnMainThread(); - - nsCOMPtr uri; - nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref, nullptr, nullptr, - nsContentUtils::GetIOService()); - if (NS_FAILED(rv)) { - aRv.ThrowTypeError(aHref); - return; - } - - mURI = std::move(uri); - UpdateURLSearchParams(); -} - -void URL::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const { - nsresult rv = nsContentUtils::GetUTFOrigin(GetURI(), aOrigin); - if (NS_WARN_IF(NS_FAILED(rv))) { - aOrigin.Truncate(); - } -} - void URL::GetProtocol(nsAString& aProtocol) const { URL_GETTER(aProtocol, GetScheme); aProtocol.Append(char16_t(':')); } -void URL::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) { - nsAString::const_iterator start; - aProtocol.BeginReading(start); - - nsAString::const_iterator end; - aProtocol.EndReading(end); - - nsAString::const_iterator iter(start); - FindCharInReadable(':', iter, end); - - // Changing the protocol of a URL, changes the "nature" of the URI - // implementation. In order to do this properly, we have to serialize the - // existing URL and reparse it in a new object. - nsCOMPtr clone; - nsresult rv = NS_MutateURI(GetURI()) - .SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter))) - .Finalize(clone); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - nsAutoCString href; - rv = clone->GetSpec(href); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - nsCOMPtr uri; - rv = NS_NewURI(getter_AddRefs(uri), href); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - mURI = std::move(uri); -} - void URL::GetUsername(nsAString& aUsername) const { URL_GETTER(aUsername, GetUsername); } diff --git a/dom/url/URL.h b/dom/url/URL.h index 34706ffaa9c0..6cb29acfe227 100644 --- a/dom/url/URL.h +++ b/dom/url/URL.h @@ -26,32 +26,29 @@ class Blob; class MediaSource; class GlobalObject; -class URL final : public URLSearchParamsObserver, public nsWrapperCache { +class URL : public URLSearchParamsObserver, public nsWrapperCache { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(URL) - explicit URL(nsISupports* aParent) : mParent(aParent) {} + URL(nsISupports* aParent) : mParent(aParent) {} // WebIDL methods nsISupports* GetParentObject() const { return mParent; } - JSObject* WrapObject(JSContext* aCx, - JS::Handle aGivenProto) override; + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; static already_AddRefed Constructor(const GlobalObject& aGlobal, const nsAString& aURL, const Optional& aBase, ErrorResult& aRv); - static already_AddRefed Constructor(nsISupports* aParent, - const nsAString& aURL, - const nsAString& aBase, - ErrorResult& aRv); - - static already_AddRefed Constructor(nsISupports* aParent, - const nsAString& aURL, nsIURI* aBase, - ErrorResult& aRv); + // Helper for Fetch API + static already_AddRefed WorkerConstructor(const GlobalObject& aGlobal, + const nsAString& aURL, + const nsAString& aBase, + ErrorResult& aRv); static void CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, nsAString& aResult, ErrorResult& aRv); @@ -67,13 +64,13 @@ class URL final : public URLSearchParamsObserver, public nsWrapperCache { void GetHref(nsAString& aHref) const; - void SetHref(const nsAString& aHref, ErrorResult& aRv); + virtual void SetHref(const nsAString& aHref, ErrorResult& aRv) = 0; - void GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const; + virtual void GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const = 0; void GetProtocol(nsAString& aProtocol) const; - void SetProtocol(const nsAString& aProtocol, ErrorResult& aRv); + virtual void SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) = 0; void GetUsername(nsAString& aUsername) const; @@ -101,7 +98,7 @@ class URL final : public URLSearchParamsObserver, public nsWrapperCache { void GetSearch(nsAString& aSearch) const; - void SetSearch(const nsAString& aSearch); + virtual void SetSearch(const nsAString& aSearch); URLSearchParams* SearchParams(); @@ -116,8 +113,8 @@ class URL final : public URLSearchParamsObserver, public nsWrapperCache { // URLSearchParamsObserver void URLSearchParamsUpdated(URLSearchParams* aSearchParams) override; - private: - ~URL() = default; + protected: + virtual ~URL() = default; void SetURI(already_AddRefed aURI); diff --git a/dom/url/URLMainThread.cpp b/dom/url/URLMainThread.cpp index 81076ef1093c..ab263db312d6 100644 --- a/dom/url/URLMainThread.cpp +++ b/dom/url/URLMainThread.cpp @@ -18,6 +18,55 @@ namespace mozilla { namespace dom { +/* static */ +already_AddRefed URLMainThread::Constructor( + const GlobalObject& aGlobal, const nsAString& aURL, + const Optional& aBase, ErrorResult& aRv) { + if (aBase.WasPassed()) { + return Constructor(aGlobal.GetAsSupports(), aURL, aBase.Value(), aRv); + } + + return Constructor(aGlobal.GetAsSupports(), aURL, nullptr, aRv); +} + +/* static */ +already_AddRefed URLMainThread::Constructor( + nsISupports* aParent, const nsAString& aURL, const nsAString& aBase, + ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr baseUri; + nsresult rv = NS_NewURI(getter_AddRefs(baseUri), aBase, nullptr, nullptr, + nsContentUtils::GetIOService()); + if (NS_WARN_IF(NS_FAILED(rv))) { + aRv.ThrowTypeError(aBase); + return nullptr; + } + + return Constructor(aParent, aURL, baseUri, aRv); +} + +/* static */ +already_AddRefed URLMainThread::Constructor( + nsISupports* aParent, const nsAString& aURL, nsIURI* aBase, + ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, aBase, + nsContentUtils::GetIOService()); + if (NS_FAILED(rv)) { + // No need to warn in this case. It's common to use the URL constructor + // to determine if a URL is valid and an exception will be propagated. + aRv.ThrowTypeError(aURL); + return nullptr; + } + + RefPtr url = new URLMainThread(aParent); + url->SetURI(uri.forget()); + return url.forget(); +} + /* static */ void URLMainThread::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, nsAString& aResult, ErrorResult& aRv) { @@ -89,6 +138,12 @@ void URLMainThread::RevokeObjectURL(const GlobalObject& aGlobal, } } +URLMainThread::URLMainThread(nsISupports* aParent) : URL(aParent) { + MOZ_ASSERT(NS_IsMainThread()); +} + +URLMainThread::~URLMainThread() { MOZ_ASSERT(NS_IsMainThread()); } + /* static */ bool URLMainThread::IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL, ErrorResult& aRv) { @@ -97,5 +152,64 @@ bool URLMainThread::IsValidURL(const GlobalObject& aGlobal, return BlobURLProtocolHandler::HasDataEntry(asciiurl); } +void URLMainThread::SetHref(const nsAString& aHref, ErrorResult& aRv) { + NS_ConvertUTF16toUTF8 href(aHref); + + nsresult rv; + nsCOMPtr ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return; + } + + nsCOMPtr uri; + rv = ioService->NewURI(href, nullptr, nullptr, getter_AddRefs(uri)); + if (NS_FAILED(rv)) { + aRv.ThrowTypeError(aHref); + return; + } + + SetURI(uri.forget()); + UpdateURLSearchParams(); +} + +void URLMainThread::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const { + nsContentUtils::GetUTFOrigin(GetURI(), aOrigin); +} + +void URLMainThread::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) { + nsAString::const_iterator start, end; + aProtocol.BeginReading(start); + aProtocol.EndReading(end); + nsAString::const_iterator iter(start); + + FindCharInReadable(':', iter, end); + + // Changing the protocol of a URL, changes the "nature" of the URI + // implementation. In order to do this properly, we have to serialize the + // existing URL and reparse it in a new object. + nsCOMPtr clone; + nsresult rv = NS_MutateURI(GetURI()) + .SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter))) + .Finalize(clone); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + nsAutoCString href; + rv = clone->GetSpec(href); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + nsCOMPtr uri; + rv = NS_NewURI(getter_AddRefs(uri), href); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + SetURI(uri.forget()); +} + } // namespace dom } // namespace mozilla diff --git a/dom/url/URLMainThread.h b/dom/url/URLMainThread.h index 6ba2a1c103de..1789bbddf19b 100644 --- a/dom/url/URLMainThread.h +++ b/dom/url/URLMainThread.h @@ -12,8 +12,23 @@ namespace mozilla { namespace dom { -class URLMainThread final { +// The URL implementation for the main-thread +class URLMainThread final : public URL { public: + static already_AddRefed Constructor( + const GlobalObject& aGlobal, const nsAString& aURL, + const Optional& aBase, ErrorResult& aRv); + + static already_AddRefed Constructor(nsISupports* aParent, + const nsAString& aURL, + const nsAString& aBase, + ErrorResult& aRv); + + static already_AddRefed Constructor(nsISupports* aParent, + const nsAString& aURL, + nsIURI* aBase, + ErrorResult& aRv); + static void CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, nsAString& aResult, ErrorResult& aRv); @@ -25,6 +40,18 @@ class URLMainThread final { static bool IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL, ErrorResult& aRv); + + explicit URLMainThread(nsISupports* aParent); + + virtual void SetHref(const nsAString& aHref, ErrorResult& aRv) override; + + virtual void GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const override; + + virtual void SetProtocol(const nsAString& aProtocol, + ErrorResult& aRv) override; + + private: + ~URLMainThread(); }; } // namespace dom diff --git a/dom/url/URLWorker.cpp b/dom/url/URLWorker.cpp index d5d268ad86f9..0c564487ef57 100644 --- a/dom/url/URLWorker.cpp +++ b/dom/url/URLWorker.cpp @@ -11,8 +11,15 @@ #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerRunnable.h" #include "mozilla/dom/WorkerScope.h" +#include "mozilla/Unused.h" +#include "nsProxyRelease.h" +#include "nsStandardURL.h" +#include "nsURLHelper.h" namespace mozilla { + +using net::nsStandardURL; + namespace dom { // This class creates an URL from a DOM Blob on the main thread. @@ -154,6 +161,163 @@ class IsValidURLRunnable : public WorkerMainThreadRunnable { bool IsValidURL() const { return mValid; } }; +// This class creates a URL object on the main thread. +class ConstructorRunnable : public WorkerMainThreadRunnable { + private: + const nsString mURL; + + nsString mBase; // IsVoid() if we have no base URI string. + + nsCOMPtr mRetval; + + public: + ConstructorRunnable(WorkerPrivate* aWorkerPrivate, const nsAString& aURL, + const Optional& aBase) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("URL :: Constructor")), + mURL(aURL) { + if (aBase.WasPassed()) { + mBase = aBase.Value(); + } else { + mBase.SetIsVoid(true); + } + mWorkerPrivate->AssertIsOnWorkerThread(); + } + + bool MainThreadRun() override { + AssertIsOnMainThread(); + + nsCOMPtr baseUri; + if (!mBase.IsVoid()) { + nsresult rv = NS_NewURI(getter_AddRefs(baseUri), mBase, nullptr, nullptr, + nsContentUtils::GetIOService()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return true; + } + } + + nsCOMPtr uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), mURL, nullptr, baseUri, + nsContentUtils::GetIOService()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return true; + } + + mRetval = std::move(uri); + return true; + } + + nsIURI* GetURI(ErrorResult& aRv) const { + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); + + if (!mRetval) { + aRv.ThrowTypeError(mURL); + } + + return mRetval; + } +}; + +class OriginGetterRunnable : public WorkerMainThreadRunnable { + public: + OriginGetterRunnable(WorkerPrivate* aWorkerPrivate, nsAString& aValue, + nsIURI* aURI) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("URL :: origin getter")), + mValue(aValue), + mURI(aURI) { + mWorkerPrivate->AssertIsOnWorkerThread(); + } + + bool MainThreadRun() override { + AssertIsOnMainThread(); + ErrorResult rv; + nsContentUtils::GetUTFOrigin(mURI, mValue); + return true; + } + + void Dispatch(ErrorResult& aRv) { + WorkerMainThreadRunnable::Dispatch(Canceling, aRv); + } + + private: + nsAString& mValue; + nsCOMPtr mURI; +}; + +class ProtocolSetterRunnable : public WorkerMainThreadRunnable { + public: + ProtocolSetterRunnable(WorkerPrivate* aWorkerPrivate, + const nsACString& aValue, nsIURI* aURI) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("ProtocolSetterRunnable")), + mValue(aValue), + mURI(aURI) { + mWorkerPrivate->AssertIsOnWorkerThread(); + } + + bool MainThreadRun() override { + AssertIsOnMainThread(); + + nsCOMPtr clone; + nsresult rv = NS_MutateURI(mURI).SetScheme(mValue).Finalize(clone); + if (NS_WARN_IF(NS_FAILED(rv))) { + return true; + } + + nsAutoCString href; + rv = clone->GetSpec(href); + if (NS_WARN_IF(NS_FAILED(rv))) { + return true; + } + + nsCOMPtr uri; + rv = NS_NewURI(getter_AddRefs(uri), href); + if (NS_WARN_IF(NS_FAILED(rv))) { + return true; + } + + mRetval = std::move(uri); + return true; + } + + void Dispatch(ErrorResult& aRv) { + WorkerMainThreadRunnable::Dispatch(Canceling, aRv); + } + + nsIURI* GetRetval() const { return mRetval; } + + private: + const nsCString mValue; + nsCOMPtr mURI; + nsCOMPtr mRetval; +}; + +/* static */ +already_AddRefed URLWorker::Constructor( + const GlobalObject& aGlobal, const nsAString& aURL, + const Optional& aBase, ErrorResult& aRv) { + JSContext* cx = aGlobal.Context(); + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); + + RefPtr url = new URLWorker(workerPrivate); + url->Init(aURL, aBase, aRv); + + return aRv.Failed() ? nullptr : url.forget(); +} + +/* static */ +already_AddRefed URLWorker::Constructor(const GlobalObject& aGlobal, + const nsAString& aURL, + const nsAString& aBase, + ErrorResult& aRv) { + Optional base; + base = &aBase; + + return Constructor(aGlobal, aURL, base, aRv); +} + /* static */ void URLWorker::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, nsAString& aResult, mozilla::ErrorResult& aRv) { @@ -223,5 +387,138 @@ bool URLWorker::IsValidURL(const GlobalObject& aGlobal, const nsAString& aUrl, return runnable->IsValidURL(); } +URLWorker::URLWorker(WorkerPrivate* aWorkerPrivate) + : URL(nullptr), mWorkerPrivate(aWorkerPrivate) {} + +void URLWorker::Init(const nsAString& aURL, const Optional& aBase, + ErrorResult& aRv) { + nsAutoCString scheme; + nsresult rv = net_ExtractURLScheme(NS_ConvertUTF16toUTF8(aURL), scheme); + if (NS_FAILED(rv)) { + // this may be a relative URL, check baseURL + if (!aBase.WasPassed()) { + aRv.ThrowTypeError(aURL); + return; + } + rv = net_ExtractURLScheme(NS_ConvertUTF16toUTF8(aBase.Value()), scheme); + if (NS_WARN_IF(NS_FAILED(rv))) { + aRv.ThrowTypeError(aURL); + return; + } + } + + // Let's check if the baseURI was passed and if it can be parsed on the worker + // thread. + bool useProxy = false; + nsCOMPtr baseURI; + if (aBase.WasPassed()) { + rv = NS_NewURI(getter_AddRefs(baseURI), + NS_ConvertUTF16toUTF8(aBase.Value())); + if (NS_FAILED(rv)) { + if (rv != NS_ERROR_UNKNOWN_PROTOCOL) { + aRv.ThrowTypeError(aBase.Value()); + return; + } + useProxy = true; + } + } + + // Let's see if we can parse aURI on this thread. + nsCOMPtr uri; + if (!useProxy) { + rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(aURL), nullptr, + baseURI); + if (NS_FAILED(rv)) { + if (rv != NS_ERROR_UNKNOWN_PROTOCOL) { + aRv.ThrowTypeError(aURL); + return; + } + useProxy = true; + } + } + + // Fallback by proxy. + if (useProxy) { + RefPtr runnable = + new ConstructorRunnable(mWorkerPrivate, aURL, aBase); + runnable->Dispatch(Canceling, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + uri = runnable->GetURI(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + } + + SetURI(uri.forget()); +} + +URLWorker::~URLWorker() = default; + +void URLWorker::SetHref(const nsAString& aHref, ErrorResult& aRv) { + nsAutoCString scheme; + nsresult rv = net_ExtractURLScheme(NS_ConvertUTF16toUTF8(aHref), scheme); + if (NS_FAILED(rv)) { + aRv.ThrowTypeError(aHref); + return; + } + + RefPtr runnable = + new ConstructorRunnable(mWorkerPrivate, aHref, Optional()); + runnable->Dispatch(Canceling, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + nsCOMPtr uri = runnable->GetURI(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + SetURI(uri.forget()); + UpdateURLSearchParams(); +} + +void URLWorker::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const { + nsresult rv = nsContentUtils::GetThreadSafeUTFOrigin(GetURI(), aOrigin); + if (rv == NS_ERROR_UNKNOWN_PROTOCOL) { + RefPtr runnable = + new OriginGetterRunnable(mWorkerPrivate, aOrigin, GetURI()); + + runnable->Dispatch(aRv); + return; + } + + if (NS_WARN_IF(NS_FAILED(rv))) { + aOrigin.Truncate(); + } +} + +void URLWorker::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) { + nsAString::const_iterator start, end; + aProtocol.BeginReading(start); + aProtocol.EndReading(end); + nsAString::const_iterator iter(start); + + FindCharInReadable(':', iter, end); + NS_ConvertUTF16toUTF8 scheme(Substring(start, iter)); + + RefPtr runnable = + new ProtocolSetterRunnable(mWorkerPrivate, scheme, GetURI()); + runnable->Dispatch(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + nsCOMPtr uri = runnable->GetRetval(); + if (NS_WARN_IF(!uri)) { + return; + } + + SetURI(uri.forget()); +} + } // namespace dom } // namespace mozilla diff --git a/dom/url/URLWorker.h b/dom/url/URLWorker.h index db17262243cf..7c2450789844 100644 --- a/dom/url/URLWorker.h +++ b/dom/url/URLWorker.h @@ -18,7 +18,10 @@ class nsStandardURL; namespace dom { -class URLWorker final { +class WorkerPrivate; + +// URLWorker implements the URL object in workers. +class URLWorker final : public URL { public: static already_AddRefed Constructor( const GlobalObject& aGlobal, const nsAString& aURL, @@ -37,6 +40,23 @@ class URLWorker final { static bool IsValidURL(const GlobalObject& aGlobal, const nsAString& aUrl, ErrorResult& aRv); + + explicit URLWorker(WorkerPrivate* aWorkerPrivate); + + void Init(const nsAString& aURL, const Optional& aBase, + ErrorResult& aRv); + + virtual void SetHref(const nsAString& aHref, ErrorResult& aRv) override; + + virtual void GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const override; + + virtual void SetProtocol(const nsAString& aProtocol, + ErrorResult& aRv) override; + + private: + ~URLWorker(); + + WorkerPrivate* mWorkerPrivate; }; } // namespace dom