diff --git a/browser/components/nsBrowserContentHandler.js b/browser/components/nsBrowserContentHandler.js index 358c4aea4f..e534e12069 100644 --- a/browser/components/nsBrowserContentHandler.js +++ b/browser/components/nsBrowserContentHandler.js @@ -707,7 +707,7 @@ nsDefaultCommandLineHandler.prototype = { } } - var URLlist = urilist.filter(shouldLoadURI).map(function (u) u.spec); + var URLlist = urilist.filter(shouldLoadURI).map(u => u.spec); if (URLlist.length) { openWindow(null, gBrowserContentHandler.chromeURL, "_blank", "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine), diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 1a051a92f1..c60083837c 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -4991,6 +4991,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, case NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION: case NS_ERROR_BAD_OPAQUE_REDIRECT_INTERCEPTION: case NS_ERROR_INTERCEPTION_CANCELED: + case NS_ERROR_REJECTED_RESPONSE_INTERCEPTION: // ServiceWorker intercepted request, but something went wrong. nsContentUtils::MaybeReportInterceptionErrorToConsole(GetDocument(), aError); @@ -7683,6 +7684,7 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress, aStatus == NS_ERROR_INTERCEPTED_USED_RESPONSE || aStatus == NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION || aStatus == NS_ERROR_INTERCEPTION_CANCELED || + aStatus == NS_ERROR_REJECTED_RESPONSE_INTERCEPTION || NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) { // Errors to be shown for any frame DisplayLoadError(aStatus, url, nullptr, aChannel); diff --git a/dom/base/DOMRequest.cpp b/dom/base/DOMRequest.cpp index d83fe54a24..a51cdce769 100644 --- a/dom/base/DOMRequest.cpp +++ b/dom/base/DOMRequest.cpp @@ -193,11 +193,7 @@ DOMRequest::FireEvent(const nsAString& aType, bool aBubble, bool aCancelable) } RefPtr event = NS_NewDOMEvent(this, nullptr, nullptr); - nsresult rv = event->InitEvent(aType, aBubble, aCancelable); - if (NS_FAILED(rv)) { - return; - } - + event->InitEvent(aType, aBubble, aCancelable); event->SetTrusted(true); bool dummy; diff --git a/dom/base/EventSource.cpp b/dom/base/EventSource.cpp index 8f68c3ce08..f287e74e5b 100644 --- a/dom/base/EventSource.cpp +++ b/dom/base/EventSource.cpp @@ -757,12 +757,7 @@ EventSource::AnnounceConnection() RefPtr event = NS_NewDOMEvent(this, nullptr, nullptr); // it doesn't bubble, and it isn't cancelable - rv = event->InitEvent(NS_LITERAL_STRING("open"), false, false); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to init the open event!!!"); - return; - } - + event->InitEvent(NS_LITERAL_STRING("open"), false, false); event->SetTrusted(true); rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr); @@ -813,12 +808,7 @@ EventSource::ReestablishConnection() RefPtr event = NS_NewDOMEvent(this, nullptr, nullptr); // it doesn't bubble, and it isn't cancelable - rv = event->InitEvent(NS_LITERAL_STRING("error"), false, false); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to init the error event!!!"); - return; - } - + event->InitEvent(NS_LITERAL_STRING("error"), false, false); event->SetTrusted(true); rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr); @@ -964,12 +954,7 @@ EventSource::FailConnection() RefPtr event = NS_NewDOMEvent(this, nullptr, nullptr); // it doesn't bubble, and it isn't cancelable - rv = event->InitEvent(NS_LITERAL_STRING("error"), false, false); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to init the error event!!!"); - return; - } - + event->InitEvent(NS_LITERAL_STRING("error"), false, false); event->SetTrusted(true); rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr); diff --git a/dom/base/WebSocket.cpp b/dom/base/WebSocket.cpp index 0319d5349c..7f1aaf1fb8 100644 --- a/dom/base/WebSocket.cpp +++ b/dom/base/WebSocket.cpp @@ -1809,9 +1809,7 @@ WebSocket::CreateAndDispatchSimpleEvent(const nsAString& aName) RefPtr event = NS_NewDOMEvent(this, nullptr, nullptr); // it doesn't bubble, and it isn't cancelable - rv = event->InitEvent(aName, false, false); - NS_ENSURE_SUCCESS(rv, rv); - + event->InitEvent(aName, false, false); event->SetTrusted(true); return DispatchDOMEvent(nullptr, event, nullptr, nullptr); diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 602cbe40f5..48801a14dc 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -3510,6 +3510,8 @@ nsContentUtils::MaybeReportInterceptionErrorToConsole(nsIDocument* aDocument, messageName = "BadOpaqueRedirectInterception"; } else if (aError == NS_ERROR_INTERCEPTION_CANCELED) { messageName = "InterceptionCanceled"; + } else if (aError == NS_ERROR_REJECTED_RESPONSE_INTERCEPTION) { + messageName = "InterceptionRejectedResponse"; } if (messageName) { @@ -3799,9 +3801,7 @@ nsresult GetEventAndTarget(nsIDocument* aDoc, nsISupports* aTarget, domDoc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event)); NS_ENSURE_SUCCESS(rv, rv); - rv = event->InitEvent(aEventName, aCanBubble, aCancelable); - NS_ENSURE_SUCCESS(rv, rv); - + event->InitEvent(aEventName, aCanBubble, aCancelable); event->SetTrusted(aTrusted); rv = event->SetTarget(target); diff --git a/dom/base/nsDOMDataChannel.cpp b/dom/base/nsDOMDataChannel.cpp index 69503c300f..c1b7c47652 100644 --- a/dom/base/nsDOMDataChannel.cpp +++ b/dom/base/nsDOMDataChannel.cpp @@ -456,9 +456,7 @@ nsDOMDataChannel::OnSimpleEvent(nsISupports* aContext, const nsAString& aName) RefPtr event = NS_NewDOMEvent(this, nullptr, nullptr); - rv = event->InitEvent(aName, false, false); - NS_ENSURE_SUCCESS(rv,rv); - + event->InitEvent(aName, false, false); event->SetTrusted(true); return DispatchDOMEvent(nullptr, event, nullptr, nullptr); diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index d9aab51c52..0503fa1f12 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -2198,7 +2198,7 @@ nsDOMWindowUtils::SuspendTimeouts() nsCOMPtr window = do_QueryReferent(mWindow); NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); - window->SuspendTimeouts(); + window->SuspendTimeouts(1, true, false); return NS_OK; } @@ -2211,7 +2211,7 @@ nsDOMWindowUtils::ResumeTimeouts() nsCOMPtr window = do_QueryReferent(mWindow); NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); - window->ResumeTimeouts(); + window->ResumeTimeouts(true, false); return NS_OK; } diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 32fed33520..24ca9c1aa2 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -11613,13 +11613,11 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic, } RefPtr event = NS_NewDOMEvent(this, nullptr, nullptr); - nsresult rv = event->InitEvent( + event->InitEvent( !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC) ? NETWORK_UPLOAD_EVENT_NAME : NETWORK_DOWNLOAD_EVENT_NAME, false, false); - NS_ENSURE_SUCCESS(rv, rv); - event->SetTrusted(true); bool dummy; @@ -11649,9 +11647,7 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic, } RefPtr event = NS_NewDOMEvent(this, nullptr, nullptr); - nsresult rv = event->InitEvent(NS_LITERAL_STRING("languagechange"), false, false); - NS_ENSURE_SUCCESS(rv, rv); - + event->InitEvent(NS_LITERAL_STRING("languagechange"), false, false); event->SetTrusted(true); bool dummy; @@ -13054,9 +13050,11 @@ nsGlobalWindow::RestoreWindowState(nsISupports *aState) void nsGlobalWindow::SuspendTimeouts(uint32_t aIncrease, - bool aFreezeChildren) + bool aFreezeChildren, + bool aFreezeWorkers) { - FORWARD_TO_INNER_VOID(SuspendTimeouts, (aIncrease, aFreezeChildren)); + FORWARD_TO_INNER_VOID(SuspendTimeouts, + (aIncrease, aFreezeChildren, aFreezeWorkers)); bool suspended = (mTimeoutsSuspendDepth != 0); mTimeoutsSuspendDepth += aIncrease; @@ -13069,8 +13067,12 @@ nsGlobalWindow::SuspendTimeouts(uint32_t aIncrease, } DisableGamepadUpdates(); - // Freeze all of the workers for this window. - mozilla::dom::workers::FreezeWorkersForWindow(this); + // Freeze or suspend all of the workers for this window. + if (aFreezeWorkers) { + mozilla::dom::workers::FreezeWorkersForWindow(this); + } else { + mozilla::dom::workers::SuspendWorkersForWindow(this); + } TimeStamp now = TimeStamp::Now(); for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) { @@ -13126,7 +13128,7 @@ nsGlobalWindow::SuspendTimeouts(uint32_t aIncrease, continue; } - win->SuspendTimeouts(aIncrease, aFreezeChildren); + win->SuspendTimeouts(aIncrease, aFreezeChildren, aFreezeWorkers); if (inner && aFreezeChildren) { inner->Freeze(); @@ -13137,9 +13139,10 @@ nsGlobalWindow::SuspendTimeouts(uint32_t aIncrease, } nsresult -nsGlobalWindow::ResumeTimeouts(bool aThawChildren) +nsGlobalWindow::ResumeTimeouts(bool aThawChildren, bool aThawWorkers) { - FORWARD_TO_INNER(ResumeTimeouts, (), NS_ERROR_NOT_INITIALIZED); + FORWARD_TO_INNER(ResumeTimeouts, (aThawChildren, aThawWorkers), + NS_ERROR_NOT_INITIALIZED); NS_ASSERTION(mTimeoutsSuspendDepth, "Mismatched calls to ResumeTimeouts!"); --mTimeoutsSuspendDepth; @@ -13157,11 +13160,15 @@ nsGlobalWindow::ResumeTimeouts(bool aThawChildren) // Resume all of the AudioContexts for this window for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) { ErrorResult dummy; - unused << mAudioContexts[i]->Resume(dummy); + RefPtr d = mAudioContexts[i]->Resume(dummy); } - // Thaw all of the workers for this window. - mozilla::dom::workers::ThawWorkersForWindow(this); + // Thaw or resume all of the workers for this window. + if (aThawWorkers) { + mozilla::dom::workers::ThawWorkersForWindow(this); + } else { + mozilla::dom::workers::ResumeWorkersForWindow(this); + } // Restore all of the timeouts, using the stored time remaining // (stored in timeout->mTimeRemaining). @@ -13240,7 +13247,7 @@ nsGlobalWindow::ResumeTimeouts(bool aThawChildren) inner->Thaw(); } - rv = win->ResumeTimeouts(aThawChildren); + rv = win->ResumeTimeouts(aThawChildren, aThawWorkers); NS_ENSURE_SUCCESS(rv, rv); } } diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 98b82013d5..dc0c398b9f 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -443,8 +443,10 @@ public: virtual already_AddRefed SaveWindowState() override; virtual nsresult RestoreWindowState(nsISupports *aState) override; virtual void SuspendTimeouts(uint32_t aIncrease = 1, - bool aFreezeChildren = true) override; - virtual nsresult ResumeTimeouts(bool aThawChildren = true) override; + bool aFreezeChildren = true, + bool aFreezeWorkers = true) override; + virtual nsresult ResumeTimeouts(bool aThawChildren = true, + bool aThawWorkers = true) override; virtual uint32_t TimeoutSuspendCount() override; virtual nsresult FireDelayedDOMEvents() override; virtual bool IsFrozen() const override diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index a7b41de507..4072946020 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -309,10 +309,12 @@ public: // Suspend timeouts in this window and in child windows. virtual void SuspendTimeouts(uint32_t aIncrease = 1, - bool aFreezeChildren = true) = 0; + bool aFreezeChildren = true, + bool aFreezeWorkers = true) = 0; // Resume suspended timeouts in this window and in child windows. - virtual nsresult ResumeTimeouts(bool aThawChildren = true) = 0; + virtual nsresult ResumeTimeouts(bool aThawChildren = true, + bool aThawWorkers = true) = 0; virtual uint32_t TimeoutSuspendCount() = 0; diff --git a/dom/base/nsPerformance.cpp b/dom/base/nsPerformance.cpp index 37d9eac91b..4129ff1c42 100644 --- a/dom/base/nsPerformance.cpp +++ b/dom/base/nsPerformance.cpp @@ -482,11 +482,7 @@ nsPerformance::DispatchBufferFullEvent() { RefPtr event = NS_NewDOMEvent(this, nullptr, nullptr); // it bubbles, and it isn't cancelable - nsresult rv = event->InitEvent(NS_LITERAL_STRING("resourcetimingbufferfull"), - true, false); - if (NS_FAILED(rv)) { - return; - } + event->InitEvent(NS_LITERAL_STRING("resourcetimingbufferfull"), true, false); event->SetTrusted(true); DispatchDOMEvent(nullptr, event, nullptr, nullptr); } diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index 5870c75461..734a83e582 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -10,6 +10,7 @@ #include "nsScriptLoader.h" +#include "prsystem.h" #include "jsapi.h" #include "jsfriendapi.h" #include "xpcpublic.h" @@ -113,6 +114,7 @@ nsScriptLoadRequestList::Contains(nsScriptLoadRequest* aElem) nsScriptLoader::nsScriptLoader(nsIDocument *aDocument) : mDocument(aDocument), mBlockerCount(0), + mNumberOfProcessors(0), mEnabled(true), mDeferEnabled(false), mDocumentParsingDone(false), @@ -273,30 +275,41 @@ nsScriptLoader::ShouldLoadScript(nsIDocument* aDocument, return NS_OK; } +class ContextMediator : public nsIStreamLoaderObserver +{ +public: + explicit ContextMediator(nsScriptLoader *aScriptLoader, nsISupports *aContext) + : mScriptLoader(aScriptLoader) + , mContext(aContext) {} + + NS_DECL_ISUPPORTS + NS_DECL_NSISTREAMLOADEROBSERVER + +private: + virtual ~ContextMediator() {} + RefPtr mScriptLoader; + nsCOMPtr mContext; +}; + +NS_IMPL_ISUPPORTS(ContextMediator, nsIStreamLoaderObserver) + +NS_IMETHODIMP +ContextMediator::OnStreamComplete(nsIStreamLoader* aLoader, + nsISupports* aContext, + nsresult aStatus, + uint32_t aStringLen, + const uint8_t* aString) +{ + // pass arguments through except for the aContext, + // we have to mediate and use mContext instead. + return mScriptLoader->OnStreamComplete(aLoader, mContext, aStatus, + aStringLen, aString); +} + nsresult nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, bool aScriptFromHead) { - nsISupports *context = aRequest->mElement.get() - ? static_cast(aRequest->mElement.get()) - : static_cast(mDocument); - nsresult rv = ShouldLoadScript(mDocument, context, aRequest->mURI, aType, aRequest->IsPreload()); - if (NS_FAILED(rv)) { - return rv; - } - - nsCOMPtr loadGroup = mDocument->GetDocumentLoadGroup(); - - nsCOMPtr window(do_QueryInterface(mDocument->MasterDocument()->GetWindow())); - - if (!window) { - return NS_ERROR_NULL_POINTER; - } - - nsIDocShell *docshell = window->GetDocShell(); - - nsCOMPtr prompter(do_QueryInterface(docshell)); - // If this document is sandboxed without 'allow-scripts', abort. if (mDocument->HasScriptsBlockedBySandbox()) { return NS_OK; @@ -305,17 +318,39 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, nsContentPolicyType contentPolicyType = aRequest->IsPreload() ? nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD : nsIContentPolicy::TYPE_INTERNAL_SCRIPT; + nsCOMPtr context; + if (aRequest->mElement) { + context = do_QueryInterface(aRequest->mElement); + } + else { + context = mDocument; + } + + nsCOMPtr loadGroup = mDocument->GetDocumentLoadGroup(); + nsCOMPtr window(do_QueryInterface(mDocument->MasterDocument()->GetWindow())); + NS_ENSURE_TRUE(window, NS_ERROR_NULL_POINTER); + nsIDocShell *docshell = window->GetDocShell(); + nsCOMPtr prompter(do_QueryInterface(docshell)); + + nsSecurityFlags securityFlags = + aRequest->mCORSMode == CORS_NONE + ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL + : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS; + if (aRequest->mCORSMode == CORS_USE_CREDENTIALS) { + securityFlags |= nsILoadInfo::SEC_REQUIRE_CORS_WITH_CREDENTIALS; + } + securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME; nsCOMPtr channel; - rv = NS_NewChannel(getter_AddRefs(channel), - aRequest->mURI, - mDocument, - nsILoadInfo::SEC_NORMAL, - contentPolicyType, - loadGroup, - prompter, - nsIRequest::LOAD_NORMAL | - nsIChannel::LOAD_CLASSIFY_URI); + nsresult rv = NS_NewChannel(getter_AddRefs(channel), + aRequest->mURI, + context, + securityFlags, + contentPolicyType, + loadGroup, + prompter, + nsIRequest::LOAD_NORMAL | + nsIChannel::LOAD_CLASSIFY_URI); NS_ENSURE_SUCCESS(rv, rv); @@ -354,26 +389,13 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, timedChannel->SetInitiatorType(NS_LITERAL_STRING("script")); } + RefPtr mediator = new ContextMediator(this, aRequest); + nsCOMPtr loader; - rv = NS_NewStreamLoader(getter_AddRefs(loader), this); + rv = NS_NewStreamLoader(getter_AddRefs(loader), mediator); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr listener = loader.get(); - - if (aRequest->mCORSMode != CORS_NONE) { - bool withCredentials = (aRequest->mCORSMode == CORS_USE_CREDENTIALS); - RefPtr corsListener = - new nsCORSListenerProxy(listener, mDocument->NodePrincipal(), - withCredentials); - rv = corsListener->Init(channel, DataURIHandling::Allow); - NS_ENSURE_SUCCESS(rv, rv); - listener = corsListener; - } - - rv = channel->AsyncOpen(listener, aRequest); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; + return channel->AsyncOpen2(loader); } bool @@ -561,7 +583,12 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) ourCORSMode == request->mCORSMode && ourRefPolicy == request->mReferrerPolicy) { rv = CheckContentPolicy(mDocument, aElement, request->mURI, type, false); - NS_ENSURE_SUCCESS(rv, false); + if (NS_FAILED(rv)) { + // probably plans have changed; even though the preload was allowed seems + // like the actual load is not; let's cancel the preload request. + request->Cancel(); + return false; + } } else { // Drop the preload request = nullptr; @@ -617,7 +644,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) // loop gets a chance to spin. // KVKV TODO: Instead of processing immediately, try off-thread-parsing - // it and only schedule a ProcessRequest if that fails. + // it and only schedule a pending ProcessRequest if that fails. ProcessPendingRequestsAsync(); } else { mLoadingAsyncRequests.AppendElement(request); @@ -666,6 +693,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) } return true; } + if (request->IsDoneLoading() && ReadyToExecuteScripts()) { // The request has already been loaded and there are no pending style // sheets. If the script comes from the network stream, cheat for @@ -684,6 +712,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) ProcessPendingRequestsAsync(); return true; } + // The script hasn't loaded yet or there's a style sheet blocking it. // The script will be run when it loads or the style sheet loads. NS_ASSERTION(!mParserBlockingRequest, @@ -782,6 +811,23 @@ nsScriptLoader::ProcessOffThreadRequest(nsScriptLoadRequest* aRequest) { MOZ_ASSERT(aRequest->mProgress == nsScriptLoadRequest::Progress_Compiling); aRequest->mProgress = nsScriptLoadRequest::Progress_DoneCompiling; + if (aRequest == mParserBlockingRequest) { + if (!ReadyToExecuteScripts()) { + // If not ready to execute scripts, schedule an async call to + // ProcessPendingRequests to handle it. + ProcessPendingRequestsAsync(); + return NS_OK; + } + + // Same logic as in top of ProcessPendingRequests. + mParserBlockingRequest = nullptr; + UnblockParser(aRequest); + ProcessRequest(aRequest); + mDocument->UnblockOnload(false); + ContinueParserAsync(aRequest); + return NS_OK; + } + nsresult rv = ProcessRequest(aRequest); mDocument->UnblockOnload(false); return rv; @@ -830,9 +876,10 @@ OffThreadScriptLoaderCallback(void *aToken, void *aCallbackData) } nsresult -nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest) +nsScriptLoader::AttemptAsyncScriptCompile(nsScriptLoadRequest* aRequest) { - if (!aRequest->mElement->GetScriptAsync() || aRequest->mIsInline) { + // Don't off-thread compile inline scripts. + if (aRequest->mIsInline) { return NS_ERROR_FAILURE; } @@ -873,7 +920,8 @@ nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest) } nsresult -nsScriptLoader::CompileOffThreadOrProcessRequest(nsScriptLoadRequest* aRequest) +nsScriptLoader::CompileOffThreadOrProcessRequest(nsScriptLoadRequest* aRequest, + bool* oCompiledOffThread) { NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "Processing requests when running scripts is unsafe."); @@ -882,8 +930,11 @@ nsScriptLoader::CompileOffThreadOrProcessRequest(nsScriptLoadRequest* aRequest) NS_ASSERTION(!aRequest->InCompilingStage(), "Candidate for off-thread compile is already in compiling stage."); - nsresult rv = AttemptAsyncScriptParse(aRequest); + nsresult rv = AttemptAsyncScriptCompile(aRequest); if (rv != NS_ERROR_FAILURE) { + if (oCompiledOffThread && rv == NS_OK) { + *oCompiledOffThread = true; + } return rv; } @@ -1174,8 +1225,12 @@ nsScriptLoader::ProcessPendingRequests() mParserBlockingRequest->IsReadyToRun() && ReadyToExecuteScripts()) { request.swap(mParserBlockingRequest); + bool offThreadCompiled = request->mProgress == nsScriptLoadRequest::Progress_DoneCompiling; UnblockParser(request); ProcessRequest(request); + if (offThreadCompiled) { + mDocument->UnblockOnload(false); + } ContinueParserAsync(request); } @@ -1487,6 +1542,18 @@ nsScriptLoader::ContinueParserAsync(nsScriptLoadRequest* aParserBlockingRequest) aParserBlockingRequest->mElement->ContinueParserAsync(); } +uint32_t +nsScriptLoader::NumberOfProcessors() +{ + if (mNumberOfProcessors > 0) + return mNumberOfProcessors; + + int32_t numProcs = PR_GetNumberOfProcessors(); + if (numProcs > 0) + mNumberOfProcessors = numProcs; + return mNumberOfProcessors; +} + nsresult nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest, nsIStreamLoader* aLoader, @@ -1575,6 +1642,23 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest, // Mark this as loaded aRequest->mProgress = nsScriptLoadRequest::Progress_DoneLoading; + // If this is currently blocking the parser, attempt to compile it off-main-thread. + if (aRequest == mParserBlockingRequest && (NumberOfProcessors() > 1)) { + nsresult rv = AttemptAsyncScriptCompile(aRequest); + if (rv == NS_OK) { + NS_ASSERTION(aRequest->mProgress == nsScriptLoadRequest::Progress_Compiling, + "Request should be off-thread compiling now."); + return NS_OK; + } + + // If off-thread compile errored, return the error. + if (rv != NS_ERROR_FAILURE) { + return rv; + } + + // If off-thread compile was rejected, continue with regular processing. + } + // And if it's async, move it to the loaded list. aRequest->mIsAsync really // _should_ be in a list, but the consequences if it's not are bad enough we // want to avoid trying to move it if it's not. diff --git a/dom/base/nsScriptLoader.h b/dom/base/nsScriptLoader.h index d530cfd61e..18ef6bc12f 100644 --- a/dom/base/nsScriptLoader.h +++ b/dom/base/nsScriptLoader.h @@ -470,9 +470,10 @@ private: return mEnabled && !mBlockerCount; } - nsresult AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest); + nsresult AttemptAsyncScriptCompile(nsScriptLoadRequest* aRequest); nsresult ProcessRequest(nsScriptLoadRequest* aRequest); - nsresult CompileOffThreadOrProcessRequest(nsScriptLoadRequest* aRequest); + nsresult CompileOffThreadOrProcessRequest(nsScriptLoadRequest* aRequest, + bool* oCompiledOffThread=nullptr); void FireScriptAvailable(nsresult aResult, nsScriptLoadRequest* aRequest); void FireScriptEvaluated(nsresult aResult, @@ -486,6 +487,7 @@ private: JS::Handle aScopeChain, JS::CompileOptions *aOptions); + uint32_t NumberOfProcessors(); nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest, nsIStreamLoader* aLoader, nsresult aStatus, @@ -529,6 +531,7 @@ private: // XXXbz do we want to cycle-collect these or something? Not sure. nsTArray< RefPtr > mPendingChildLoaders; uint32_t mBlockerCount; + uint32_t mNumberOfProcessors; bool mEnabled; bool mDeferEnabled; bool mDocumentParsingDone; diff --git a/dom/base/nsSyncLoadService.cpp b/dom/base/nsSyncLoadService.cpp index 2a67cac150..4cce905281 100644 --- a/dom/base/nsSyncLoadService.cpp +++ b/dom/base/nsSyncLoadService.cpp @@ -23,7 +23,6 @@ #include "nsNetUtil.h" #include "nsAutoPtr.h" #include "nsStreamUtils.h" -#include "nsCORSListenerProxy.h" #include using mozilla::net::ReferrerPolicy; @@ -42,7 +41,7 @@ public: NS_DECL_ISUPPORTS - nsresult LoadDocument(nsIChannel* aChannel, nsIPrincipal *aLoaderPrincipal, + nsresult LoadDocument(nsIChannel* aChannel, bool aChannelIsSync, bool aForceToXML, ReferrerPolicy aReferrerPolicy, nsIDOMDocument** aResult); @@ -130,29 +129,29 @@ NS_IMPL_ISUPPORTS(nsSyncLoader, nsresult nsSyncLoader::LoadDocument(nsIChannel* aChannel, - nsIPrincipal *aLoaderPrincipal, bool aChannelIsSync, bool aForceToXML, ReferrerPolicy aReferrerPolicy, nsIDOMDocument **aResult) { + NS_ENSURE_ARG(aChannel); NS_ENSURE_ARG_POINTER(aResult); *aResult = nullptr; nsresult rv = NS_OK; - nsCOMPtr loaderUri; - if (aLoaderPrincipal) { - aLoaderPrincipal->GetURI(getter_AddRefs(loaderUri)); - } - mChannel = aChannel; nsCOMPtr http = do_QueryInterface(mChannel); if (http) { http->SetRequestHeader(NS_LITERAL_CSTRING("Accept"), NS_LITERAL_CSTRING("text/xml,application/xml,application/xhtml+xml,*/*;q=0.1"), false); - if (loaderUri) { - http->SetReferrerWithPolicy(loaderUri, aReferrerPolicy); + nsCOMPtr loadInfo = aChannel->GetLoadInfo(); + if (loadInfo) { + nsCOMPtr loaderUri; + loadInfo->TriggeringPrincipal()->GetURI(getter_AddRefs(loaderUri)); + if (loaderUri) { + http->SetReferrerWithPolicy(loaderUri, aReferrerPolicy); + } } } @@ -186,14 +185,6 @@ nsSyncLoader::LoadDocument(nsIChannel* aChannel, listener.swap(forceListener); } - if (aLoaderPrincipal) { - RefPtr corsListener = - new nsCORSListenerProxy(listener, aLoaderPrincipal, false); - rv = corsListener->Init(mChannel, DataURIHandling::Disallow); - NS_ENSURE_SUCCESS(rv, rv); - listener = corsListener; - } - if (aChannelIsSync) { rv = PushSyncStream(listener); } @@ -226,7 +217,7 @@ nsSyncLoader::PushAsyncStream(nsIStreamListener* aListener) mAsyncLoadStatus = NS_OK; // Start reading from the channel - nsresult rv = mChannel->AsyncOpen(this, nullptr); + nsresult rv = mChannel->AsyncOpen2(this); if (NS_SUCCEEDED(rv)) { // process events until we're finished. @@ -254,7 +245,7 @@ nsresult nsSyncLoader::PushSyncStream(nsIStreamListener* aListener) { nsCOMPtr in; - nsresult rv = mChannel->Open(getter_AddRefs(in)); + nsresult rv = mChannel->Open2(getter_AddRefs(in)); NS_ENSURE_SUCCESS(rv, rv); mLoading = true; @@ -309,8 +300,12 @@ nsSyncLoader::GetInterface(const nsIID & aIID, /* static */ nsresult -nsSyncLoadService::LoadDocument(nsIURI *aURI, nsIPrincipal *aLoaderPrincipal, - nsILoadGroup *aLoadGroup, bool aForceToXML, +nsSyncLoadService::LoadDocument(nsIURI *aURI, + nsContentPolicyType aContentPolicyType, + nsIPrincipal *aLoaderPrincipal, + nsSecurityFlags aSecurityFlags, + nsILoadGroup *aLoadGroup, + bool aForceToXML, ReferrerPolicy aReferrerPolicy, nsIDOMDocument** aResult) { @@ -318,8 +313,8 @@ nsSyncLoadService::LoadDocument(nsIURI *aURI, nsIPrincipal *aLoaderPrincipal, nsresult rv = NS_NewChannel(getter_AddRefs(channel), aURI, aLoaderPrincipal, - nsILoadInfo::SEC_NORMAL, - nsIContentPolicy::TYPE_OTHER, + aSecurityFlags, + aContentPolicyType, aLoadGroup); NS_ENSURE_SUCCESS(rv, rv); @@ -328,15 +323,12 @@ nsSyncLoadService::LoadDocument(nsIURI *aURI, nsIPrincipal *aLoaderPrincipal, } bool isChrome = false, isResource = false; - bool isSync = (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && - isChrome) || - (NS_SUCCEEDED(aURI->SchemeIs("resource", &isResource)) && - isResource); - + bool isSync = + (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) || + (NS_SUCCEEDED(aURI->SchemeIs("resource", &isResource)) && isResource); RefPtr loader = new nsSyncLoader(); - return loader->LoadDocument(channel, aLoaderPrincipal, isSync, - aForceToXML, aReferrerPolicy, aResult); - + return loader->LoadDocument(channel, isSync, aForceToXML, + aReferrerPolicy, aResult); } /* static */ diff --git a/dom/base/nsSyncLoadService.h b/dom/base/nsSyncLoadService.h index 0a4a1643e4..b9297f8bcf 100644 --- a/dom/base/nsSyncLoadService.h +++ b/dom/base/nsSyncLoadService.h @@ -29,17 +29,22 @@ public: * Synchronously load the document from the specified URI. * * @param aURI URI to load the document from. + * @param aContentPolicyType contentPolicyType to be set on the channel * @param aLoaderPrincipal Principal of loading document. For security - * checks and referrer header. May be null if no - * security checks should be done. + * checks and referrer header. + * @param aSecurityFlags securityFlags to be set on the channel * @param aLoadGroup The loadgroup to use for loading the document. * @param aForceToXML Whether to parse the document as XML, regardless of * content type. * @param referrerPolicy Referrer policy. * @param aResult [out] The document loaded from the URI. */ - static nsresult LoadDocument(nsIURI *aURI, nsIPrincipal *aLoaderPrincipal, - nsILoadGroup *aLoadGroup, bool aForceToXML, + static nsresult LoadDocument(nsIURI *aURI, + nsContentPolicyType aContentPolicyType, + nsIPrincipal *aLoaderPrincipal, + nsSecurityFlags aSecurityFlags, + nsILoadGroup *aLoadGroup, + bool aForceToXML, mozilla::net::ReferrerPolicy aReferrerPolicy, nsIDOMDocument** aResult); diff --git a/dom/base/nsXMLHttpRequest.cpp b/dom/base/nsXMLHttpRequest.cpp index c0e5e78a31..f96364a921 100644 --- a/dom/base/nsXMLHttpRequest.cpp +++ b/dom/base/nsXMLHttpRequest.cpp @@ -2852,9 +2852,6 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable& aBody) AddLoadFlags(mChannel, nsIChannel::LOAD_EXPLICIT_CREDENTIALS); } - NS_ASSERTION(listener != this, - "Using an object as a listener that can't be exposed to JS"); - // When we are sync loading, we need to bypass the local cache when it would // otherwise block us waiting for exclusive access to the cache. If we don't // do this, then we could dead lock in some cases (see bug 309424). diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 10b182dc1f..dd7cefae92 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -485,12 +485,18 @@ DOMInterfaces = { 'nativeType': 'mozilla::dom::workers::ExtendableEvent', }, +'ExtendableMessageEvent': { + 'headerFile': 'mozilla/dom/ServiceWorkerEvents.h', + 'nativeType': 'mozilla::dom::workers::ExtendableMessageEvent', +}, + 'FetchEvent': { 'headerFile': 'ServiceWorkerEvents.h', 'nativeType': 'mozilla::dom::workers::FetchEvent', 'binaryNames': { 'request': 'request_' }, + 'implicitJSContext': [ 'respondWith' ], }, 'FileReader': { diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 452f80bc15..5febcf4aad 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -15994,7 +15994,7 @@ class CGEventMethod(CGNativeMember): self.args.insert(0, Argument("JSContext*", "aCx")) if not self.isInit: self.args.insert(0, Argument("const GlobalObject&", "aGlobal")) - self.args.append(Argument('ErrorResult&', 'aRv')) + self.args.append(Argument('ErrorResult&', 'aRv')) return constructorForNativeCaller + CGNativeMember.declare(self, cgClass) def defineInit(self, cgClass): @@ -16016,11 +16016,7 @@ class CGEventMethod(CGNativeMember): self.body = fill( """ - nsresult rv = InitEvent(${typeArg}, ${bubblesArg}, ${cancelableArg}); - if (NS_FAILED(rv)) { - aRv.Throw(rv); - return; - } + InitEvent(${typeArg}, ${bubblesArg}, ${cancelableArg}); ${members} """, typeArg=self.args[0].name, @@ -16028,8 +16024,6 @@ class CGEventMethod(CGNativeMember): cancelableArg=self.args[2].name, members=members) - self.args.append(Argument('ErrorResult&', 'aRv')) - return CGNativeMember.define(self, cgClass) def define(self, cgClass): diff --git a/dom/events/AnimationEvent.cpp b/dom/events/AnimationEvent.cpp index b5bc314c44..0a46606716 100644 --- a/dom/events/AnimationEvent.cpp +++ b/dom/events/AnimationEvent.cpp @@ -44,7 +44,7 @@ AnimationEvent::Constructor(const GlobalObject& aGlobal, RefPtr e = new AnimationEvent(t, nullptr, nullptr); bool trusted = e->Init(t); - aRv = e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); + e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); InternalAnimationEvent* internalEvent = e->mEvent->AsAnimationEvent(); internalEvent->animationName = aParam.mAnimationName; diff --git a/dom/events/AsyncEventDispatcher.cpp b/dom/events/AsyncEventDispatcher.cpp index a83b510a60..b885fff6c3 100644 --- a/dom/events/AsyncEventDispatcher.cpp +++ b/dom/events/AsyncEventDispatcher.cpp @@ -42,8 +42,7 @@ AsyncEventDispatcher::Run() RefPtr event = mEvent ? mEvent->InternalDOMEvent() : nullptr; if (!event) { event = NS_NewDOMEvent(mTarget, nullptr, nullptr); - nsresult rv = event->InitEvent(mEventType, mBubbles, false); - NS_ENSURE_SUCCESS(rv, rv); + event->InitEvent(mEventType, mBubbles, false); event->SetTrusted(true); } if (mOnlyChromeDispatch) { diff --git a/dom/events/ClipboardEvent.cpp b/dom/events/ClipboardEvent.cpp index fbbdb9d672..0be2008fc6 100644 --- a/dom/events/ClipboardEvent.cpp +++ b/dom/events/ClipboardEvent.cpp @@ -43,7 +43,7 @@ ClipboardEvent::InitClipboardEvent(const nsAString& aType, // Null clipboardData is OK ErrorResult rv; - InitClipboardEvent(aType, aCanBubble, aCancelable, clipboardData, rv); + InitClipboardEvent(aType, aCanBubble, aCancelable, clipboardData); return rv.StealNSResult(); } @@ -51,14 +51,9 @@ ClipboardEvent::InitClipboardEvent(const nsAString& aType, void ClipboardEvent::InitClipboardEvent(const nsAString& aType, bool aCanBubble, bool aCancelable, - DataTransfer* aClipboardData, - ErrorResult& aError) + DataTransfer* aClipboardData) { - aError = Event::InitEvent(aType, aCanBubble, aCancelable); - if (aError.Failed()) { - return; - } - + Event::InitEvent(aType, aCanBubble, aCancelable); mEvent->AsClipboardEvent()->clipboardData = aClipboardData; } @@ -85,7 +80,7 @@ ClipboardEvent::Constructor(const GlobalObject& aGlobal, } e->InitClipboardEvent(aType, aParam.mBubbles, aParam.mCancelable, - clipboardData, aRv); + clipboardData); e->SetTrusted(trusted); return e.forget(); } diff --git a/dom/events/ClipboardEvent.h b/dom/events/ClipboardEvent.h index 563cbae18a..c3dcde8f20 100644 --- a/dom/events/ClipboardEvent.h +++ b/dom/events/ClipboardEvent.h @@ -46,8 +46,7 @@ public: void InitClipboardEvent(const nsAString& aType, bool aCanBubble, bool aCancelable, - DataTransfer* aClipboardData, - ErrorResult& aError); + DataTransfer* aClipboardData); protected: ~ClipboardEvent() {} diff --git a/dom/events/CommandEvent.cpp b/dom/events/CommandEvent.cpp index a337f4457d..5248a2629a 100644 --- a/dom/events/CommandEvent.cpp +++ b/dom/events/CommandEvent.cpp @@ -51,8 +51,7 @@ CommandEvent::InitCommandEvent(const nsAString& aTypeArg, bool aCancelableArg, const nsAString& aCommand) { - nsresult rv = Event::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg); - NS_ENSURE_SUCCESS(rv, rv); + Event::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg); mEvent->AsCommandEvent()->command = do_GetAtom(aCommand); return NS_OK; diff --git a/dom/events/CustomEvent.cpp b/dom/events/CustomEvent.cpp index 1bb2082b35..0094b4124a 100644 --- a/dom/events/CustomEvent.cpp +++ b/dom/events/CustomEvent.cpp @@ -66,8 +66,7 @@ CustomEvent::InitCustomEvent(const nsAString& aType, bool aCancelable, nsIVariant* aDetail) { - nsresult rv = Event::InitEvent(aType, aCanBubble, aCancelable); - NS_ENSURE_SUCCESS(rv, rv); + Event::InitEvent(aType, aCanBubble, aCancelable); mDetail = aDetail; return NS_OK; } @@ -89,7 +88,7 @@ CustomEvent::InitCustomEvent(JSContext* aCx, aRv.Throw(NS_ERROR_FAILURE); return; } - aRv = InitCustomEvent(aType, aCanBubble, aCancelable, detail); + InitCustomEvent(aType, aCanBubble, aCancelable, detail); } NS_IMETHODIMP diff --git a/dom/events/DOMEventTargetHelper.cpp b/dom/events/DOMEventTargetHelper.cpp index a6be0c2841..30e33e58aa 100644 --- a/dom/events/DOMEventTargetHelper.cpp +++ b/dom/events/DOMEventTargetHelper.cpp @@ -263,8 +263,7 @@ nsresult DOMEventTargetHelper::DispatchTrustedEvent(const nsAString& aEventName) { RefPtr event = NS_NewDOMEvent(this, nullptr, nullptr); - nsresult rv = event->InitEvent(aEventName, false, false); - NS_ENSURE_SUCCESS(rv, rv); + event->InitEvent(aEventName, false, false); return DispatchTrustedEvent(event); } diff --git a/dom/events/DeviceMotionEvent.cpp b/dom/events/DeviceMotionEvent.cpp index 833f46ac7e..b78241ef09 100644 --- a/dom/events/DeviceMotionEvent.cpp +++ b/dom/events/DeviceMotionEvent.cpp @@ -33,13 +33,9 @@ DeviceMotionEvent::InitDeviceMotionEvent( const DeviceAccelerationInit& aAcceleration, const DeviceAccelerationInit& aAccelIncludingGravity, const DeviceRotationRateInit& aRotationRate, - Nullable aInterval, - ErrorResult& aRv) + Nullable aInterval) { - aRv = Event::InitEvent(aType, aCanBubble, aCancelable); - if (aRv.Failed()) { - return; - } + Event::InitEvent(aType, aCanBubble, aCancelable); mAcceleration = new DeviceAcceleration(this, aAcceleration.mX, aAcceleration.mY, @@ -64,10 +60,7 @@ DeviceMotionEvent::Constructor(const GlobalObject& aGlobal, { nsCOMPtr t = do_QueryInterface(aGlobal.GetAsSupports()); RefPtr e = new DeviceMotionEvent(t, nullptr, nullptr); - aRv = e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable); - if (aRv.Failed()) { - return nullptr; - } + e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable); bool trusted = e->Init(t); e->mAcceleration = new DeviceAcceleration(e, diff --git a/dom/events/DeviceMotionEvent.h b/dom/events/DeviceMotionEvent.h index 246f510132..ca631787d8 100644 --- a/dom/events/DeviceMotionEvent.h +++ b/dom/events/DeviceMotionEvent.h @@ -128,8 +128,7 @@ public: const DeviceAccelerationInit& aAcceleration, const DeviceAccelerationInit& aAccelerationIncludingGravity, const DeviceRotationRateInit& aRotationRate, - Nullable aInterval, - ErrorResult& aRv); + Nullable aInterval); static already_AddRefed Constructor(const GlobalObject& aGlobal, diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index db043dfb17..ea9a8c373e 100644 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -414,7 +414,7 @@ Event::Constructor(const GlobalObject& aGlobal, nsCOMPtr t = do_QueryInterface(aGlobal.GetAsSupports()); RefPtr e = new Event(t, nullptr, nullptr); bool trusted = e->Init(t); - aRv = e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); + e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); e->SetTrusted(trusted); return e.forget(); } @@ -572,13 +572,13 @@ Event::SetEventType(const nsAString& aEventTypeArg) } } -NS_IMETHODIMP +void Event::InitEvent(const nsAString& aEventTypeArg, bool aCanBubbleArg, bool aCancelableArg) { // Make sure this event isn't already being dispatched. - NS_ENSURE_TRUE(!mEvent->mFlags.mIsBeingDispatched, NS_OK); + NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched); if (IsTrusted()) { // Ensure the caller is permitted to dispatch trusted DOM events. @@ -600,7 +600,6 @@ Event::InitEvent(const nsAString& aEventTypeArg, // re-dispatching it. mEvent->target = nullptr; mEvent->originalTarget = nullptr; - return NS_OK; } NS_IMETHODIMP @@ -1195,8 +1194,7 @@ Event::Deserialize(const IPC::Message* aMsg, void** aIter) bool trusted = false; NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &trusted), false); - nsresult rv = InitEvent(type, bubbles, cancelable); - NS_ENSURE_SUCCESS(rv, false); + InitEvent(type, bubbles, cancelable); SetTrusted(trusted); return true; diff --git a/dom/events/Event.h b/dom/events/Event.h index 4644bd5b3c..65e03c7315 100644 --- a/dom/events/Event.h +++ b/dom/events/Event.h @@ -211,12 +211,6 @@ public: double TimeStamp() const; - void InitEvent(const nsAString& aType, bool aBubbles, bool aCancelable, - ErrorResult& aRv) - { - aRv = InitEvent(aType, aBubbles, aCancelable); - } - EventTarget* GetOriginalTarget() const; EventTarget* GetExplicitOriginalTarget() const; EventTarget* GetComposedTarget() const; @@ -316,7 +310,7 @@ private: NS_IMETHOD StopPropagation(void) override { return _to StopPropagation(); } \ NS_IMETHOD StopCrossProcessForwarding(void) override { return _to StopCrossProcessForwarding(); } \ NS_IMETHOD PreventDefault(void) override { return _to PreventDefault(); } \ - NS_IMETHOD InitEvent(const nsAString& eventTypeArg, bool canBubbleArg, bool cancelableArg) override { return _to InitEvent(eventTypeArg, canBubbleArg, cancelableArg); } \ + void InitEvent(const nsAString& eventTypeArg, bool canBubbleArg, bool cancelableArg) override { _to InitEvent(eventTypeArg, canBubbleArg, cancelableArg); } \ NS_IMETHOD GetDefaultPrevented(bool* aDefaultPrevented) override { return _to GetDefaultPrevented(aDefaultPrevented); } \ NS_IMETHOD StopImmediatePropagation(void) override { return _to StopImmediatePropagation(); } \ NS_IMETHOD GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget) override { return _to GetOriginalTarget(aOriginalTarget); } \ diff --git a/dom/events/MessageEvent.cpp b/dom/events/MessageEvent.cpp index b0e67a6c49..dbf56837e0 100644 --- a/dom/events/MessageEvent.cpp +++ b/dom/events/MessageEvent.cpp @@ -14,9 +14,6 @@ #include "jsapi.h" #include "nsGlobalWindow.h" // So we can assign an nsGlobalWindow* to mWindowSource -#include "ServiceWorker.h" -#include "ServiceWorkerClient.h" - namespace mozilla { namespace dom { @@ -107,14 +104,12 @@ MessageEvent::GetSource(nsIDOMWindow** aSource) } void -MessageEvent::GetSource(Nullable& aValue) const +MessageEvent::GetSource(Nullable& aValue) const { if (mWindowSource) { aValue.SetValue().SetAsWindowProxy() = mWindowSource; } else if (mPortSource) { aValue.SetValue().SetAsMessagePort() = mPortSource; - } else if (mClientSource) { - aValue.SetValue().SetAsClient() = mClientSource; } } @@ -136,11 +131,7 @@ MessageEvent::Constructor(EventTarget* aEventTarget, { RefPtr event = new MessageEvent(aEventTarget, nullptr, nullptr); - aRv = event->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); - if (aRv.Failed()) { - return nullptr; - } - + event->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); bool trusted = event->Init(aEventTarget); event->SetTrusted(trusted); @@ -187,9 +178,7 @@ MessageEvent::InitMessageEvent(const nsAString& aType, const nsAString& aLastEventId, nsIDOMWindow* aSource) { - nsresult rv = Event::InitEvent(aType, aCanBubble, aCancelable); - NS_ENSURE_SUCCESS(rv, rv); - + Event::InitEvent(aType, aCanBubble, aCancelable); mData = aData; mozilla::HoldJSObjects(this); mOrigin = aOrigin; @@ -199,6 +188,44 @@ MessageEvent::InitMessageEvent(const nsAString& aType, return NS_OK; } +void +MessageEvent::InitMessageEvent(JSContext* aCx, const nsAString& aType, + bool aCanBubble, bool aCancelable, + JS::Handle aData, + const nsAString& aOrigin, + const nsAString& aLastEventId, + const Nullable& aSource, + const Nullable>>& aPorts) +{ + Event::InitEvent(aType, aCanBubble, aCancelable); + mData = aData; + mozilla::HoldJSObjects(this); + mOrigin = aOrigin; + mLastEventId = aLastEventId; + + mWindowSource = nullptr; + mPortSource = nullptr; + + if (!aSource.IsNull()) { + if (aSource.Value().IsWindowProxy()) { + mWindowSource = aSource.Value().GetAsWindowProxy(); + } else { + mPortSource = &aSource.Value().GetAsMessagePort(); + } + } + + mPorts = nullptr; + + if (!aPorts.IsNull()) { + nsTArray> ports; + for (uint32_t i = 0, len = aPorts.Value().Length(); i < len; ++i) { + ports.AppendElement(aPorts.Value()[i]); + } + + mPorts = new MessagePortList(static_cast(this), ports); + } +} + void MessageEvent::SetPorts(MessagePortList* aPorts) { @@ -212,12 +239,6 @@ MessageEvent::SetSource(mozilla::dom::MessagePort* aPort) mPortSource = aPort; } -void -MessageEvent::SetSource(mozilla::dom::workers::ServiceWorkerClient* aClient) -{ - mClientSource = aClient; -} - } // namespace dom } // namespace mozilla @@ -227,7 +248,7 @@ using namespace mozilla::dom; already_AddRefed NS_NewDOMMessageEvent(EventTarget* aOwner, nsPresContext* aPresContext, - WidgetEvent* aEvent) + WidgetEvent* aEvent) { RefPtr it = new MessageEvent(aOwner, aPresContext, aEvent); return it.forget(); diff --git a/dom/events/MessageEvent.h b/dom/events/MessageEvent.h index fe0eb8b86e..76aca3ea23 100644 --- a/dom/events/MessageEvent.h +++ b/dom/events/MessageEvent.h @@ -8,9 +8,10 @@ #define mozilla_dom_MessageEvent_h_ #include "mozilla/dom/Event.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/MessagePortList.h" #include "nsCycleCollectionParticipant.h" #include "nsIDOMMessageEvent.h" -#include "mozilla/dom/MessagePortList.h" namespace mozilla { namespace dom { @@ -18,13 +19,8 @@ namespace dom { struct MessageEventInit; class MessagePort; class MessagePortList; -class OwningWindowProxyOrMessagePortOrClient; - -namespace workers { - -class ServiceWorkerClient; - -} // namespace workers +class OwningWindowProxyOrMessagePort; +class WindowProxyOrMessagePort; /** * Implements the MessageEvent event, used for cross-document messaging and @@ -54,7 +50,7 @@ public: void GetData(JSContext* aCx, JS::MutableHandle aData, ErrorResult& aRv); - void GetSource(Nullable& aValue) const; + void GetSource(Nullable& aValue) const; MessagePortList* GetPorts() { @@ -66,8 +62,6 @@ public: // Non WebIDL methods void SetSource(mozilla::dom::MessagePort* aPort); - void SetSource(workers::ServiceWorkerClient* aClient); - void SetSource(nsPIDOMWindow* aWindow) { mWindowSource = aWindow; @@ -85,6 +79,12 @@ public: const MessageEventInit& aEventInit, ErrorResult& aRv); + void InitMessageEvent(JSContext* aCx, const nsAString& aType, bool aCanBubble, + bool aCancelable, JS::Handle aData, + const nsAString& aOrigin, const nsAString& aLastEventId, + const Nullable& aSource, + const Nullable>>& aPorts); + protected: ~MessageEvent(); @@ -94,7 +94,6 @@ private: nsString mLastEventId; nsCOMPtr mWindowSource; RefPtr mPortSource; - RefPtr mClientSource; RefPtr mPorts; }; diff --git a/dom/events/MutationEvent.cpp b/dom/events/MutationEvent.cpp index 81fa75d455..8020d4978f 100644 --- a/dom/events/MutationEvent.cpp +++ b/dom/events/MutationEvent.cpp @@ -96,8 +96,7 @@ MutationEvent::InitMutationEvent(const nsAString& aTypeArg, const nsAString& aAttrNameArg, uint16_t aAttrChangeArg) { - nsresult rv = Event::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg); - NS_ENSURE_SUCCESS(rv, rv); + Event::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg); InternalMutationEvent* mutation = mEvent->AsMutationEvent(); mutation->mRelatedNode = aRelatedNodeArg; diff --git a/dom/events/SpeechRecognitionError.cpp b/dom/events/SpeechRecognitionError.cpp index a8d9a0faa8..f1b54acccd 100644 --- a/dom/events/SpeechRecognitionError.cpp +++ b/dom/events/SpeechRecognitionError.cpp @@ -29,7 +29,7 @@ SpeechRecognitionError::Constructor(const GlobalObject& aGlobal, nsCOMPtr t = do_QueryInterface(aGlobal.GetAsSupports()); RefPtr e = new SpeechRecognitionError(t, nullptr, nullptr); bool trusted = e->Init(t); - e->InitSpeechRecognitionError(aType, aParam.mBubbles, aParam.mCancelable, aParam.mError, aParam.mMessage, aRv); + e->InitSpeechRecognitionError(aType, aParam.mBubbles, aParam.mCancelable, aParam.mError, aParam.mMessage); e->SetTrusted(trusted); return e.forget(); } @@ -39,15 +39,11 @@ SpeechRecognitionError::InitSpeechRecognitionError(const nsAString& aType, bool aCanBubble, bool aCancelable, SpeechRecognitionErrorCode aError, - const nsAString& aMessage, - ErrorResult& aRv) + const nsAString& aMessage) { - aRv = Event::InitEvent(aType, aCanBubble, aCancelable); - NS_ENSURE_TRUE_VOID(!aRv.Failed()); - + Event::InitEvent(aType, aCanBubble, aCancelable); mError = aError; mMessage = aMessage; - return; } } // namespace dom diff --git a/dom/events/SpeechRecognitionError.h b/dom/events/SpeechRecognitionError.h index 7035900f04..ef43feffd1 100644 --- a/dom/events/SpeechRecognitionError.h +++ b/dom/events/SpeechRecognitionError.h @@ -49,8 +49,7 @@ public: bool aCanBubble, bool aCancelable, SpeechRecognitionErrorCode aError, - const nsAString& aMessage, - ErrorResult& aRv); + const nsAString& aMessage); protected: SpeechRecognitionErrorCode mError; diff --git a/dom/events/StorageEvent.cpp b/dom/events/StorageEvent.cpp index 4e0dabcf5c..ab79e06b09 100644 --- a/dom/events/StorageEvent.cpp +++ b/dom/events/StorageEvent.cpp @@ -85,14 +85,9 @@ StorageEvent::InitStorageEvent(const nsAString& aType, bool aCanBubble, const nsAString& aOldValue, const nsAString& aNewValue, const nsAString& aURL, - DOMStorage* aStorageArea, - ErrorResult& aRv) + DOMStorage* aStorageArea) { - aRv = InitEvent(aType, aCanBubble, aCancelable); - if (aRv.Failed()) { - return; - } - + InitEvent(aType, aCanBubble, aCancelable); mKey = aKey; mOldValue = aOldValue; mNewValue = aNewValue; diff --git a/dom/events/StorageEvent.h b/dom/events/StorageEvent.h index a46827bb69..39a107b939 100644 --- a/dom/events/StorageEvent.h +++ b/dom/events/StorageEvent.h @@ -57,8 +57,7 @@ public: const nsAString& aOldValue, const nsAString& aNewValue, const nsAString& aURL, - DOMStorage* aStorageArea, - ErrorResult& aRv); + DOMStorage* aStorageArea); void GetKey(nsString& aRetVal) const { diff --git a/dom/events/TouchEvent.cpp b/dom/events/TouchEvent.cpp index db08879f86..38b184a876 100644 --- a/dom/events/TouchEvent.cpp +++ b/dom/events/TouchEvent.cpp @@ -102,14 +102,9 @@ TouchEvent::InitTouchEvent(const nsAString& aType, bool aMetaKey, TouchList* aTouches, TouchList* aTargetTouches, - TouchList* aChangedTouches, - ErrorResult& aRv) + TouchList* aChangedTouches) { - aRv = UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail); - if (aRv.Failed()) { - return; - } - + UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail); mEvent->AsInputEvent()->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey); mTouches = aTouches; diff --git a/dom/events/TouchEvent.h b/dom/events/TouchEvent.h index 457a92a398..58e54f4284 100644 --- a/dom/events/TouchEvent.h +++ b/dom/events/TouchEvent.h @@ -115,8 +115,7 @@ public: bool aMetaKey, TouchList* aTouches, TouchList* aTargetTouches, - TouchList* aChangedTouches, - ErrorResult& aRv); + TouchList* aChangedTouches); static bool PrefEnabled(JSContext* aCx = nullptr, JSObject* aGlobal = nullptr); diff --git a/dom/events/TransitionEvent.cpp b/dom/events/TransitionEvent.cpp index a0ee4df1fa..590f57d366 100644 --- a/dom/events/TransitionEvent.cpp +++ b/dom/events/TransitionEvent.cpp @@ -44,7 +44,7 @@ TransitionEvent::Constructor(const GlobalObject& aGlobal, RefPtr e = new TransitionEvent(t, nullptr, nullptr); bool trusted = e->Init(t); - aRv = e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); + e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); InternalTransitionEvent* internalEvent = e->mEvent->AsTransitionEvent(); internalEvent->propertyName = aParam.mPropertyName; diff --git a/dom/events/UIEvent.cpp b/dom/events/UIEvent.cpp index 4968d73538..66877f5dfb 100644 --- a/dom/events/UIEvent.cpp +++ b/dom/events/UIEvent.cpp @@ -161,9 +161,7 @@ UIEvent::InitUIEvent(const nsAString& typeArg, nsCOMPtr view = do_QueryInterface(viewArg); NS_ENSURE_TRUE(view, NS_ERROR_INVALID_ARG); } - nsresult rv = Event::InitEvent(typeArg, canBubbleArg, cancelableArg); - NS_ENSURE_SUCCESS(rv, rv); - + Event::InitEvent(typeArg, canBubbleArg, cancelableArg); mDetail = detailArg; mView = viewArg; diff --git a/dom/events/test/test_messageEvent.html b/dom/events/test/test_messageEvent.html index b08a7d1ee1..8cabd7ffe4 100644 --- a/dom/events/test/test_messageEvent.html +++ b/dom/events/test/test_messageEvent.html @@ -13,6 +13,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=848294 + + + + +Mozilla Bug 1185544 +

+ +
+
+ + + + diff --git a/dom/push/test/test_serviceworker_lifetime.html b/dom/push/test/test_serviceworker_lifetime.html new file mode 100644 index 0000000000..233df55605 --- /dev/null +++ b/dom/push/test/test_serviceworker_lifetime.html @@ -0,0 +1,331 @@ + + + + + Test for Bug 1188545 + + + + +Mozilla Bug 118845 +

+ +
+
+ + + + diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index 44d26b7882..7f3c2f0001 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -10,7 +10,7 @@ NS_IMPL_ISUPPORTS(nsContentSecurityManager, nsIContentSecurityManager) -nsresult +static nsresult ValidateSecurityFlags(nsILoadInfo* aLoadInfo) { nsSecurityFlags securityMode = aLoadInfo->GetSecurityMode(); @@ -43,7 +43,7 @@ static bool SchemeIs(nsIURI* aURI, const char* aScheme) return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme; } -nsresult +static nsresult DoCheckLoadURIChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) { nsresult rv = NS_OK; @@ -73,11 +73,23 @@ DoCheckLoadURIChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) return NS_OK; } -nsresult +static bool +URIHasFlags(nsIURI* aURI, uint32_t aURIFlags) +{ + bool hasFlags; + nsresult rv = NS_URIChainHasFlags(aURI, aURIFlags, &hasFlags); + NS_ENSURE_SUCCESS(rv, false); + + return hasFlags; +} + +static nsresult DoSOPChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) { - if (aLoadInfo->GetAllowChrome() && SchemeIs(aURI, "chrome")) { - // Enforce same-origin policy, except to chrome. + if (aLoadInfo->GetAllowChrome() && + (URIHasFlags(aURI, nsIProtocolHandler::URI_IS_UI_RESOURCE) || + SchemeIs(aURI, "moz-safe-about"))) { + // UI resources are allowed. return DoCheckLoadURIChecks(aURI, aLoadInfo); } @@ -96,11 +108,11 @@ DoSOPChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) sameOriginDataInherits); } -nsresult +static nsresult DoCORSChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo, nsCOMPtr& aInAndOutListener) { - MOZ_ASSERT(aInAndOutListener, "can not perform CORS checks without a listener"); + MOZ_RELEASE_ASSERT(aInAndOutListener, "can not perform CORS checks without a listener"); // No need to set up CORS if TriggeringPrincipal is the SystemPrincipal. // For example, allow user stylesheets to load XBL from external files @@ -123,7 +135,7 @@ DoCORSChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo, return NS_OK; } -nsresult +static nsresult DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) { nsContentPolicyType contentPolicyType = @@ -285,7 +297,7 @@ DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) } int16_t shouldLoad = nsIContentPolicy::ACCEPT; - nsresult rv = NS_CheckContentLoadPolicy(contentPolicyType, + nsresult rv = NS_CheckContentLoadPolicy(internalContentPolicyType, aURI, aLoadInfo->LoadingPrincipal(), requestingContext, diff --git a/dom/smil/TimeEvent.cpp b/dom/smil/TimeEvent.cpp index d31fa424dd..a824b9a950 100644 --- a/dom/smil/TimeEvent.cpp +++ b/dom/smil/TimeEvent.cpp @@ -64,9 +64,8 @@ TimeEvent::InitTimeEvent(const nsAString& aTypeArg, nsIDOMWindow* aViewArg, int32_t aDetailArg) { - nsresult rv = Event::InitEvent(aTypeArg, false /*doesn't bubble*/, - false /*can't cancel*/); - NS_ENSURE_SUCCESS(rv, rv); + Event::InitEvent(aTypeArg, false /*doesn't bubble*/, + false /*can't cancel*/); mDetail = aDetailArg; mView = aViewArg; diff --git a/dom/smil/TimeEvent.h b/dom/smil/TimeEvent.h index be41de026b..1a52bacc5b 100644 --- a/dom/smil/TimeEvent.h +++ b/dom/smil/TimeEvent.h @@ -47,12 +47,6 @@ public: return mView; } - void InitTimeEvent(const nsAString& aType, nsIDOMWindow* aView, - int32_t aDetail, ErrorResult& aRv) - { - aRv = InitTimeEvent(aType, aView, aDetail); - } - private: ~TimeEvent() {} diff --git a/dom/system/nsDeviceSensors.cpp b/dom/system/nsDeviceSensors.cpp index 801f915ad5..733e6c13fb 100644 --- a/dom/system/nsDeviceSensors.cpp +++ b/dom/system/nsDeviceSensors.cpp @@ -390,15 +390,13 @@ nsDeviceSensors::FireDOMMotionEvent(nsIDOMDocument *domdoc, DeviceMotionEvent* me = static_cast(event.get()); - ErrorResult rv; me->InitDeviceMotionEvent(NS_LITERAL_STRING("devicemotion"), true, false, *mLastAcceleration, *mLastAccelerationIncludingGravity, *mLastRotationRate, - Nullable(DEFAULT_SENSOR_POLL), - rv); + Nullable(DEFAULT_SENSOR_POLL)); event->SetTrusted(true); diff --git a/dom/webidl/CompositionEvent.webidl b/dom/webidl/CompositionEvent.webidl index 9a059f8c75..23b3932917 100644 --- a/dom/webidl/CompositionEvent.webidl +++ b/dom/webidl/CompositionEvent.webidl @@ -17,7 +17,6 @@ interface CompositionEvent : UIEvent partial interface CompositionEvent { - [Throws] void initCompositionEvent(DOMString typeArg, boolean canBubbleArg, boolean cancelableArg, diff --git a/dom/webidl/DeviceMotionEvent.webidl b/dom/webidl/DeviceMotionEvent.webidl index a1d7bc04bf..fa4ecf3ca3 100644 --- a/dom/webidl/DeviceMotionEvent.webidl +++ b/dom/webidl/DeviceMotionEvent.webidl @@ -47,7 +47,6 @@ dictionary DeviceMotionEventInit : EventInit { // Mozilla extensions. partial interface DeviceMotionEvent { - [Throws] void initDeviceMotionEvent(DOMString type, boolean canBubble, boolean cancelable, diff --git a/dom/webidl/DeviceOrientationEvent.webidl b/dom/webidl/DeviceOrientationEvent.webidl index 3cd053b66f..46194453eb 100644 --- a/dom/webidl/DeviceOrientationEvent.webidl +++ b/dom/webidl/DeviceOrientationEvent.webidl @@ -13,7 +13,6 @@ interface DeviceOrientationEvent : Event readonly attribute boolean absolute; // initDeviceOrientationEvent is a Gecko specific deprecated method. - [Throws] void initDeviceOrientationEvent(DOMString type, boolean canBubble, boolean cancelable, diff --git a/dom/webidl/DragEvent.webidl b/dom/webidl/DragEvent.webidl index 913cb20727..2cc173d5ca 100644 --- a/dom/webidl/DragEvent.webidl +++ b/dom/webidl/DragEvent.webidl @@ -9,7 +9,6 @@ interface DragEvent : MouseEvent { readonly attribute DataTransfer? dataTransfer; - [Throws] void initDragEvent(DOMString type, boolean canBubble, boolean cancelable, diff --git a/dom/webidl/Event.webidl b/dom/webidl/Event.webidl index aebbdc8e36..dbb0e01eb6 100644 --- a/dom/webidl/Event.webidl +++ b/dom/webidl/Event.webidl @@ -45,7 +45,6 @@ interface Event { [Pure] readonly attribute DOMHighResTimeStamp timeStamp; - [Throws] void initEvent(DOMString type, boolean bubbles, boolean cancelable); attribute boolean cancelBubble; }; diff --git a/dom/webidl/ExtendableMessageEvent.webidl b/dom/webidl/ExtendableMessageEvent.webidl new file mode 100644 index 0000000000..9800618e24 --- /dev/null +++ b/dom/webidl/ExtendableMessageEvent.webidl @@ -0,0 +1,43 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * For more information on this interface, please see + * http://www.whatwg.org/specs/web-apps/current-work/#messageevent + */ + +[Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict), + Exposed=(ServiceWorker)] +interface ExtendableMessageEvent : ExtendableEvent { + /** + * Custom data associated with this event. + */ + [GetterThrows] + readonly attribute any data; + + /** + * The origin of the site from which this event originated. + */ + readonly attribute DOMString origin; + + /** + * The last event ID string of the event source. + */ + readonly attribute DOMString lastEventId; + + /** + * The client, service worker or port which originated this event. + */ + readonly attribute (Client or ServiceWorker or MessagePort)? source; + + readonly attribute MessagePortList? ports; +}; + +dictionary ExtendableMessageEventInit : ExtendableEventInit { + any data; + DOMString origin = ""; + DOMString lastEventId = ""; + (Client or ServiceWorker or MessagePort)? source; + sequence? ports; +}; diff --git a/dom/webidl/FetchEvent.webidl b/dom/webidl/FetchEvent.webidl index a5a7f8e354..105ae12c02 100644 --- a/dom/webidl/FetchEvent.webidl +++ b/dom/webidl/FetchEvent.webidl @@ -10,11 +10,8 @@ [Constructor(DOMString type, optional FetchEventInit eventInitDict), Func="mozilla::dom::workers::ServiceWorkerVisible", Exposed=(ServiceWorker)] -interface FetchEvent : Event { - readonly attribute Request request; - - // https://github.com/slightlyoff/ServiceWorker/issues/631 - readonly attribute Client? client; // The window issuing the request. +interface FetchEvent : ExtendableEvent { + [SameObject] readonly attribute Request? request; readonly attribute boolean isReload; [Throws] @@ -23,6 +20,5 @@ interface FetchEvent : Event { dictionary FetchEventInit : EventInit { Request request; - Client client; - boolean isReload; + boolean isReload = false; }; diff --git a/dom/webidl/HashChangeEvent.webidl b/dom/webidl/HashChangeEvent.webidl index 86bfe8a69c..053c829b22 100644 --- a/dom/webidl/HashChangeEvent.webidl +++ b/dom/webidl/HashChangeEvent.webidl @@ -10,7 +10,6 @@ interface HashChangeEvent : Event readonly attribute DOMString? oldURL; readonly attribute DOMString? newURL; - [Throws] void initHashChangeEvent(DOMString typeArg, boolean canBubbleArg, boolean cancelableArg, diff --git a/dom/webidl/KeyEvent.webidl b/dom/webidl/KeyEvent.webidl index 37ff7fc2ec..5166328545 100644 --- a/dom/webidl/KeyEvent.webidl +++ b/dom/webidl/KeyEvent.webidl @@ -224,7 +224,6 @@ interface KeyEvent // for compatibility with the other web browsers on Windows. const unsigned long DOM_VK_WIN_OEM_CLEAR = 0xFE; - [Throws] void initKeyEvent(DOMString type, boolean canBubble, boolean cancelable, diff --git a/dom/webidl/MessageEvent.webidl b/dom/webidl/MessageEvent.webidl index 8693d310dd..2c5cfaf669 100644 --- a/dom/webidl/MessageEvent.webidl +++ b/dom/webidl/MessageEvent.webidl @@ -31,12 +31,9 @@ interface MessageEvent : Event { readonly attribute DOMString lastEventId; /** - * The window, port or client which originated this event. - * FIXME(catalinb): Update this when the spec changes are implemented. - * https://www.w3.org/Bugs/Public/show_bug.cgi?id=28199 - * https://bugzilla.mozilla.org/show_bug.cgi?id=1143717 + * The window or port which originated this event. */ - readonly attribute (WindowProxy or MessagePort or Client)? source; + readonly attribute (WindowProxy or MessagePort)? source; /** * Initializes this event with the given data, in a manner analogous to @@ -44,6 +41,11 @@ interface MessageEvent : Event { * data, origin, source, and lastEventId attributes of this appropriately. */ readonly attribute MessagePortList? ports; + + void initMessageEvent(DOMString type, boolean bubbles, boolean cancelable, + any data, DOMString origin, DOMString lastEventId, + (WindowProxy or MessagePort)? source, + sequence? ports); }; dictionary MessageEventInit : EventInit { diff --git a/dom/webidl/MouseEvent.webidl b/dom/webidl/MouseEvent.webidl index 3e32808872..d10d9531a5 100644 --- a/dom/webidl/MouseEvent.webidl +++ b/dom/webidl/MouseEvent.webidl @@ -32,7 +32,6 @@ interface MouseEvent : UIEvent { readonly attribute long movementY; // Deprecated in DOM Level 3: - [Throws] void initMouseEvent(DOMString typeArg, boolean canBubbleArg, boolean cancelableArg, @@ -91,7 +90,6 @@ partial interface MouseEvent readonly attribute unsigned short mozInputSource; - [Throws] void initNSMouseEvent(DOMString typeArg, boolean canBubbleArg, boolean cancelableArg, diff --git a/dom/webidl/MouseScrollEvent.webidl b/dom/webidl/MouseScrollEvent.webidl index eb02d0572d..aa9e30fd2b 100644 --- a/dom/webidl/MouseScrollEvent.webidl +++ b/dom/webidl/MouseScrollEvent.webidl @@ -11,7 +11,6 @@ interface MouseScrollEvent : MouseEvent readonly attribute long axis; - [Throws] void initMouseScrollEvent(DOMString type, boolean canBubble, boolean cancelable, diff --git a/dom/webidl/ScrollAreaEvent.webidl b/dom/webidl/ScrollAreaEvent.webidl index c0e6670c57..0f48b4bc83 100644 --- a/dom/webidl/ScrollAreaEvent.webidl +++ b/dom/webidl/ScrollAreaEvent.webidl @@ -11,7 +11,6 @@ interface ScrollAreaEvent : UIEvent readonly attribute float width; readonly attribute float height; - [Throws] void initScrollAreaEvent(DOMString type, boolean canBubble, boolean cancelable, diff --git a/dom/webidl/SimpleGestureEvent.webidl b/dom/webidl/SimpleGestureEvent.webidl index 18cb92e43f..0829076dd4 100644 --- a/dom/webidl/SimpleGestureEvent.webidl +++ b/dom/webidl/SimpleGestureEvent.webidl @@ -24,7 +24,6 @@ interface SimpleGestureEvent : MouseEvent readonly attribute unsigned long clickCount; - [Throws] void initSimpleGestureEvent(DOMString typeArg, boolean canBubbleArg, boolean cancelableArg, diff --git a/dom/webidl/StorageEvent.webidl b/dom/webidl/StorageEvent.webidl index 44836d2196..c3e9605eb6 100644 --- a/dom/webidl/StorageEvent.webidl +++ b/dom/webidl/StorageEvent.webidl @@ -20,7 +20,6 @@ interface StorageEvent : Event readonly attribute Storage? storageArea; // Bug 1016053 - This is not spec compliant. - [Throws] void initStorageEvent(DOMString type, boolean canBubble, boolean cancelable, diff --git a/dom/webidl/TouchEvent.webidl b/dom/webidl/TouchEvent.webidl index 6e9a718f72..85ad1c3759 100644 --- a/dom/webidl/TouchEvent.webidl +++ b/dom/webidl/TouchEvent.webidl @@ -15,7 +15,6 @@ interface TouchEvent : UIEvent { readonly attribute boolean ctrlKey; readonly attribute boolean shiftKey; - [Throws] void initTouchEvent(DOMString type, boolean canBubble, boolean cancelable, diff --git a/dom/webidl/XULCommandEvent.webidl b/dom/webidl/XULCommandEvent.webidl index 209415dd9e..9c024edc13 100644 --- a/dom/webidl/XULCommandEvent.webidl +++ b/dom/webidl/XULCommandEvent.webidl @@ -14,7 +14,6 @@ interface XULCommandEvent : UIEvent readonly attribute Event? sourceEvent; - [Throws] void initCommandEvent(DOMString type, boolean canBubble, boolean cancelable, diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 706ddce169..62a95f3ea8 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -147,6 +147,7 @@ WEBIDL_FILES = [ 'EventSource.webidl', 'EventTarget.webidl', 'ExtendableEvent.webidl', + 'ExtendableMessageEvent.webidl', 'FakePluginTagInit.webidl', 'Fetch.webidl', 'FetchEvent.webidl', diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index e87d1eb1b9..47ccab0971 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -1243,6 +1243,26 @@ ThawWorkersForWindow(nsPIDOMWindow* aWindow) } } +void +SuspendWorkersForWindow(nsPIDOMWindow* aWindow) +{ + AssertIsOnMainThread(); + RuntimeService* runtime = RuntimeService::GetService(); + if (runtime) { + runtime->SuspendWorkersForWindow(aWindow); + } +} + +void +ResumeWorkersForWindow(nsPIDOMWindow* aWindow) +{ + AssertIsOnMainThread(); + RuntimeService* runtime = RuntimeService::GetService(); + if (runtime) { + runtime->ResumeWorkersForWindow(aWindow); + } +} + WorkerCrossThreadDispatcher::WorkerCrossThreadDispatcher( WorkerPrivate* aWorkerPrivate) : mMutex("WorkerCrossThreadDispatcher::mMutex"), @@ -2343,6 +2363,34 @@ RuntimeService::ThawWorkersForWindow(nsPIDOMWindow* aWindow) } } +void +RuntimeService::SuspendWorkersForWindow(nsPIDOMWindow* aWindow) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(aWindow); + + nsAutoTArray workers; + GetWorkersForWindow(aWindow, workers); + + for (uint32_t index = 0; index < workers.Length(); index++) { + workers[index]->Suspend(); + } +} + +void +RuntimeService::ResumeWorkersForWindow(nsPIDOMWindow* aWindow) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(aWindow); + + nsAutoTArray workers; + GetWorkersForWindow(aWindow, workers); + + for (uint32_t index = 0; index < workers.Length(); index++) { + workers[index]->Resume(); + } +} + nsresult RuntimeService::CreateSharedWorker(const GlobalObject& aGlobal, const nsAString& aScriptURL, diff --git a/dom/workers/RuntimeService.h b/dom/workers/RuntimeService.h index 7538388242..cc3593b240 100644 --- a/dom/workers/RuntimeService.h +++ b/dom/workers/RuntimeService.h @@ -140,6 +140,12 @@ public: void ThawWorkersForWindow(nsPIDOMWindow* aWindow); + void + SuspendWorkersForWindow(nsPIDOMWindow* aWindow); + + void + ResumeWorkersForWindow(nsPIDOMWindow* aWindow); + nsresult CreateSharedWorker(const GlobalObject& aGlobal, const nsAString& aScriptURL, diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index c5227b4803..26a8bbd3a9 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -66,7 +66,6 @@ using mozilla::dom::cache::Cache; using mozilla::dom::cache::CacheStorage; using mozilla::dom::Promise; using mozilla::dom::PromiseNativeHandler; -using mozilla::dom::workers::exceptions::ThrowDOMExceptionForNSResult; using mozilla::ErrorResult; using mozilla::ipc::PrincipalInfo; using mozilla::UniquePtr; @@ -149,13 +148,6 @@ ChannelFromScriptURL(nsIPrincipal* principal, return NS_ERROR_DOM_SECURITY_ERR; } } else if (aIsMainScript) { - // If this script loader is being used to make a new worker then we need - // to do a same-origin check. Otherwise we need to clear the load with the - // security manager. - nsCString scheme; - rv = uri->GetScheme(scheme); - NS_ENSURE_SUCCESS(rv, rv); - // We pass true as the 3rd argument to checkMayLoad here. // This allows workers in sandboxed documents to load data URLs // (and other URLs that inherit their principal from their @@ -281,6 +273,8 @@ struct ScriptLoadInfo CacheStatus mCacheStatus; + Maybe mMutedErrorFlag; + bool Finished() const { return mLoadingFinished && !mCachePromise && !mChannel; @@ -322,7 +316,8 @@ private: void ShutdownScriptLoader(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aResult); + bool aResult, + bool aMutedError); }; class CacheScriptLoader; @@ -505,6 +500,7 @@ class ScriptLoaderRunnable final : public WorkerFeature, WorkerScriptType mWorkerScriptType; bool mCanceled; bool mCanceledMainThread; + ErrorResult& mRv; public: NS_DECL_THREADSAFE_ISUPPORTS @@ -513,10 +509,11 @@ public: nsIEventTarget* aSyncLoopTarget, nsTArray& aLoadInfos, bool aIsMainScript, - WorkerScriptType aWorkerScriptType) + WorkerScriptType aWorkerScriptType, + ErrorResult& aRv) : mWorkerPrivate(aWorkerPrivate), mSyncLoopTarget(aSyncLoopTarget), mIsMainScript(aIsMainScript), mWorkerScriptType(aWorkerScriptType), - mCanceled(false), mCanceledMainThread(false) + mCanceled(false), mCanceledMainThread(false), mRv(aRv) { aWorkerPrivate->AssertIsOnWorkerThread(); MOZ_ASSERT(aSyncLoopTarget); @@ -1115,6 +1112,18 @@ private: ScriptLoadInfo& loadInfo = mLoadInfos[aIndex]; MOZ_ASSERT(loadInfo.mCacheStatus == ScriptLoadInfo::Cached); + nsCOMPtr responsePrincipal = + PrincipalInfoToPrincipal(*aPrincipalInfo); + + nsIPrincipal* principal = mWorkerPrivate->GetPrincipal(); + if (!principal) { + WorkerPrivate* parentWorker = mWorkerPrivate->GetParent(); + MOZ_ASSERT(parentWorker, "Must have a parent!"); + principal = parentWorker->GetPrincipal(); + } + + loadInfo.mMutedErrorFlag.emplace(!principal->Subsumes(responsePrincipal)); + // May be null. nsIDocument* parentDoc = mWorkerPrivate->GetDocument(); @@ -1137,8 +1146,6 @@ private: nsILoadGroup* loadGroup = mWorkerPrivate->GetLoadGroup(); MOZ_ASSERT(loadGroup); - nsCOMPtr responsePrincipal = - PrincipalInfoToPrincipal(*aPrincipalInfo); mozilla::DebugOnly equal = false; MOZ_ASSERT(responsePrincipal && NS_SUCCEEDED(responsePrincipal->Equals(principal, &equal))); MOZ_ASSERT(equal); @@ -1578,7 +1585,7 @@ CacheScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aCont return NS_OK; } - class ChannelGetterRunnable final : public nsRunnable +class ChannelGetterRunnable final : public nsRunnable { WorkerPrivate* mParentWorker; nsCOMPtr mSyncLoopTarget; @@ -1716,9 +1723,11 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) NS_ASSERTION(!loadInfo.mExecutionResult, "Should not have executed yet!"); if (NS_FAILED(loadInfo.mLoadResult)) { - scriptloader::ReportLoadError(aCx, loadInfo.mURL, loadInfo.mLoadResult, - false); - aWorkerPrivate->MaybeDispatchLoadFailedRunnable(); + scriptloader::ReportLoadError(aCx, loadInfo.mLoadResult); + // Top level scripts only! + if (mIsWorkerScript) { + aWorkerPrivate->MaybeDispatchLoadFailedRunnable(); + } return true; } @@ -1732,6 +1741,9 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) options.setVersion(JSVERSION_LATEST); } + MOZ_ASSERT(loadInfo.mMutedErrorFlag.isSome()); + options.setMutedErrors(loadInfo.mMutedErrorFlag.valueOr(true)); + JS::SourceBufferHolder srcBuf(loadInfo.mScriptTextBuf, loadInfo.mScriptTextLength, JS::SourceBufferHolder::GiveOwnership); @@ -1758,14 +1770,16 @@ ScriptExecutorRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, if (mLastIndex == loadInfos.Length() - 1) { // All done. If anything failed then return false. bool result = true; + bool mutedError = false; for (uint32_t index = 0; index < loadInfos.Length(); index++) { if (!loadInfos[index].mExecutionResult) { + mutedError = loadInfos[index].mMutedErrorFlag.valueOr(true); result = false; break; } } - ShutdownScriptLoader(aCx, aWorkerPrivate, result); + ShutdownScriptLoader(aCx, aWorkerPrivate, result, mutedError); } } @@ -1773,7 +1787,8 @@ NS_IMETHODIMP ScriptExecutorRunnable::Cancel() { if (mLastIndex == mScriptLoader.mLoadInfos.Length() - 1) { - ShutdownScriptLoader(mWorkerPrivate->GetJSContext(), mWorkerPrivate, false); + ShutdownScriptLoader(mWorkerPrivate->GetJSContext(), mWorkerPrivate, + false, false); } return MainThreadWorkerSyncRunnable::Cancel(); } @@ -1781,7 +1796,8 @@ ScriptExecutorRunnable::Cancel() void ScriptExecutorRunnable::ShutdownScriptLoader(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aResult) + bool aResult, + bool aMutedError) { MOZ_ASSERT(mLastIndex == mScriptLoader.mLoadInfos.Length() - 1); @@ -1789,14 +1805,25 @@ ScriptExecutorRunnable::ShutdownScriptLoader(JSContext* aCx, aWorkerPrivate->SetLoadingWorkerScript(false); } + if (!aResult) { + // If this error has to be muted, we have to clear the pending exception, + // if any, and use the ErrorResult object to throw a new exception. + if (aMutedError && JS_IsExceptionPending(aCx)) { + JS_ClearPendingException(aCx); + mScriptLoader.mRv.Throw(NS_ERROR_FAILURE); + } else { + mScriptLoader.mRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + } + } + aWorkerPrivate->RemoveFeature(aCx, &mScriptLoader); aWorkerPrivate->StopSyncLoop(mSyncLoopTarget, aResult); } -bool +void LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate, nsTArray& aLoadInfos, bool aIsMainScript, - WorkerScriptType aWorkerScriptType) + WorkerScriptType aWorkerScriptType, ErrorResult& aRv) { aWorkerPrivate->AssertIsOnWorkerThread(); NS_ASSERTION(!aLoadInfos.IsEmpty(), "Bad arguments!"); @@ -1805,22 +1832,25 @@ LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate, RefPtr loader = new ScriptLoaderRunnable(aWorkerPrivate, syncLoop.EventTarget(), - aLoadInfos, aIsMainScript, aWorkerScriptType); + aLoadInfos, aIsMainScript, aWorkerScriptType, + aRv); NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!"); if (!aWorkerPrivate->AddFeature(aCx, loader)) { - return false; + aRv.Throw(NS_ERROR_FAILURE); + return; } if (NS_FAILED(NS_DispatchToMainThread(loader))) { NS_ERROR("Failed to dispatch!"); aWorkerPrivate->RemoveFeature(aCx, loader); - return false; + aRv.Throw(NS_ERROR_FAILURE); + return; } - return syncLoop.Run(); + syncLoop.Run(); } } /* anonymous namespace */ @@ -1877,25 +1907,21 @@ ChannelFromScriptURLWorkerThread(JSContext* aCx, return getter->GetResult(); } -void ReportLoadError(JSContext* aCx, const nsAString& aURL, - nsresult aLoadResult, bool aIsMainThread) +void ReportLoadError(JSContext* aCx, nsresult aLoadResult) { - NS_LossyConvertUTF16toASCII url(aURL); - switch (aLoadResult) { case NS_BINDING_ABORTED: // Canceled, don't set an exception. break; - case NS_ERROR_MALFORMED_URI: - JS_ReportError(aCx, "Malformed script URI: %s", url.get()); - break; - case NS_ERROR_FILE_NOT_FOUND: case NS_ERROR_NOT_AVAILABLE: - JS_ReportError(aCx, "Script file not found: %s", url.get()); + Throw(aCx, NS_ERROR_DOM_NETWORK_ERR); break; + case NS_ERROR_MALFORMED_URI: + aLoadResult = NS_ERROR_DOM_SYNTAX_ERR; + // fall through case NS_ERROR_DOM_SECURITY_ERR: case NS_ERROR_DOM_SYNTAX_ERR: Throw(aCx, aLoadResult); @@ -1906,9 +1932,10 @@ void ReportLoadError(JSContext* aCx, const nsAString& aURL, } } -bool +void LoadMainScript(JSContext* aCx, const nsAString& aScriptURL, - WorkerScriptType aWorkerScriptType) + WorkerScriptType aWorkerScriptType, + ErrorResult& aRv) { WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx); NS_ASSERTION(worker, "This should never be null!"); @@ -1918,7 +1945,7 @@ LoadMainScript(JSContext* aCx, const nsAString& aScriptURL, ScriptLoadInfo* info = loadInfos.AppendElement(); info->mURL = aScriptURL; - return LoadAllScripts(aCx, worker, loadInfos, true, aWorkerScriptType); + LoadAllScripts(aCx, worker, loadInfos, true, aWorkerScriptType, aRv); } void @@ -1944,10 +1971,7 @@ Load(JSContext* aCx, WorkerPrivate* aWorkerPrivate, loadInfos[index].mURL = aScriptURLs[index]; } - if (!LoadAllScripts(aCx, aWorkerPrivate, loadInfos, false, aWorkerScriptType)) { - // LoadAllScripts can fail if we're shutting down. - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - } + LoadAllScripts(aCx, aWorkerPrivate, loadInfos, false, aWorkerScriptType, aRv); } } // namespace scriptloader diff --git a/dom/workers/ScriptLoader.h b/dom/workers/ScriptLoader.h index 35b0d253d0..9a8d768266 100644 --- a/dom/workers/ScriptLoader.h +++ b/dom/workers/ScriptLoader.h @@ -47,11 +47,11 @@ ChannelFromScriptURLWorkerThread(JSContext* aCx, const nsAString& aScriptURL, nsIChannel** aChannel); -void ReportLoadError(JSContext* aCx, const nsAString& aURL, - nsresult aLoadResult, bool aIsMainThread); +void ReportLoadError(JSContext* aCx, nsresult aLoadResult); -bool LoadMainScript(JSContext* aCx, const nsAString& aScriptURL, - WorkerScriptType aWorkerScriptType); +void LoadMainScript(JSContext* aCx, const nsAString& aScriptURL, + WorkerScriptType aWorkerScriptType, + ErrorResult& aRv); void Load(JSContext* aCx, WorkerPrivate* aWorkerPrivate, diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp index 25ead34018..8bf1673a61 100644 --- a/dom/workers/ServiceWorkerEvents.cpp +++ b/dom/workers/ServiceWorkerEvents.cpp @@ -5,8 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ServiceWorkerEvents.h" -#include "ServiceWorkerClient.h" +#include "nsIConsoleReportCollector.h" #include "nsIHttpChannelInternal.h" #include "nsINetworkInterceptController.h" #include "nsIOutputStream.h" @@ -20,8 +20,13 @@ #include "nsSerializationHelper.h" #include "nsQueryObject.h" +#include "mozilla/ErrorResult.h" #include "mozilla/Preferences.h" +#include "mozilla/dom/DOMException.h" +#include "mozilla/dom/DOMExceptionBinding.h" #include "mozilla/dom/FetchEventBinding.h" +#include "mozilla/dom/MessagePort.h" +#include "mozilla/dom/MessagePortList.h" #include "mozilla/dom/PromiseNativeHandler.h" #include "mozilla/dom/Request.h" #include "mozilla/dom/Response.h" @@ -37,7 +42,10 @@ #include "mozilla/dom/TypedArray.h" #endif +#include "js/Conversions.h" +#include "js/TypeDecls.h" #include "WorkerPrivate.h" +#include "xpcpublic.h" using namespace mozilla::dom; @@ -60,9 +68,9 @@ CancelChannelRunnable::Run() } FetchEvent::FetchEvent(EventTarget* aOwner) -: Event(aOwner, nullptr, nullptr) -, mIsReload(false) -, mWaitToRespond(false) + : ExtendableEvent(aOwner) + , mIsReload(false) + , mWaitToRespond(false) { } @@ -72,12 +80,10 @@ FetchEvent::~FetchEvent() void FetchEvent::PostInit(nsMainThreadPtrHandle& aChannel, - const nsACString& aScriptSpec, - UniquePtr&& aClientInfo) + const nsACString& aScriptSpec) { mChannel = aChannel; mScriptSpec.Assign(aScriptSpec); - mClientInfo = Move(aClientInfo); } /*static*/ already_AddRefed @@ -94,15 +100,46 @@ FetchEvent::Constructor(const GlobalObject& aGlobal, e->SetTrusted(trusted); e->mRequest = aOptions.mRequest.WasPassed() ? &aOptions.mRequest.Value() : nullptr; - e->mIsReload = aOptions.mIsReload.WasPassed() ? - aOptions.mIsReload.Value() : false; - e->mClient = aOptions.mClient.WasPassed() ? - &aOptions.mClient.Value() : nullptr; + e->mIsReload = aOptions.mIsReload; return e.forget(); } namespace { +void +AsyncLog(nsIInterceptedChannel *aInterceptedChannel, + const nsACString& aRespondWithScriptSpec, + uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber, + const nsACString& aMessageName, const nsTArray& aParams) +{ + MOZ_ASSERT(aInterceptedChannel); + nsCOMPtr inner; + aInterceptedChannel->GetChannel(getter_AddRefs(inner)); + nsCOMPtr reporter = do_QueryInterface(inner); + if (reporter) { + reporter->AddConsoleReport(nsIScriptError::errorFlag, + NS_LITERAL_CSTRING("Service Worker Interception"), + nsContentUtils::eDOM_PROPERTIES, + aRespondWithScriptSpec, + aRespondWithLineNumber, + aRespondWithColumnNumber, + aMessageName, aParams); + } +} + +template +void +AsyncLog(nsIInterceptedChannel* aInterceptedChannel, + const nsACString& aRespondWithScriptSpec, + uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber, + const nsACString& aMessageName, Params... aParams) +{ + nsTArray paramsList(sizeof...(Params)); + StringArrayAppender::Append(paramsList, sizeof...(Params), aParams...); + AsyncLog(aInterceptedChannel, aRespondWithScriptSpec, aRespondWithLineNumber, + aRespondWithColumnNumber, aMessageName, paramsList); +} + class FinishResponse final : public nsRunnable { nsMainThreadPtrHandle mChannel; @@ -203,6 +240,10 @@ class RespondWithHandler final : public PromiseNativeHandler const DebugOnly mIsClientRequest; const bool mIsNavigationRequest; const nsCString mScriptSpec; + const nsString mRequestURL; + const nsCString mRespondWithScriptSpec; + const uint32_t mRespondWithLineNumber; + const uint32_t mRespondWithColumnNumber; bool mRequestWasHandled; public: NS_DECL_ISUPPORTS @@ -210,12 +251,20 @@ public: RespondWithHandler(nsMainThreadPtrHandle& aChannel, RequestMode aRequestMode, bool aIsClientRequest, bool aIsNavigationRequest, - const nsACString& aScriptSpec) + const nsACString& aScriptSpec, + const nsAString& aRequestURL, + const nsACString& aRespondWithScriptSpec, + uint32_t aRespondWithLineNumber, + uint32_t aRespondWithColumnNumber) : mInterceptedChannel(aChannel) , mRequestMode(aRequestMode) , mIsClientRequest(aIsClientRequest) , mIsNavigationRequest(aIsNavigationRequest) , mScriptSpec(aScriptSpec) + , mRequestURL(aRequestURL) + , mRespondWithScriptSpec(aRespondWithScriptSpec) + , mRespondWithLineNumber(aRespondWithLineNumber) + , mRespondWithColumnNumber(aRespondWithColumnNumber) , mRequestWasHandled(false) { } @@ -225,10 +274,27 @@ public: void RejectedCallback(JSContext* aCx, JS::Handle aValue) override; void CancelRequest(nsresult aStatus); + + void AsyncLog(const nsACString& aMessageName, const nsTArray& aParams) + { + ::AsyncLog(mInterceptedChannel, mRespondWithScriptSpec, mRespondWithLineNumber, + mRespondWithColumnNumber, aMessageName, aParams); + } + + void AsyncLog(const nsACString& aSourceSpec, uint32_t aLine, uint32_t aColumn, + const nsACString& aMessageName, const nsTArray& aParams) + { + ::AsyncLog(mInterceptedChannel, aSourceSpec, aLine, aColumn, aMessageName, + aParams); + } + private: ~RespondWithHandler() { if (!mRequestWasHandled) { + ::AsyncLog(mInterceptedChannel, mRespondWithScriptSpec, + mRespondWithLineNumber, mRespondWithColumnNumber, + NS_LITERAL_CSTRING("InterceptionFailedWithURL"), &mRequestURL); CancelRequest(NS_ERROR_INTERCEPTION_FAILED); } } @@ -241,17 +307,29 @@ struct RespondWithClosure ChannelInfo mWorkerChannelInfo; const nsCString mScriptSpec; const nsCString mResponseURLSpec; + const nsString mRequestURL; + const nsCString mRespondWithScriptSpec; + const uint32_t mRespondWithLineNumber; + const uint32_t mRespondWithColumnNumber; RespondWithClosure(nsMainThreadPtrHandle& aChannel, InternalResponse* aInternalResponse, const ChannelInfo& aWorkerChannelInfo, const nsCString& aScriptSpec, - const nsACString& aResponseURLSpec) + const nsACString& aResponseURLSpec, + const nsAString& aRequestURL, + const nsACString& aRespondWithScriptSpec, + uint32_t aRespondWithLineNumber, + uint32_t aRespondWithColumnNumber) : mInterceptedChannel(aChannel) , mInternalResponse(aInternalResponse) , mWorkerChannelInfo(aWorkerChannelInfo) , mScriptSpec(aScriptSpec) , mResponseURLSpec(aResponseURLSpec) + , mRequestURL(aRequestURL) + , mRespondWithScriptSpec(aRespondWithScriptSpec) + , mRespondWithLineNumber(aRespondWithLineNumber) + , mRespondWithColumnNumber(aRespondWithColumnNumber) { } }; @@ -267,35 +345,143 @@ void RespondWithCopyComplete(void* aClosure, nsresult aStatus) data->mScriptSpec, data->mResponseURLSpec); } else { + AsyncLog(data->mInterceptedChannel, data->mRespondWithScriptSpec, + data->mRespondWithLineNumber, data->mRespondWithColumnNumber, + NS_LITERAL_CSTRING("InterceptionFailedWithURL"), + &data->mRequestURL); event = new CancelChannelRunnable(data->mInterceptedChannel, NS_ERROR_INTERCEPTION_FAILED); } MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(event))); } +namespace { + +void +ExtractErrorValues(JSContext* aCx, JS::Handle aValue, + nsACString& aSourceSpecOut, uint32_t *aLineOut, + uint32_t *aColumnOut, nsString& aMessageOut) +{ + MOZ_ASSERT(aLineOut); + MOZ_ASSERT(aColumnOut); + + if (aValue.isObject()) { + JS::Rooted obj(aCx, &aValue.toObject()); + RefPtr domException; + + // Try to process as an Error object. Use the file/line/column values + // from the Error as they will be more specific to the root cause of + // the problem. + JSErrorReport* err = obj ? JS_ErrorFromException(aCx, obj) : nullptr; + if (err) { + // Use xpc to extract the error message only. We don't actually send + // this report anywhere. + RefPtr report = new xpc::ErrorReport(); + report->Init(err, + "", // fallback message + false, // chrome + 0); // window ID + + if (!report->mFileName.IsEmpty()) { + CopyUTF16toUTF8(report->mFileName, aSourceSpecOut); + *aLineOut = report->mLineNumber; + *aColumnOut = report->mColumn; + } + aMessageOut.Assign(report->mErrorMsg); + } + + // Next, try to unwrap the rejection value as a DOMException. + else if(NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException))) { + + nsAutoString filename; + if (NS_SUCCEEDED(domException->GetFilename(filename)) && + !filename.IsEmpty()) { + CopyUTF16toUTF8(filename, aSourceSpecOut); + *aLineOut = domException->LineNumber(); + *aColumnOut = domException->ColumnNumber(); + } + + domException->GetName(aMessageOut); + aMessageOut.AppendLiteral(": "); + + nsAutoString message; + domException->GetMessageMoz(message); + aMessageOut.Append(message); + } + } + + // If we could not unwrap a specific error type, then perform default safe + // string conversions on primitives. Objects will result in "[Object]" + // unfortunately. + if (aMessageOut.IsEmpty()) { + nsAutoJSString jsString; + if (jsString.init(aCx, aValue)) { + aMessageOut = jsString; + } + } +} + +} // anonymous namespace + class MOZ_STACK_CLASS AutoCancel { RefPtr mOwner; - nsresult mStatus; + nsCString mSourceSpec; + uint32_t mLine; + uint32_t mColumn; + nsCString mMessageName; + nsTArray mParams; public: - explicit AutoCancel(RespondWithHandler* aOwner) + AutoCancel(RespondWithHandler* aOwner, const nsString& aRequestURL) : mOwner(aOwner) - , mStatus(NS_ERROR_INTERCEPTION_FAILED) + , mLine(0) + , mColumn(0) + , mMessageName(NS_LITERAL_CSTRING("InterceptionFailedWithURL")) { + mParams.AppendElement(aRequestURL); } ~AutoCancel() { if (mOwner) { - mOwner->CancelRequest(mStatus); + if (mSourceSpec.IsEmpty()) { + mOwner->AsyncLog(mMessageName, mParams); + } else { + mOwner->AsyncLog(mSourceSpec, mLine, mColumn, mMessageName, mParams); + } + mOwner->CancelRequest(NS_ERROR_INTERCEPTION_FAILED); } } - void SetCancelStatus(nsresult aStatus) + template + void SetCancelMessage(const nsACString& aMessageName, Params... aParams) { - MOZ_ASSERT(NS_FAILED(aStatus)); - mStatus = aStatus; + MOZ_ASSERT(mOwner); + MOZ_ASSERT(mMessageName.EqualsLiteral("InterceptionFailedWithURL")); + MOZ_ASSERT(mParams.Length() == 1); + mMessageName = aMessageName; + mParams.Clear(); + StringArrayAppender::Append(mParams, sizeof...(Params), aParams...); + } + + template + void SetCancelMessageAndLocation(const nsACString& aSourceSpec, + uint32_t aLine, uint32_t aColumn, + const nsACString& aMessageName, + Params... aParams) + { + MOZ_ASSERT(mOwner); + MOZ_ASSERT(mMessageName.EqualsLiteral("InterceptionFailedWithURL")); + MOZ_ASSERT(mParams.Length() == 1); + + mSourceSpec = aSourceSpec; + mLine = aLine; + mColumn = aColumn; + + mMessageName = aMessageName; + mParams.Clear(); + StringArrayAppender::Append(mParams, sizeof...(Params), aParams...); } void Reset() @@ -309,15 +495,35 @@ NS_IMPL_ISUPPORTS0(RespondWithHandler) void RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle aValue) { - AutoCancel autoCancel(this); + AutoCancel autoCancel(this, mRequestURL); if (!aValue.isObject()) { + NS_WARNING("FetchEvent::RespondWith was passed a promise resolved to a non-Object value"); + + nsCString sourceSpec; + uint32_t line = 0; + uint32_t column = 0; + nsString valueString; + ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString); + + autoCancel.SetCancelMessageAndLocation(sourceSpec, line, column, + NS_LITERAL_CSTRING("InterceptedNonResponseWithURL"), + &mRequestURL, &valueString); return; } RefPtr response; nsresult rv = UNWRAP_OBJECT(Response, &aValue.toObject(), response); if (NS_FAILED(rv)) { + nsCString sourceSpec; + uint32_t line = 0; + uint32_t column = 0; + nsString valueString; + ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString); + + autoCancel.SetCancelMessageAndLocation(sourceSpec, line, column, + NS_LITERAL_CSTRING("InterceptedNonResponseWithURL"), + &mRequestURL, &valueString); return; } @@ -329,7 +535,8 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle aValu // security implications are not a complete disaster. if (response->Type() == ResponseType::Opaque && !worker->OpaqueInterceptionEnabled()) { - autoCancel.SetCancelStatus(NS_ERROR_OPAQUE_INTERCEPTION_DISABLED); + autoCancel.SetCancelMessage( + NS_LITERAL_CSTRING("OpaqueInterceptionDisabledWithURL"), &mRequestURL); return; } @@ -341,24 +548,33 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle aValu // "opaqueredirect". if (response->Type() == ResponseType::Error) { - autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTED_ERROR_RESPONSE); + autoCancel.SetCancelMessage( + NS_LITERAL_CSTRING("InterceptedErrorResponseWithURL"), &mRequestURL); return; } MOZ_ASSERT_IF(mIsClientRequest, mRequestMode == RequestMode::Same_origin); if (response->Type() == ResponseType::Opaque && mRequestMode != RequestMode::No_cors) { - autoCancel.SetCancelStatus(NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE); + uint32_t mode = static_cast(mRequestMode); + NS_ConvertASCIItoUTF16 modeString(RequestModeValues::strings[mode].value, + RequestModeValues::strings[mode].length); + + autoCancel.SetCancelMessage( + NS_LITERAL_CSTRING("BadOpaqueInterceptionRequestModeWithURL"), + &mRequestURL, &modeString); return; } if (!mIsNavigationRequest && response->Type() == ResponseType::Opaqueredirect) { - autoCancel.SetCancelStatus(NS_ERROR_BAD_OPAQUE_REDIRECT_INTERCEPTION); + autoCancel.SetCancelMessage( + NS_LITERAL_CSTRING("BadOpaqueRedirectInterceptionWithURL"), &mRequestURL); return; } if (NS_WARN_IF(response->BodyUsed())) { - autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTED_USED_RESPONSE); + autoCancel.SetCancelMessage( + NS_LITERAL_CSTRING("InterceptedUsedResponseWithURL"), &mRequestURL); return; } @@ -374,7 +590,6 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle aValu if (response->Type() == ResponseType::Opaque) { ir->GetUnfilteredUrl(responseURL); if (NS_WARN_IF(responseURL.IsEmpty())) { - autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTION_FAILED); return; } } @@ -382,7 +597,11 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle aValu nsAutoPtr closure(new RespondWithClosure(mInterceptedChannel, ir, worker->GetChannelInfo(), mScriptSpec, - responseURL)); + responseURL, + mRequestURL, + mRespondWithScriptSpec, + mRespondWithLineNumber, + mRespondWithColumnNumber)); nsCOMPtr body; ir->GetUnfilteredBody(getter_AddRefs(body)); // Errors and redirects may not have a body. @@ -419,6 +638,17 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle aValu void RespondWithHandler::RejectedCallback(JSContext* aCx, JS::Handle aValue) { + nsCString sourceSpec = mRespondWithScriptSpec; + uint32_t line = mRespondWithLineNumber; + uint32_t column = mRespondWithColumnNumber; + nsString valueString; + + ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString); + + ::AsyncLog(mInterceptedChannel, sourceSpec, line, column, + NS_LITERAL_CSTRING("InterceptionRejectedResponseWithURL"), + &mRequestURL, &valueString); + CancelRequest(NS_ERROR_INTERCEPTION_FAILED); } @@ -434,57 +664,46 @@ RespondWithHandler::CancelRequest(nsresult aStatus) } // namespace void -FetchEvent::RespondWith(Promise& aArg, ErrorResult& aRv) +FetchEvent::RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv) { - if (mWaitToRespond) { + if (EventPhase() == nsIDOMEvent::NONE || mWaitToRespond) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } - // 4.5.3.2 If the respond-with entered flag is set, then: - // Throw an "InvalidStateError" exception. - // Here we use |mPromise != nullptr| as respond-with enter flag - if (mPromise) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return; - } - mPromise = &aArg; + + // Record where respondWith() was called in the script so we can include the + // information in any error reporting. We should be guaranteed not to get + // a file:// string here because service workers require http/https. + nsCString spec; + uint32_t line = 0; + uint32_t column = 0; + nsJSUtils::GetCallingLocation(aCx, spec, &line, &column); RefPtr ir = mRequest->GetInternalRequest(); + + nsAutoCString requestURL; + ir->GetURL(requestURL); + StopImmediatePropagation(); mWaitToRespond = true; RefPtr handler = new RespondWithHandler(mChannel, mRequest->Mode(), ir->IsClientRequest(), - ir->IsNavigationRequest(), mScriptSpec); + ir->IsNavigationRequest(), mScriptSpec, + NS_ConvertUTF8toUTF16(requestURL), + spec, line, column); aArg.AppendNativeHandler(handler); + + WaitUntil(aArg, aRv); } -already_AddRefed -FetchEvent::GetClient() -{ - if (!mClient) { - if (!mClientInfo) { - return nullptr; - } - - WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); - MOZ_ASSERT(worker); - RefPtr global = worker->GlobalScope(); - - mClient = new ServiceWorkerClient(global, *mClientInfo); - } - RefPtr client = mClient; - return client.forget(); -} - -NS_IMPL_ADDREF_INHERITED(FetchEvent, Event) -NS_IMPL_RELEASE_INHERITED(FetchEvent, Event) +NS_IMPL_ADDREF_INHERITED(FetchEvent, ExtendableEvent) +NS_IMPL_RELEASE_INHERITED(FetchEvent, ExtendableEvent) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FetchEvent) -NS_INTERFACE_MAP_END_INHERITING(Event) +NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent) -NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent, Event, mRequest, mClient, - mPromise) +NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent, ExtendableEvent, mRequest) ExtendableEvent::ExtendableEvent(EventTarget* aOwner) : Event(aOwner, nullptr, nullptr) @@ -728,4 +947,145 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(PushEvent, ExtendableEvent, mData) #endif /* ! MOZ_SIMPLEPUSH */ +ExtendableMessageEvent::ExtendableMessageEvent(EventTarget* aOwner) + : ExtendableEvent(aOwner) + , mData(JS::UndefinedValue()) +{ + mozilla::HoldJSObjects(this); +} + +ExtendableMessageEvent::~ExtendableMessageEvent() +{ + mData.setUndefined(); + DropJSObjects(this); +} + +void +ExtendableMessageEvent::GetData(JSContext* aCx, + JS::MutableHandle aData, + ErrorResult& aRv) +{ + JS::ExposeValueToActiveJS(mData); + aData.set(mData); + if (!JS_WrapValue(aCx, aData)) { + aRv.Throw(NS_ERROR_FAILURE); + } +} + +void +ExtendableMessageEvent::GetSource(Nullable& aValue) const +{ + if (mClient) { + aValue.SetValue().SetAsClient() = mClient; + } else if (mServiceWorker) { + aValue.SetValue().SetAsServiceWorker() = mServiceWorker; + } else if (mMessagePort) { + aValue.SetValue().SetAsMessagePort() = mMessagePort; + } else { + MOZ_CRASH("Unexpected source value"); + } +} + +/* static */ already_AddRefed +ExtendableMessageEvent::Constructor(const GlobalObject& aGlobal, + const nsAString& aType, + const ExtendableMessageEventInit& aOptions, + ErrorResult& aRv) +{ + nsCOMPtr t = do_QueryInterface(aGlobal.GetAsSupports()); + return Constructor(t, aType, aOptions, aRv); +} + +/* static */ already_AddRefed +ExtendableMessageEvent::Constructor(mozilla::dom::EventTarget* aEventTarget, + const nsAString& aType, + const ExtendableMessageEventInit& aOptions, + ErrorResult& aRv) +{ + RefPtr event = new ExtendableMessageEvent(aEventTarget); + + event->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable); + bool trusted = event->Init(aEventTarget); + event->SetTrusted(trusted); + + event->mData = aOptions.mData; + event->mOrigin = aOptions.mOrigin; + event->mLastEventId = aOptions.mLastEventId; + + if (aOptions.mSource.WasPassed() && !aOptions.mSource.Value().IsNull()) { + if (aOptions.mSource.Value().Value().IsClient()) { + event->mClient = aOptions.mSource.Value().Value().GetAsClient(); + } else if (aOptions.mSource.Value().Value().IsServiceWorker()){ + event->mServiceWorker = aOptions.mSource.Value().Value().GetAsServiceWorker(); + } else if (aOptions.mSource.Value().Value().IsServiceWorker()){ + event->mMessagePort = aOptions.mSource.Value().Value().GetAsMessagePort(); + } + MOZ_ASSERT(event->mClient || event->mServiceWorker || event->mMessagePort); + } + + if (aOptions.mPorts.WasPassed() && !aOptions.mPorts.Value().IsNull()) { + nsTArray> ports; + const Sequence>& portsParam = + aOptions.mPorts.Value().Value(); + for (uint32_t i = 0, len = portsParam.Length(); i < len; ++i) { + ports.AppendElement(portsParam[i].get()); + } + event->mPorts = new MessagePortList(static_cast(event), ports); + } + + return event.forget(); +} + +MessagePortList* +ExtendableMessageEvent::GetPorts() const +{ + return mPorts; +} + +void +ExtendableMessageEvent::SetPorts(MessagePortList* aPorts) +{ + MOZ_ASSERT(!mPorts && aPorts); + mPorts = aPorts; +} + +void +ExtendableMessageEvent::SetSource(ServiceWorkerClient* aClient) +{ + mClient = aClient; +} + +void +ExtendableMessageEvent::SetSource(ServiceWorker* aServiceWorker) +{ + mServiceWorker = aServiceWorker; +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(ExtendableMessageEvent) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ExtendableMessageEvent, Event) + tmp->mData.setUndefined(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mClient) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mServiceWorker) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mPorts) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ExtendableMessageEvent, Event) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClient) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorker) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagePort) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPorts) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ExtendableMessageEvent, Event) + NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mData) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ExtendableMessageEvent) +NS_INTERFACE_MAP_END_INHERITING(Event) + +NS_IMPL_ADDREF_INHERITED(ExtendableMessageEvent, Event) +NS_IMPL_RELEASE_INHERITED(ExtendableMessageEvent, Event) + END_WORKERS_NAMESPACE diff --git a/dom/workers/ServiceWorkerEvents.h b/dom/workers/ServiceWorkerEvents.h index 6c27d7816e..a7c5368389 100644 --- a/dom/workers/ServiceWorkerEvents.h +++ b/dom/workers/ServiceWorkerEvents.h @@ -9,6 +9,7 @@ #include "mozilla/dom/Event.h" #include "mozilla/dom/ExtendableEventBinding.h" +#include "mozilla/dom/ExtendableMessageEventBinding.h" #include "mozilla/dom/FetchEventBinding.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/Response.h" @@ -28,6 +29,8 @@ class nsIInterceptedChannel; namespace mozilla { namespace dom { class Blob; +class MessagePort; +class MessagePortList; class Request; class ResponseOrPromise; } // namespace dom @@ -35,8 +38,6 @@ class ResponseOrPromise; BEGIN_WORKERS_NAMESPACE -class ServiceWorkerClient; - class CancelChannelRunnable final : public nsRunnable { nsMainThreadPtrHandle mChannel; @@ -48,78 +49,6 @@ public: NS_IMETHOD Run() override; }; -class FetchEvent final : public Event -{ - nsMainThreadPtrHandle mChannel; - RefPtr mClient; - RefPtr mRequest; - nsCString mScriptSpec; - UniquePtr mClientInfo; - RefPtr mPromise; - bool mIsReload; - bool mWaitToRespond; -protected: - explicit FetchEvent(EventTarget* aOwner); - ~FetchEvent(); - -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchEvent, Event) - NS_FORWARD_TO_EVENT - - virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle aGivenProto) override - { - return FetchEventBinding::Wrap(aCx, this, aGivenProto); - } - - void PostInit(nsMainThreadPtrHandle& aChannel, - const nsACString& aScriptSpec, - UniquePtr&& aClientInfo); - - static already_AddRefed - Constructor(const GlobalObject& aGlobal, - const nsAString& aType, - const FetchEventInit& aOptions, - ErrorResult& aRv); - - bool - WaitToRespond() const - { - return mWaitToRespond; - } - - Request* - Request_() const - { - return mRequest; - } - - already_AddRefed - GetClient(); - - bool - IsReload() const - { - return mIsReload; - } - - void - RespondWith(Promise& aArg, ErrorResult& aRv); - - already_AddRefed - GetPromise() const - { - RefPtr p = mPromise; - return p.forget(); - } - - already_AddRefed - ForwardTo(const nsAString& aUrl); - - already_AddRefed - Default(); -}; - class ExtendableEvent : public Event { nsTArray> mPromises; @@ -172,6 +101,64 @@ public: } }; +class FetchEvent final : public ExtendableEvent +{ + nsMainThreadPtrHandle mChannel; + RefPtr mRequest; + nsCString mScriptSpec; + bool mIsReload; + bool mWaitToRespond; +protected: + explicit FetchEvent(EventTarget* aOwner); + ~FetchEvent(); + +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchEvent, ExtendableEvent) + NS_FORWARD_TO_EVENT + + virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle aGivenProto) override + { + return FetchEventBinding::Wrap(aCx, this, aGivenProto); + } + + void PostInit(nsMainThreadPtrHandle& aChannel, + const nsACString& aScriptSpec); + + static already_AddRefed + Constructor(const GlobalObject& aGlobal, + const nsAString& aType, + const FetchEventInit& aOptions, + ErrorResult& aRv); + + bool + WaitToRespond() const + { + return mWaitToRespond; + } + + Request* + GetRequest_() const + { + return mRequest; + } + + bool + IsReload() const + { + return mIsReload; + } + + void + RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv); + + already_AddRefed + ForwardTo(const nsAString& aUrl); + + already_AddRefed + Default(); +}; + #ifndef MOZ_SIMPLEPUSH class PushMessageData final : public nsISupports, @@ -250,5 +237,71 @@ public: }; #endif /* ! MOZ_SIMPLEPUSH */ +class ExtendableMessageEvent final : public ExtendableEvent +{ + JS::Heap mData; + nsString mOrigin; + nsString mLastEventId; + RefPtr mClient; + RefPtr mServiceWorker; + RefPtr mMessagePort; + RefPtr mPorts; + +protected: + explicit ExtendableMessageEvent(EventTarget* aOwner); + ~ExtendableMessageEvent(); + +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ExtendableMessageEvent, + ExtendableEvent) + + NS_FORWARD_TO_EVENT + + virtual JSObject* WrapObjectInternal( + JSContext* aCx, JS::Handle aGivenProto) override + { + return mozilla::dom::ExtendableMessageEventBinding::Wrap(aCx, this, aGivenProto); + } + + static already_AddRefed + Constructor(mozilla::dom::EventTarget* aOwner, + const nsAString& aType, + const ExtendableMessageEventInit& aOptions, + ErrorResult& aRv); + + static already_AddRefed + Constructor(const GlobalObject& aGlobal, + const nsAString& aType, + const ExtendableMessageEventInit& aOptions, + ErrorResult& aRv); + + void GetData(JSContext* aCx, JS::MutableHandle aData, + ErrorResult& aRv); + + void GetSource(Nullable& aValue) const; + + NS_IMETHOD GetOrigin(nsAString& aOrigin) + { + aOrigin = mOrigin; + return NS_OK; + } + + NS_IMETHOD GetLastEventId(nsAString& aLastEventId) + { + aLastEventId = mLastEventId; + return NS_OK; + } + + MessagePortList* GetPorts() const; + + void SetPorts(MessagePortList* aPorts); + + void SetSource(ServiceWorkerClient* aClient); + + void SetSource(ServiceWorker* aServiceWorker); +}; + END_WORKERS_NAMESPACE + #endif /* mozilla_dom_workers_serviceworkerevents_h__ */ diff --git a/dom/workers/ServiceWorkerMessageEvent.cpp b/dom/workers/ServiceWorkerMessageEvent.cpp index 2bd2fa17f3..fab9e1d2ea 100644 --- a/dom/workers/ServiceWorkerMessageEvent.cpp +++ b/dom/workers/ServiceWorkerMessageEvent.cpp @@ -142,10 +142,7 @@ ServiceWorkerMessageEvent::Constructor(EventTarget* aEventTarget, RefPtr event = new ServiceWorkerMessageEvent(aEventTarget, nullptr, nullptr); - aRv = event->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } + event->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); bool trusted = event->Init(aEventTarget); event->SetTrusted(trusted); diff --git a/dom/workers/ServiceWorkerPrivate.cpp b/dom/workers/ServiceWorkerPrivate.cpp index e8e12de2ef..57882532dc 100644 --- a/dom/workers/ServiceWorkerPrivate.cpp +++ b/dom/workers/ServiceWorkerPrivate.cpp @@ -5,16 +5,21 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ServiceWorkerPrivate.h" - #include "ServiceWorkerManager.h" +#include "nsStreamUtils.h" +#include "nsStringStream.h" +#include "mozilla/dom/FetchUtil.h" + +#include "nsIConsoleReportCollector.h" +#include "nsIScriptError.h" +#include "nsIScriptError.h" using namespace mozilla; using namespace mozilla::dom; BEGIN_WORKERS_NAMESPACE -#define SERVICE_WORKER_IDLE_TIMEOUT 30000 // ms -#define SERVICE_WORKER_WAITUNTIL_TIMEOUT 300000 // ms +NS_IMPL_ISUPPORTS0(ServiceWorkerPrivate) // Tracks the "dom.disable_open_click_delay" preference. Modified on main // thread, read on worker threads. @@ -547,19 +552,22 @@ public: { MOZ_ASSERT(aWorkerPrivate); - WorkerGlobalScope* globalScope = aWorkerPrivate->GlobalScope(); + RefPtr target = aWorkerPrivate->GlobalScope(); - RefPtr event = NS_NewDOMEvent(globalScope, nullptr, nullptr); + ExtendableEventInit init; + init.mBubbles = false; + init.mCancelable = false; - nsresult rv = event->InitEvent(NS_LITERAL_STRING("pushsubscriptionchange"), - false, false); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } + RefPtr event = + ExtendableEvent::Constructor(target, + NS_LITERAL_STRING("pushsubscriptionchange"), + init); event->SetTrusted(true); - globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr); + DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(), + event, nullptr); + return true; } }; @@ -903,7 +911,6 @@ class FetchEventRunnable : public ExtendableFunctionalEventWorkerRunnable const nsCString mScriptSpec; nsTArray mHeaderNames; nsTArray mHeaderValues; - UniquePtr mClientInfo; nsCString mSpec; nsCString mMethod; bool mIsReload; @@ -928,7 +935,6 @@ public: aWorkerPrivate, aKeepAliveToken, aRegistration) , mInterceptedChannel(aChannel) , mScriptSpec(aScriptSpec) - , mClientInfo(Move(aClientInfo)) , mIsReload(aIsReload) , mIsHttpChannel(false) , mRequestMode(RequestMode::No_cors) @@ -1019,8 +1025,17 @@ public: nsCOMPtr uploadChannel = do_QueryInterface(httpChannel); if (uploadChannel) { MOZ_ASSERT(!mUploadStream); - rv = uploadChannel->CloneUploadStream(getter_AddRefs(mUploadStream)); + bool bodyHasHeaders = false; + rv = uploadChannel->GetUploadStreamHasHeaders(&bodyHasHeaders); NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr uploadStream; + rv = uploadChannel->CloneUploadStream(getter_AddRefs(uploadStream)); + NS_ENSURE_SUCCESS(rv, rv); + if (bodyHasHeaders) { + HandleBodyWithHeaders(uploadStream); + } else { + mUploadStream = uploadStream; + } } } else { nsCOMPtr jarChannel = do_QueryInterface(channel); @@ -1126,7 +1141,7 @@ private: init.mRequest.Value() = request; init.mBubbles = false; init.mCancelable = true; - init.mIsReload.Construct(mIsReload); + init.mIsReload = mIsReload; RefPtr event = FetchEvent::Constructor(globalObj, NS_LITERAL_STRING("fetch"), init, result); if (NS_WARN_IF(result.Failed())) { @@ -1134,7 +1149,7 @@ private: return false; } - event->PostInit(mInterceptedChannel, mScriptSpec, Move(mClientInfo)); + event->PostInit(mInterceptedChannel, mScriptSpec); event->SetTrusted(true); RefPtr target = do_QueryObject(aWorkerPrivate->GlobalScope()); @@ -1142,7 +1157,21 @@ private: if (NS_WARN_IF(NS_FAILED(rv2)) || !event->WaitToRespond()) { nsCOMPtr runnable; if (event->DefaultPrevented(aCx)) { - runnable = new CancelChannelRunnable(mInterceptedChannel, NS_ERROR_INTERCEPTION_CANCELED); + nsCOMPtr inner; + mInterceptedChannel->GetChannel(getter_AddRefs(inner)); + nsCOMPtr reporter = do_QueryInterface(inner); + if (reporter) { + NS_ConvertUTF8toUTF16 requestURL(mSpec); + reporter->AddConsoleReport(nsIScriptError::errorFlag, + NS_LITERAL_CSTRING("Service Worker Interception"), + nsContentUtils::eDOM_PROPERTIES, + mScriptSpec, 0, 0, + NS_LITERAL_CSTRING("InterceptionCanceledWithURL"), + &requestURL); + + } + runnable = new CancelChannelRunnable(mInterceptedChannel, + NS_ERROR_INTERCEPTION_FAILED); } else { runnable = new ResumeRequest(mInterceptedChannel); } @@ -1150,11 +1179,11 @@ private: MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); } - RefPtr respondWithPromise = event->GetPromise(); - if (respondWithPromise) { + RefPtr waitUntilPromise = event->GetPromise(); + if (waitUntilPromise) { RefPtr keepAliveHandler = new KeepAliveHandler(mKeepAliveToken); - respondWithPromise->AppendNativeHandler(keepAliveHandler); + waitUntilPromise->AppendNativeHandler(keepAliveHandler); } // 9.8.22 If request is a non-subresource request, then: Invoke Soft Update algorithm @@ -1165,6 +1194,52 @@ private: } return true; } + + nsresult + HandleBodyWithHeaders(nsIInputStream* aUploadStream) + { + // We are dealing with an nsMIMEInputStream which uses string input streams + // under the hood, so all of the data is available synchronously. + bool nonBlocking = false; + nsresult rv = aUploadStream->IsNonBlocking(&nonBlocking); + NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(!nonBlocking)) { + return NS_ERROR_NOT_AVAILABLE; + } + nsAutoCString body; + rv = NS_ConsumeStream(aUploadStream, UINT32_MAX, body); + NS_ENSURE_SUCCESS(rv, rv); + + // Extract the headers in the beginning of the buffer + nsAutoCString::const_iterator begin, end; + body.BeginReading(begin); + body.EndReading(end); + const nsAutoCString::const_iterator body_end = end; + nsAutoCString headerName, headerValue; + bool emptyHeader = false; + while (FetchUtil::ExtractHeader(begin, end, headerName, + headerValue, &emptyHeader) && + !emptyHeader) { + mHeaderNames.AppendElement(headerName); + mHeaderValues.AppendElement(headerValue); + headerName.Truncate(); + headerValue.Truncate(); + } + + // Replace the upload stream with one only containing the body text. + nsCOMPtr strStream = + do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + // Skip past the "\r\n" that separates the headers and the body. + ++begin; + ++begin; + body.Assign(Substring(begin, body_end)); + rv = strStream->SetData(body.BeginReading(), body.Length()); + NS_ENSURE_SUCCESS(rv, rv); + mUploadStream = strStream; + + return NS_OK; + } }; NS_IMPL_ISUPPORTS_INHERITED(FetchEventRunnable, WorkerRunnable, nsIHttpHeaderVisitor) @@ -1323,6 +1398,13 @@ ServiceWorkerPrivate::TerminateWorker() mIdleWorkerTimer->Cancel(); mKeepAliveToken = nullptr; if (mWorkerPrivate) { + if (Preferences::GetBool("dom.serviceWorkers.testing.enabled")) { + nsCOMPtr os = services::GetObserverService(); + if (os) { + os->NotifyObservers(this, "service-worker-shutdown", nullptr); + } + } + AutoJSAPI jsapi; jsapi.Init(); NS_WARN_IF(!mWorkerPrivate->Terminate(jsapi.cx())); @@ -1366,10 +1448,11 @@ ServiceWorkerPrivate::NoteIdleWorkerCallback(nsITimer* aTimer, void* aPrivate) // If we still have a workerPrivate at this point it means there are pending // waitUntil promises. Wait a bit more until we forcibly terminate the // worker. + uint32_t timeout = Preferences::GetInt("dom.serviceWorkers.idle_extended_timeout"); DebugOnly rv = swp->mIdleWorkerTimer->InitWithFuncCallback(ServiceWorkerPrivate::TerminateWorkerCallback, aPrivate, - SERVICE_WORKER_WAITUNTIL_TIMEOUT, + timeout, nsITimer::TYPE_ONE_SHOT); MOZ_ASSERT(NS_SUCCEEDED(rv)); } @@ -1400,9 +1483,10 @@ ServiceWorkerPrivate::ResetIdleTimeout(WakeUpReason aWhy) mIsPushWorker = true; } + uint32_t timeout = Preferences::GetInt("dom.serviceWorkers.idle_timeout"); DebugOnly rv = mIdleWorkerTimer->InitWithFuncCallback(ServiceWorkerPrivate::NoteIdleWorkerCallback, - this, SERVICE_WORKER_IDLE_TIMEOUT, + this, timeout, nsITimer::TYPE_ONE_SHOT); MOZ_ASSERT(NS_SUCCEEDED(rv)); if (!mKeepAliveToken) { diff --git a/dom/workers/ServiceWorkerPrivate.h b/dom/workers/ServiceWorkerPrivate.h index d619da9ef7..9ec69ecef2 100644 --- a/dom/workers/ServiceWorkerPrivate.h +++ b/dom/workers/ServiceWorkerPrivate.h @@ -34,9 +34,10 @@ public: // object which can be cancelled if no events are received for a certain // amount of time. The worker is kept alive by holding a |KeepAliveToken| // reference. +// // Extendable events hold tokens for the duration of their handler execution // and until their waitUntil promise is resolved, while ServiceWorkerPrivate -// will hold a token for |SERVICE_WORKER_IDLE_TIMEOUT| seconds after each +// will hold a token for |dom.serviceWorkers.idle_timeout| seconds after each // new event. // // Note: All timer events must be handled on the main thread because the @@ -45,7 +46,7 @@ public: // // There are 3 cases where we may ignore keep alive tokens: // 1. When ServiceWorkerPrivate's token expired, if there are still waitUntil -// handlers holding tokens, we wait another |SERVICE_WORKER_WAITUNTIL_TIMEOUT| +// handlers holding tokens, we wait another |dom.serviceWorkers.idle_extended_timeout| // seconds before forcibly terminating the worker. // 2. If the worker stopped controlling documents and it is not handling push // events. @@ -55,12 +56,12 @@ public: // with an appropriate reason before any runnable is dispatched to the worker. // If the event is extendable then the runnable should inherit // ExtendableEventWorkerRunnable. -class ServiceWorkerPrivate final +class ServiceWorkerPrivate final : public nsISupports { friend class KeepAliveToken; public: - NS_INLINE_DECL_REFCOUNTING(ServiceWorkerPrivate) + NS_DECL_ISUPPORTS explicit ServiceWorkerPrivate(ServiceWorkerInfo* aInfo); @@ -172,7 +173,7 @@ private: // is created. bool mIsPushWorker; - // We keep a token for |SERVICE_WORKER_IDLE_TIMEOUT| seconds to give the + // We keep a token for |dom.serviceWorkers.idle_timeout| seconds to give the // worker a grace period after each event. RefPtr mKeepAliveToken; diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 5f1df809d2..b70a687287 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -493,7 +493,9 @@ private: virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { - if (!scriptloader::LoadMainScript(aCx, mScriptURL, WorkerScript)) { + ErrorResult rv; + scriptloader::LoadMainScript(aCx, mScriptURL, WorkerScript, rv); + if (NS_WARN_IF(rv.Failed())) { return false; } @@ -526,8 +528,14 @@ private: JS::Rooted global(aCx, globalScope->GetWrapper()); + ErrorResult rv; JSAutoCompartment ac(aCx, global); - return scriptloader::LoadMainScript(aCx, mScriptURL, DebuggerScript); + scriptloader::LoadMainScript(aCx, mScriptURL, DebuggerScript, rv); + if (NS_WARN_IF(rv.Failed())) { + return false; + } + + return true; } }; @@ -564,12 +572,7 @@ private: RefPtr event = NS_NewDOMEvent(globalScope, nullptr, nullptr); - nsresult rv = event->InitEvent(NS_LITERAL_STRING("close"), false, false); - if (NS_FAILED(rv)) { - Throw(aCx, rv); - return false; - } - + event->InitEvent(NS_LITERAL_STRING("close"), false, false); event->SetTrusted(true); globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr); @@ -577,6 +580,13 @@ private: return true; } + NS_IMETHOD Cancel() override + { + // We need to run regardless. + Run(); + return WorkerRunnable::Cancel(); + } + virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult) override @@ -654,31 +664,53 @@ public: return false; } - RefPtr event = new MessageEvent(aTarget, nullptr, nullptr); - rv = event->InitMessageEvent(NS_LITERAL_STRING("message"), - false /* non-bubbling */, - false /* cancelable */, - messageData, - EmptyString(), - EmptyString(), - nullptr); + nsTArray> ports = TakeTransferredPorts(); + + nsCOMPtr domEvent; + // For messages dispatched to service worker, use ExtendableMessageEvent + // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#extendablemessage-event-section if (mEventSource) { RefPtr client = new ServiceWorkerWindowClient(aTarget, *mEventSource); + + RootedDictionary init(aCx); + + init.mBubbles = false; + init.mCancelable = false; + + init.mData = messageData; + init.mPorts.Construct(); + init.mPorts.Value().SetNull(); + + ErrorResult rv; + RefPtr event = ExtendableMessageEvent::Constructor( + aTarget, NS_LITERAL_STRING("message"), init, rv); + if (NS_WARN_IF(rv.Failed())) { + return false; + } event->SetSource(client); + event->SetPorts(new MessagePortList(static_cast(event.get()), + ports)); + domEvent = do_QueryObject(event); + } else { + RefPtr event = new MessageEvent(aTarget, nullptr, nullptr); + nsresult rv = event->InitMessageEvent(NS_LITERAL_STRING("message"), + false /* non-bubbling */, + false /* cancelable */, + messageData, + EmptyString(), + EmptyString(), + nullptr); + if (NS_WARN_IF(NS_FAILED(rv))) { + xpc::Throw(aCx, rv); + return false; + } + event->SetPorts(new MessagePortList(static_cast(event.get()), + ports)); + domEvent = do_QueryObject(event); } - if (NS_WARN_IF(rv.Failed())) { - xpc::Throw(aCx, rv.StealNSResult()); - return false; - } - - nsTArray> ports = TakeTransferredPorts(); - - event->SetTrusted(true); - event->SetPorts(new MessagePortList(static_cast(event.get()), - ports)); - nsCOMPtr domEvent = do_QueryObject(event); + domEvent->SetTrusted(true); nsEventStatus dummy = nsEventStatus_eIgnore; aTarget->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy); @@ -696,7 +728,8 @@ private: return true; } - if (aWorkerPrivate->IsFrozen()) { + if (aWorkerPrivate->IsFrozen() || aWorkerPrivate->IsSuspended()) { + MOZ_ASSERT(!IsDebuggerRunnable()); aWorkerPrivate->QueueRunnable(this); return true; } @@ -815,7 +848,7 @@ private: { // This busy count will be matched by the CloseEventRunnable. return aWorkerPrivate->ModifyBusyCount(aCx, true) && - aWorkerPrivate->Close(aCx); + aWorkerPrivate->Close(); } }; @@ -859,6 +892,7 @@ class ReportErrorRunnable final : public WorkerRunnable uint32_t mFlags; uint32_t mErrorNumber; JSExnType mExnType; + bool mMutedError; public: // aWorkerPrivate is the worker thread we're on (or the main thread, if null) @@ -870,12 +904,12 @@ public: const nsString& aMessage, const nsString& aFilename, const nsString& aLine, uint32_t aLineNumber, uint32_t aColumnNumber, uint32_t aFlags, - uint32_t aErrorNumber, JSExnType aExnType, uint64_t aInnerWindowId) + uint32_t aErrorNumber, JSExnType aExnType, + bool aMutedError, uint64_t aInnerWindowId) { if (aWorkerPrivate) { aWorkerPrivate->AssertIsOnWorkerThread(); - } - else { + } else { AssertIsOnMainThread(); } @@ -896,11 +930,17 @@ public: if (!JSREPORT_IS_WARNING(aFlags)) { // First fire an ErrorEvent at the worker. RootedDictionary init(aCx); - init.mMessage = aMessage; - init.mFilename = aFilename; - init.mLineno = aLineNumber; + + if (aMutedError) { + init.mMessage.AssignLiteral("Script error."); + } else { + init.mMessage = aMessage; + init.mFilename = aFilename; + init.mLineno = aLineNumber; + } + init.mCancelable = true; - init.mBubbles = true; + init.mBubbles = false; if (aTarget) { RefPtr event = @@ -975,7 +1015,7 @@ public: RefPtr runnable = new ReportErrorRunnable(aWorkerPrivate, aMessage, aFilename, aLine, aLineNumber, aColumnNumber, aFlags, - aErrorNumber, aExnType); + aErrorNumber, aExnType, aMutedError); return runnable->Dispatch(aCx); } @@ -990,11 +1030,11 @@ private: const nsString& aFilename, const nsString& aLine, uint32_t aLineNumber, uint32_t aColumnNumber, uint32_t aFlags, uint32_t aErrorNumber, - JSExnType aExnType) + JSExnType aExnType, bool aMutedError) : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount), mMessage(aMessage), mFilename(aFilename), mLine(aLine), mLineNumber(aLineNumber), mColumnNumber(aColumnNumber), mFlags(aFlags), - mErrorNumber(aErrorNumber), mExnType(aExnType) + mErrorNumber(aErrorNumber), mExnType(aExnType), mMutedError(aMutedError) { } virtual void @@ -1024,7 +1064,8 @@ private: else { AssertIsOnMainThread(); - if (aWorkerPrivate->IsFrozen()) { + if (aWorkerPrivate->IsFrozen() || aWorkerPrivate->IsSuspended()) { + MOZ_ASSERT(!IsDebuggerRunnable()); aWorkerPrivate->QueueRunnable(this); return true; } @@ -1067,7 +1108,7 @@ private: return ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mMessage, mFilename, mLine, mLineNumber, mColumnNumber, mFlags, - mErrorNumber, mExnType, innerWindowId); + mErrorNumber, mExnType, mMutedError, innerWindowId); } }; @@ -1255,6 +1296,13 @@ private: return true; } + + NS_IMETHOD Cancel() override + { + // We need to run regardless. + Run(); + return WorkerRunnable::Cancel(); + } }; class UpdateRuntimeOptionsRunnable final : public WorkerControlRunnable @@ -2111,8 +2159,8 @@ WorkerPrivateParent::WorkerPrivateParent( mParent(aParent), mScriptURL(aScriptURL), mWorkerName(aWorkerName), mLoadingWorkerScript(false), mBusyCount(0), mParentStatus(Pending), mParentFrozen(false), - mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false), - mWorkerType(aWorkerType), + mParentSuspended(false), mIsChromeWorker(aIsChromeWorker), + mMainThreadObjectsForgotten(false), mWorkerType(aWorkerType), mCreationTimeStamp(TimeStamp::Now()), mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC) { @@ -2579,7 +2627,7 @@ WorkerPrivateParent::Thaw(JSContext* aCx, nsPIDOMWindow* aWindow) // Execute queued runnables before waking up the worker, otherwise the worker // could post new messages before we run those that have been queued. - if (!mQueuedRunnables.IsEmpty()) { + if (!IsSuspended() && !mQueuedRunnables.IsEmpty()) { AssertIsOnMainThread(); MOZ_ASSERT(IsDedicatedWorker()); @@ -2600,9 +2648,53 @@ WorkerPrivateParent::Thaw(JSContext* aCx, nsPIDOMWindow* aWindow) return true; } +template +void +WorkerPrivateParent::Suspend() +{ + AssertIsOnMainThread(); + + MOZ_ASSERT(!mParentSuspended, "Suspended more than once!"); + + mParentSuspended = true; +} + +template +void +WorkerPrivateParent::Resume() +{ + AssertIsOnMainThread(); + + MOZ_ASSERT(mParentSuspended, "Resumed more than once!"); + + mParentSuspended = false; + + { + MutexAutoLock lock(mMutex); + + if (mParentStatus >= Terminating) { + return; + } + } + + // Execute queued runnables before waking up, otherwise the worker could post + // new messages before we run those that have been queued. + if (!IsFrozen() && !mQueuedRunnables.IsEmpty()) { + AssertIsOnMainThread(); + MOZ_ASSERT(IsDedicatedWorker()); + + nsTArray> runnables; + mQueuedRunnables.SwapElements(runnables); + + for (uint32_t index = 0; index < runnables.Length(); index++) { + runnables[index]->Run(); + } + } +} + template bool -WorkerPrivateParent::Close(JSContext* aCx) +WorkerPrivateParent::Close() { AssertIsOnParentThread(); @@ -2962,9 +3054,7 @@ WorkerPrivate::OfflineStatusChangeEventInternal(JSContext* aCx, bool aIsOffline) RefPtr event = NS_NewDOMEvent(globalScope, nullptr, nullptr); - nsresult rv = event->InitEvent(eventType, false, false); - NS_ENSURE_SUCCESS_VOID(rv); - + event->InitEvent(eventType, false, false); event->SetTrusted(true); globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr); @@ -3855,6 +3945,7 @@ WorkerPrivate::WorkerPrivate(JSContext* aCx, , mRunningExpiredTimeouts(false) , mCloseHandlerStarted(false) , mCloseHandlerFinished(false) + , mPendingEventQueueClearing(false) , mMemoryReporterRunning(false) , mBlockedForMemoryReporter(false) , mCancelAllPendingRunnables(false) @@ -3981,7 +4072,8 @@ WorkerPrivate::Constructor(JSContext* aCx, aIsChromeWorker, InheritLoadGroup, aWorkerType, stackLoadInfo.ptr()); if (NS_FAILED(rv)) { - scriptloader::ReportLoadError(aCx, aScriptURL, rv, !parent); + // XXXkhuey this is weird, why throw again after setting an exception? + scriptloader::ReportLoadError(aCx, rv); aRv.Throw(rv); return nullptr; } @@ -4684,6 +4776,7 @@ WorkerPrivate::ScheduleDeletion(WorkerRanOrNot aRanOrNot) AssertIsOnWorkerThread(); MOZ_ASSERT(mChildWorkers.IsEmpty()); MOZ_ASSERT(mSyncLoopStack.IsEmpty()); + MOZ_ASSERT(!mPendingEventQueueClearing); ClearMainEventQueue(aRanOrNot); #ifdef DEBUG @@ -4923,6 +5016,7 @@ WorkerPrivate::ClearMainEventQueue(WorkerRanOrNot aRanOrNot) { AssertIsOnWorkerThread(); + MOZ_ASSERT(!mSyncLoopStack.Length()); MOZ_ASSERT(!mCancelAllPendingRunnables); mCancelAllPendingRunnables = true; @@ -5285,6 +5379,11 @@ WorkerPrivate::DestroySyncLoop(uint32_t aLoopIndex, nsIThreadInternal* aThread) MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aThread->PopEventQueue(nestedEventTarget))); + if (!mSyncLoopStack.Length() && mPendingEventQueueClearing) { + ClearMainEventQueue(WorkerRan); + mPendingEventQueueClearing = false; + } + return result; } @@ -5573,7 +5672,13 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus) // If this is the first time our status has changed then we need to clear the // main event queue. if (previousStatus == Running) { - ClearMainEventQueue(WorkerRan); + // NB: If we're in a sync loop, we can't clear the queue immediately, + // because this is the wrong queue. So we have to defer it until later. + if (mSyncLoopStack.Length()) { + mPendingEventQueueClearing = true; + } else { + ClearMainEventQueue(WorkerRan); + } } // If we've run the close handler, we don't need to do anything else. @@ -5683,6 +5788,7 @@ WorkerPrivate::ReportError(JSContext* aCx, const char* aMessage, nsString message, filename, line; uint32_t lineNumber, columnNumber, flags, errorNumber; JSExnType exnType = JSEXN_ERR; + bool mutedError = aReport && aReport->isMuted; if (aReport) { // ErrorEvent objects don't have a |name| field the way ES |Error| objects @@ -5727,7 +5833,8 @@ WorkerPrivate::ReportError(JSContext* aCx, const char* aMessage, if (!ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, message, filename, line, lineNumber, - columnNumber, flags, errorNumber, exnType, 0)) { + columnNumber, flags, errorNumber, exnType, + mutedError, 0)) { JS_ReportPendingException(aCx); } diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index ba6f3949b7..ddf9bd6449 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -185,6 +185,7 @@ private: uint64_t mBusyCount; Status mParentStatus; bool mParentFrozen; + bool mParentSuspended; bool mIsChromeWorker; bool mMainThreadObjectsForgotten; WorkerType mWorkerType; @@ -305,6 +306,12 @@ public: bool Thaw(JSContext* aCx, nsPIDOMWindow* aWindow); + void + Suspend(); + + void + Resume(); + bool Terminate(JSContext* aCx) { @@ -313,7 +320,7 @@ public: } bool - Close(JSContext* aCx); + Close(); bool ModifyBusyCount(JSContext* aCx, bool aIncrease); @@ -399,6 +406,13 @@ public: return mParentFrozen; } + bool + IsSuspended() const + { + AssertIsOnParentThread(); + return mParentSuspended; + } + bool IsAcceptingEvents() { @@ -944,6 +958,7 @@ class WorkerPrivate : public WorkerPrivateParent bool mRunningExpiredTimeouts; bool mCloseHandlerStarted; bool mCloseHandlerFinished; + bool mPendingEventQueueClearing; bool mMemoryReporterRunning; bool mBlockedForMemoryReporter; bool mCancelAllPendingRunnables; diff --git a/dom/workers/Workers.h b/dom/workers/Workers.h index ccfb177ff1..bbf345a3fa 100644 --- a/dom/workers/Workers.h +++ b/dom/workers/Workers.h @@ -294,6 +294,12 @@ FreezeWorkersForWindow(nsPIDOMWindow* aWindow); void ThawWorkersForWindow(nsPIDOMWindow* aWindow); +void +SuspendWorkersForWindow(nsPIDOMWindow* aWindow); + +void +ResumeWorkersForWindow(nsPIDOMWindow* aWindow); + class WorkerTask { protected: diff --git a/dom/workers/test/WorkerDebugger_suspended_debugger.js b/dom/workers/test/WorkerDebugger_suspended_debugger.js new file mode 100644 index 0000000000..2ed4e16c44 --- /dev/null +++ b/dom/workers/test/WorkerDebugger_suspended_debugger.js @@ -0,0 +1,6 @@ +"use strict"; + +var dbg = new Debugger(global); +dbg.onDebuggerStatement = function (frame) { + postMessage("debugger"); +}; diff --git a/dom/workers/test/WorkerDebugger_suspended_worker.js b/dom/workers/test/WorkerDebugger_suspended_worker.js new file mode 100644 index 0000000000..c096be7e46 --- /dev/null +++ b/dom/workers/test/WorkerDebugger_suspended_worker.js @@ -0,0 +1,6 @@ +"use strict"; + +self.onmessage = function () { + postMessage("worker"); + debugger; +}; diff --git a/dom/workers/test/chrome.ini b/dom/workers/test/chrome.ini index 876e5b5037..5579c7355a 100644 --- a/dom/workers/test/chrome.ini +++ b/dom/workers/test/chrome.ini @@ -27,6 +27,8 @@ support-files = WorkerDebugger_childWorker.js WorkerDebugger_worker.js WorkerDebugger_sharedWorker.js + WorkerDebugger_suspended_debugger.js + WorkerDebugger_suspended_worker.js WorkerTest.jsm WorkerTest_subworker.js WorkerTest_worker.js @@ -60,7 +62,7 @@ support-files = [test_WorkerDebuggerGlobalScope.reportError.xul] [test_WorkerDebuggerGlobalScope.setImmediate.xul] [test_WorkerDebuggerManager.xul] -[test_bug883784.jsm] +[test_WorkerDebugger_suspended.xul] [test_bug883784.xul] [test_chromeWorker.xul] [test_chromeWorkerJSM.xul] diff --git a/dom/workers/test/serviceworkers/fetch/fetch_tests.js b/dom/workers/test/serviceworkers/fetch/fetch_tests.js index d5958dff5d..6e67699b5f 100644 --- a/dom/workers/test/serviceworkers/fetch/fetch_tests.js +++ b/dom/workers/test/serviceworkers/fetch/fetch_tests.js @@ -375,3 +375,27 @@ fetch(new Request('empty-header', {headers:{"emptyheader":""}})) my_ok(false, "A promise was rejected with " + err); finish(); }); + +expectAsyncResult(); +fetch('fetchevent-extendable') +.then(function(res) { + return res.text(); +}).then(function(body) { + my_ok(body == "extendable", "FetchEvent inherits from ExtendableEvent"); + finish(); +}, function(err) { + my_ok(false, "A promise was rejected with " + err); + finish(); +}); + +expectAsyncResult(); +fetch('fetchevent-request') +.then(function(res) { + return res.text(); +}).then(function(body) { + my_ok(body == "nullable", "FetchEvent.request must be nullable"); + finish(); +}, function(err) { + my_ok(false, "A promise was rejected with " + err); + finish(); +}); diff --git a/dom/workers/test/serviceworkers/fetch/plugin/worker.js b/dom/workers/test/serviceworkers/fetch/plugin/worker.js index eaf7c4346b..e97d062050 100644 --- a/dom/workers/test/serviceworkers/fetch/plugin/worker.js +++ b/dom/workers/test/serviceworkers/fetch/plugin/worker.js @@ -1,7 +1,14 @@ self.addEventListener("fetch", function(event) { var resource = event.request.url.split('/').pop(); - if (event.client) { - event.client.postMessage({context: event.request.context, - resource: resource}); - } + event.waitUntil( + clients.matchAll() + .then(clients => { + clients.forEach(client => { + if (client.url.includes("plugins.html")) { + client.postMessage({context: event.request.context, + resource: resource}); + } + }); + }) + ); }); diff --git a/dom/workers/test/serviceworkers/fetch_event_client.js b/dom/workers/test/serviceworkers/fetch_event_client.js deleted file mode 100644 index 0296f12ef5..0000000000 --- a/dom/workers/test/serviceworkers/fetch_event_client.js +++ /dev/null @@ -1,6 +0,0 @@ -var CLIENT_URL = - "http://mochi.test:8888/tests/dom/workers/test/serviceworkers/sw_clients/dummy.html" - -self.addEventListener("fetch", function(event) { - event.client.postMessage({status: event.client.url === CLIENT_URL}); -}); diff --git a/dom/workers/test/serviceworkers/fetch_event_worker.js b/dom/workers/test/serviceworkers/fetch_event_worker.js index a64e4b5c7e..0db8a10578 100644 --- a/dom/workers/test/serviceworkers/fetch_event_worker.js +++ b/dom/workers/test/serviceworkers/fetch_event_worker.js @@ -276,4 +276,20 @@ onfetch = function(ev) { } ev.respondWith(new Response("emptyheader")); } + + else if (ev.request.url.includes('fetchevent-extendable')) { + if (ev instanceof ExtendableEvent) { + ev.respondWith(new Response("extendable")); + } else { + ev.respondWith(Promise.reject()); + } + } + + else if (ev.request.url.includes('fetchevent-request')) { + if ((new FetchEvent("foo")).request === null) { + ev.respondWith(new Response("nullable")); + } else { + ev.respondWith(Promise.reject()); + } + } }; diff --git a/dom/workers/test/serviceworkers/importscript_worker.js b/dom/workers/test/serviceworkers/importscript_worker.js index c6873ea6df..b1121ee93f 100644 --- a/dom/workers/test/serviceworkers/importscript_worker.js +++ b/dom/workers/test/serviceworkers/importscript_worker.js @@ -6,6 +6,12 @@ function callByScript() { importScripts(['importscript.sjs']); importScripts(['importscript.sjs']); +try { + importScripts(['there-is-nothing-here.js']); +} catch (ex) { + // Importing a non-existent script should not abort the SW load, bug 1198982. +} + onmessage = function(e) { self.clients.matchAll().then(function(res) { if (!res.length) { diff --git a/dom/workers/test/serviceworkers/mochitest.ini b/dom/workers/test/serviceworkers/mochitest.ini index 6d3ea32510..173041858c 100644 --- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -171,8 +171,6 @@ support-files = opaque_intercept_worker.js notify_loaded.js test_request_context.js - fetch_event_client.js - sw_clients/dummy.html fetch/plugin/worker.js fetch/plugin/plugins.html eventsource/* @@ -269,7 +267,6 @@ skip-if = toolkit == "android" || toolkit == "gonk" [test_workerUpdate.html] [test_workerupdatefoundevent.html] [test_opaque_intercept.html] -[test_fetch_event_client_postmessage.html] [test_xslt.html] [test_escapedSlashes.html] [test_eventsource_intercept.html] diff --git a/dom/workers/test/serviceworkers/source_message_posting_worker.js b/dom/workers/test/serviceworkers/source_message_posting_worker.js index ab8c085daf..36ce951fec 100644 --- a/dom/workers/test/serviceworkers/source_message_posting_worker.js +++ b/dom/workers/test/serviceworkers/source_message_posting_worker.js @@ -3,6 +3,10 @@ onmessage = function(e) { dump("ERROR: message doesn't have a source."); } + if (!(e instanceof ExtendableMessageEvent)) { + e.source.postMessage("ERROR. event is not an extendable message event."); + } + // The client should be a window client if (e.source instanceof WindowClient) { e.source.postMessage(e.data); diff --git a/dom/workers/test/serviceworkers/sw_clients/dummy.html b/dom/workers/test/serviceworkers/sw_clients/dummy.html deleted file mode 100644 index bfdb5f8318..0000000000 --- a/dom/workers/test/serviceworkers/sw_clients/dummy.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Bug 1158735 - Dummy page - - - - - diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js index 669dacc6c3..858be3d56d 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js @@ -117,6 +117,8 @@ var interfaceNamesInGlobalScope = "EventTarget", // IMPORTANT: Do not change this list without review from a DOM peer! "ExtendableEvent", +// IMPORTANT: Do not change this list without review from a DOM peer! + "ExtendableMessageEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "FetchEvent", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/workers/test/serviceworkers/unresolved_fetch_worker.js b/dom/workers/test/serviceworkers/unresolved_fetch_worker.js index 8ce9d549c5..993ff2fc25 100644 --- a/dom/workers/test/serviceworkers/unresolved_fetch_worker.js +++ b/dom/workers/test/serviceworkers/unresolved_fetch_worker.js @@ -1,9 +1,12 @@ onfetch = function(event) { - if (!event.client) { - dump("ERROR: event doesnt have a client"); - } - - event.client.postMessage("continue"); + event.waitUntil( + clients.matchAll() + .then(clients => { + clients.forEach(client => { + client.postMessage("continue"); + }); + }) + ); // never resolve event.respondWith(new Promise(function(res, rej) {})); diff --git a/dom/workers/test/test_WorkerDebugger_suspended.xul b/dom/workers/test/test_WorkerDebugger_suspended.xul new file mode 100644 index 0000000000..0ed8bb71ae --- /dev/null +++ b/dom/workers/test/test_WorkerDebugger_suspended.xul @@ -0,0 +1,75 @@ + + + + + + + +

+ +

+  
+  
diff --git a/dom/xml/nsXMLPrettyPrinter.cpp b/dom/xml/nsXMLPrettyPrinter.cpp index 9f0f8c5e12..c2746f2794 100644 --- a/dom/xml/nsXMLPrettyPrinter.cpp +++ b/dom/xml/nsXMLPrettyPrinter.cpp @@ -101,7 +101,9 @@ nsXMLPrettyPrinter::PrettyPrint(nsIDocument* aDocument, NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr xslDocument; - rv = nsSyncLoadService::LoadDocument(xslUri, nsContentUtils::GetSystemPrincipal(), + rv = nsSyncLoadService::LoadDocument(xslUri, nsIContentPolicy::TYPE_XSLT, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, nullptr, true, mozilla::net::RP_Default, getter_AddRefs(xslDocument)); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/xslt/xml/txXMLParser.cpp b/dom/xslt/xml/txXMLParser.cpp index 7f7facb0f4..0cf281f2cf 100644 --- a/dom/xslt/xml/txXMLParser.cpp +++ b/dom/xslt/xml/txXMLParser.cpp @@ -15,8 +15,10 @@ #include "nsIPrincipal.h" nsresult -txParseDocumentFromURI(const nsAString& aHref, const txXPathNode& aLoader, - nsAString& aErrMsg, txXPathNode** aResult) +txParseDocumentFromURI(const nsAString& aHref, + const txXPathNode& aLoader, + nsAString& aErrMsg, + txXPathNode** aResult) { NS_ENSURE_ARG_POINTER(aResult); *aResult = nullptr; @@ -36,7 +38,9 @@ txParseDocumentFromURI(const nsAString& aHref, const txXPathNode& aLoader, nsIDOMDocument* theDocument = nullptr; nsAutoSyncOperation sync(loaderDocument); rv = nsSyncLoadService::LoadDocument(documentURI, + nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, loaderDocument->NodePrincipal(), + nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS, loadGroup, true, loaderDocument->GetReferrerPolicy(), &theDocument); diff --git a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp index 2250f1e56f..dde45ac1d9 100644 --- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp +++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp @@ -629,20 +629,6 @@ txSyncCompileObserver::loadURI(const nsAString& aUri, getter_AddRefs(referrerPrincipal)); NS_ENSURE_SUCCESS(rv, rv); - // Content Policy - int16_t shouldLoad = nsIContentPolicy::ACCEPT; - rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_INTERNAL_STYLESHEET, - uri, - referrerPrincipal, - nullptr, - NS_LITERAL_CSTRING("application/xml"), - nullptr, - &shouldLoad); - NS_ENSURE_SUCCESS(rv, rv); - if (NS_CP_REJECTED(shouldLoad)) { - return NS_ERROR_DOM_BAD_URI; - } - // This is probably called by js, a loadGroup for the channel doesn't // make sense. nsCOMPtr source; @@ -652,8 +638,12 @@ txSyncCompileObserver::loadURI(const nsAString& aUri, } nsAutoSyncOperation sync(source ? source->OwnerDoc() : nullptr); nsCOMPtr document; - rv = nsSyncLoadService::LoadDocument(uri, referrerPrincipal, nullptr, - false, aReferrerPolicy, + + rv = nsSyncLoadService::LoadDocument(uri, nsIContentPolicy::TYPE_XSLT, + referrerPrincipal, + nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS, + nullptr, false, + aReferrerPolicy, getter_AddRefs(document)); NS_ENSURE_SUCCESS(rv, rv); diff --git a/embedding/components/windowwatcher/nsAutoWindowStateHelper.cpp b/embedding/components/windowwatcher/nsAutoWindowStateHelper.cpp index e5ef170483..919e9d0aa4 100644 --- a/embedding/components/windowwatcher/nsAutoWindowStateHelper.cpp +++ b/embedding/components/windowwatcher/nsAutoWindowStateHelper.cpp @@ -60,9 +60,7 @@ nsAutoWindowStateHelper::DispatchEventToChrome(const char* aEventName) if (rv.Failed()) { return false; } - NS_ENSURE_TRUE(NS_SUCCEEDED(event->InitEvent( - NS_ConvertASCIItoUTF16(aEventName), true, true)), - false); + event->InitEvent(NS_ConvertASCIItoUTF16(aEventName), true, true); event->SetTrusted(true); event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true; diff --git a/js/src/gc/Tracer.h b/js/src/gc/Tracer.h index 64976ad25d..76ee0fc5fd 100644 --- a/js/src/gc/Tracer.h +++ b/js/src/gc/Tracer.h @@ -123,7 +123,7 @@ TraceGenericPointerRoot(JSTracer* trc, gc::Cell** thingp, const char* name); void TraceManuallyBarrieredGenericPointerEdge(JSTracer* trc, gc::Cell** thingp, const char* name); -// Depricated. Please use one of the strongly typed variants above. +// Deprecated. Please use one of the strongly typed variants above. void TraceChildren(JSTracer* trc, void* thing, JS::TraceKind kind); diff --git a/js/src/jit-test/tests/basic/bug1207863.js b/js/src/jit-test/tests/basic/bug1207863.js new file mode 100644 index 0000000000..a75beba349 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1207863.js @@ -0,0 +1,24 @@ +// |jit-test| allow-oom; allow-unhandlable-oom + +if (!("oomAtAllocation" in this && "resetOOMFailure" in this)) + quit(); + +function oomTest(f) { + var i = 1; + do { + try { + oomAtAllocation(i); + f(); + } catch (e) { + more = resetOOMFailure(); + } + i++; + } while(more); +} +oomTest( + () => 3 + | (function () { + "use strict"; + return eval("f();"); + })() +); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index d03e2a2cb6..9472c49dc4 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4131,7 +4131,7 @@ JS::CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& opt JS_PUBLIC_API(bool) JS::CanCompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t length) { - static const size_t TINY_LENGTH = 1000; + static const size_t TINY_LENGTH = 5 * 1000; static const size_t HUGE_LENGTH = 100 * 1000; // These are heuristics which the caller may choose to ignore (e.g., for diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h index 5c945fbbd9..0eecff6d6c 100644 --- a/js/src/vm/ArgumentsObject.h +++ b/js/src/vm/ArgumentsObject.h @@ -76,7 +76,7 @@ struct ArgumentsData // Maximum supported value of arguments.length. This bounds the maximum // number of arguments that can be supplied to Function.prototype.apply. // This value also bounds the number of elements parsed in an array -// initialiser. +// initializer. static const unsigned ARGS_LENGTH_MAX = 500 * 1000; /* diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 4dd73bd16a..9fa890cc8b 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -1085,6 +1085,8 @@ InnerViewTable::addView(JSContext* cx, ArrayBufferObject* buffer, ArrayBufferVie ReportOutOfMemory(cx); return false; } + // ViewVector has one inline element, so the first insertion is + // guaranteed to succeed. MOZ_ALWAYS_TRUE(p->value().append(view)); } @@ -1141,11 +1143,8 @@ InnerViewTable::sweep(JSRuntime* rt) return; for (Map::Enum e(map); !e.empty(); e.popFront()) { - JSObject* key = e.front().key(); - if (sweepEntry(&key, e.front().value())) + if (sweepEntry(&e.front().mutableKey(), e.front().value())) e.removeFront(); - else if (key != e.front().key()) - e.rekeyFront(key); } } @@ -1156,15 +1155,13 @@ InnerViewTable::sweepAfterMinorGC(JSRuntime* rt) if (nurseryKeysValid) { for (size_t i = 0; i < nurseryKeys.length(); i++) { - JSObject* key = nurseryKeys[i]; - Map::Ptr p = map.lookup(key); + JSObject* buffer = MaybeForwarded(nurseryKeys[i]); + Map::Ptr p = map.lookup(buffer); if (!p) continue; - if (sweepEntry(&key, p->value())) - map.remove(nurseryKeys[i]); - else - map.rekeyIfMoved(nurseryKeys[i], key); + if (sweepEntry(&p->mutableKey(), p->value())) + map.remove(buffer); } nurseryKeys.clear(); } else { diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index 6ab676af38..998ed35bda 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -501,9 +501,17 @@ class InnerViewTable friend class ArrayBufferObject; private: + // This key is a raw pointer and not a ReadBarriered because the post- + // barrier would hold nursery-allocated entries live unconditionally. It is + // a very common pattern in low-level and performance-oriented JavaScript + // to create hundreds or thousands of very short lived temporary views on a + // larger buffer; having to tenured all of these would be a catastrophic + // performance regression. Thus, it is vital that nursery pointers in this + // map not be held live. Special support is required in the minor GC, + // implemented in sweepAfterMinorGC. typedef HashMap, + MovableCellHasher, SystemAllocPolicy> Map; // For all objects sharing their storage with some other view, this maps @@ -511,7 +519,10 @@ class InnerViewTable Map map; // List of keys from innerViews where either the source or at least one - // target is in the nursery. + // target is in the nursery. The raw pointer to a JSObject is allowed here + // because this vector is cleared after every minor collection. Users in + // sweepAfterMinorCollection must be careful to use MaybeForwarded before + // touching these pointers. Vector nurseryKeys; // Whether nurseryKeys is a complete list. diff --git a/js/src/vm/PIC.h b/js/src/vm/PIC.h index 8484fb4dfa..371bb62538 100644 --- a/js/src/vm/PIC.h +++ b/js/src/vm/PIC.h @@ -166,12 +166,12 @@ struct ForOfPIC * * Array.prototype's slot number for @@iterator (arrayProtoIteratorSlot_) * Array.prototype's canonical value for @@iterator (canonicalIteratorFunc_) - * To quickly retreive and ensure that the iterator constructor + * To quickly retrieve and ensure that the iterator constructor * stored in the slot has not changed. * * ArrayIterator.prototype's slot number for 'next' (arrayIteratorProtoNextSlot_) * ArrayIterator.prototype's canonical value for 'next' (canonicalNextFunc_) - * To quickly retreive and ensure that the 'next' method for ArrayIterator + * To quickly retrieve and ensure that the 'next' method for ArrayIterator * objects has not changed. */ class Chain : public BaseChain diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index c3eddb30e1..b0f0c6a3a7 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -604,7 +604,7 @@ JSRuntime::resetJitStackLimit() { // Note that, for now, we use the untrusted limit for ion. This is fine, // because it's the most conservative limit, and if we hit it, we'll bail - // out of ion into the interpeter, which will do a proper recursion check. + // out of ion into the interpreter, which will do a proper recursion check. #ifdef JS_SIMULATOR jitStackLimit_ = jit::Simulator::StackLimit(); #else diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 676be5bcfe..a1b62e537d 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -1035,7 +1035,7 @@ struct JSRuntime : public JS::shadow::Runtime, /* Garbage collector state, used by jsgc.c. */ js::gc::GCRuntime gc; - /* Garbage collector state has been sucessfully initialized. */ + /* Garbage collector state has been successfully initialized. */ bool gcInitialized; int gcZeal() { return gc.zeal(); } @@ -1105,7 +1105,7 @@ struct JSRuntime : public JS::shadow::Runtime, /* Had an out-of-memory error which did not populate an exception. */ bool hadOutOfMemory; - /* We are curently deleting an object due to an initialization failure. */ + /* We are currently deleting an object due to an initialization failure. */ mozilla::DebugOnly handlingInitFailure; /* A context has been created on this runtime. */ diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 2cbac58977..93463b5e4d 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -1427,7 +1427,9 @@ ScopeIter::settle() MOZ_ASSERT(ssi_.type() == StaticScopeIter::Block); incrementStaticScopeIter(); MOZ_ASSERT(ssi_.type() == StaticScopeIter::Eval); + MOZ_ASSERT(maybeStaticScope() == frame_.script()->enclosingStaticScope()); incrementStaticScopeIter(); + frame_ = NullFramePtr(); } // Check if we have left the extent of the initial frame after we've diff --git a/js/src/vm/TraceLogging.h b/js/src/vm/TraceLogging.h index 9ba78edcfb..8212858357 100644 --- a/js/src/vm/TraceLogging.h +++ b/js/src/vm/TraceLogging.h @@ -35,7 +35,7 @@ namespace jit { /* * Tracelogging overview. * - * Tracelogging makes it possible to trace the occurence of a single event and/or + * Tracelogging makes it possible to trace the occurrence of a single event and/or * the start and stop of an event. This is implemented to give an as low overhead as * possible so it doesn't interfere with running. * @@ -47,17 +47,17 @@ namespace jit { * * 2) Optionally create a TraceLoggerEvent for the text that needs to get logged. This * step takes some time, so try to do this beforehand, outside the hot - * path and don't do unnecessary repetitions, since it will criple + * path and don't do unnecessary repetitions, since it will cripple * performance. * - TraceLoggerEvent event(logger, "foo"); * * There are also some predefined events. They are located in * TraceLoggerTextId. They don't require to create an TraceLoggerEvent and * can also be used as an argument to these functions. - * 3) Log the occurence of a single event: + * 3) Log the occurrence of a single event: * - TraceLogTimestamp(logger, TraceLoggerTextId); * Note: it is temporarily not supported to provide an TraceLoggerEvent as - * argument to log the occurence of a single event. + * argument to log the occurrence of a single event. * * or log the start and stop of an event: * - TraceLogStartEvent(logger, TraceLoggerTextId); diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 3fcd783fbb..39a9d03805 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -1836,7 +1836,7 @@ const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = { * Actually ({}).toString.call(Uint8Array.prototype) should throw, because * Uint8Array.prototype lacks the the typed array internal slots. (Same as * with %TypedArray%.prototype.) It's not clear this is desirable (see - * above), but it's what we've always done, so keep doing it til we + * above), but it's what we've always done, so keep doing it till we * implement @@toStringTag or ES6 changes. */ \ #typedArray "Prototype", \ diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index b348777cbb..7495aafd22 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -1105,6 +1105,7 @@ nsDocumentViewer::PermitUnloadInternal(bool aCallerClosesWindow, { AutoDontWarnAboutSyncXHR disableSyncXHRWarning; + nsresult rv = NS_OK; *aPermitUnload = true; if (!mDocument @@ -1145,9 +1146,7 @@ nsDocumentViewer::PermitUnloadInternal(bool aCallerClosesWindow, getter_AddRefs(event)); nsCOMPtr beforeUnload = do_QueryInterface(event); NS_ENSURE_STATE(beforeUnload); - nsresult rv = event->InitEvent(NS_LITERAL_STRING("beforeunload"), - false, true); - NS_ENSURE_SUCCESS(rv, rv); + event->InitEvent(NS_LITERAL_STRING("beforeunload"), false, true); // Dispatching to |window|, but using |document| as the target. event->SetTarget(mDocument); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 9c6d72f4a6..9f009e2832 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -166,6 +166,12 @@ pref("dom.serviceWorkers.interception.enabled", false); // Allow service workers to intercept opaque (cross origin) responses pref("dom.serviceWorkers.interception.opaque.enabled", false); +// The amount of time (milliseconds) service workers keep running after each event. +pref("dom.serviceWorkers.idle_timeout", 30000); + +// The amount of time (milliseconds) service workers can be kept running using waitUntil promises. +pref("dom.serviceWorkers.idle_extended_timeout", 300000); + // Whether nonzero values can be returned from performance.timing.* pref("dom.enable_performance", true); diff --git a/testing/web-platform/meta/html/dom/interfaces.html.ini b/testing/web-platform/meta/html/dom/interfaces.html.ini index 18107fac1c..b9837a2847 100644 --- a/testing/web-platform/meta/html/dom/interfaces.html.ini +++ b/testing/web-platform/meta/html/dom/interfaces.html.ini @@ -2323,9 +2323,6 @@ [Navigator interface: window.navigator must inherit property "javaEnabled" with the proper type (20)] expected: FAIL - [MessageEvent interface: operation initMessageEvent(DOMString,boolean,boolean,any,DOMString,DOMString,[object Object\],[object Object\],MessagePort)] - expected: FAIL - [PortCollection interface: existence and properties of interface object] expected: FAIL diff --git a/testing/web-platform/meta/workers/Worker_ErrorEvent_bubbles_cancelable.htm.ini b/testing/web-platform/meta/workers/Worker_ErrorEvent_bubbles_cancelable.htm.ini deleted file mode 100644 index a202896943..0000000000 --- a/testing/web-platform/meta/workers/Worker_ErrorEvent_bubbles_cancelable.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[Worker_ErrorEvent_bubbles_cancelable.htm] - type: testharness - [ErrorEvent on worker doesn't bubble and is cancelable] - expected: FAIL - diff --git a/testing/web-platform/meta/workers/interfaces/WorkerGlobalScope/close/incoming-message.html.ini b/testing/web-platform/meta/workers/interfaces/WorkerGlobalScope/close/incoming-message.html.ini deleted file mode 100644 index ffc23eacc2..0000000000 --- a/testing/web-platform/meta/workers/interfaces/WorkerGlobalScope/close/incoming-message.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[incoming-message.html] - type: testharness - disabled: - if debug: unstable - [close() and incoming message] - expected: FAIL - diff --git a/testing/web-platform/meta/workers/interfaces/WorkerUtils/importScripts/004.html.ini b/testing/web-platform/meta/workers/interfaces/WorkerUtils/importScripts/004.html.ini new file mode 100644 index 0000000000..0d95be7218 --- /dev/null +++ b/testing/web-platform/meta/workers/interfaces/WorkerUtils/importScripts/004.html.ini @@ -0,0 +1,4 @@ +[004.html] + type: testharness + [importScripts broken script] + expected: FAIL diff --git a/testing/web-platform/meta/workers/interfaces/WorkerUtils/importScripts/006.html.ini b/testing/web-platform/meta/workers/interfaces/WorkerUtils/importScripts/006.html.ini new file mode 100644 index 0000000000..48e747243c --- /dev/null +++ b/testing/web-platform/meta/workers/interfaces/WorkerUtils/importScripts/006.html.ini @@ -0,0 +1,6 @@ +[006.html] + type: testharness + expected: ERROR + [importScripts uncaught exception] + expected: TIMEOUT + diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event-async-respond-with.https.html b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event-async-respond-with.https.html index 5c908b3d94..912e709ca3 100644 --- a/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event-async-respond-with.https.html +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event-async-respond-with.https.html @@ -22,8 +22,8 @@ promise_test(function(t) { }); var worker = frame.contentWindow.navigator.serviceWorker.controller; - frame.remove(); worker.postMessage({port: channel.port2}, [channel.port2]); + frame.remove(); return saw_message; }) .then(function(message) { diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event.https.html b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event.https.html index d4c96dce24..a4d9f68a6a 100644 --- a/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event.https.html +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-event.https.html @@ -155,7 +155,8 @@ async_test(function(t) { }) .then(function(frame) { assert_equals(frame.contentDocument.body.textContent, - 'POST:testName1=testValue1&testName2=testValue2'); + 'POST:application/x-www-form-urlencoded:' + + 'testName1=testValue1&testName2=testValue2'); document.body.removeChild(frame); return service_worker_unregister_and_done(t, scope); }) @@ -172,15 +173,7 @@ async_test(function(t) { .then(function(frame) { assert_equals( frame.contentDocument.body.textContent, - '(0)', - 'Response should be the argument of the first respondWith() call.'); - frame.remove(); - return with_iframe(scope); - }) - .then(function(frame) { - assert_equals( - frame.contentDocument.body.textContent, - '(0)(1)[InvalidStateError](2)[InvalidStateError](0)', + '(0)(1)[InvalidStateError](2)[InvalidStateError]', 'Multiple calls of respondWith must throw InvalidStateErrors.'); frame.remove(); return service_worker_unregister_and_done(t, scope); @@ -190,6 +183,7 @@ async_test(function(t) { async_test(function(t) { var scope = 'resources/simple.html?used-check'; + var first_frame; service_worker_unregister_and_register(t, worker, scope) .then(function(reg) { return wait_for_state(t, reg.installing, 'activated'); @@ -199,7 +193,7 @@ async_test(function(t) { assert_equals(frame.contentDocument.body.textContent, 'Here\'s an other html file.\n', 'Response should come from fetched other file'); - frame.remove(); + first_frame = frame; return with_iframe(scope); }) .then(function(frame) { @@ -211,6 +205,7 @@ async_test(function(t) { frame.contentDocument.body.textContent, 'bodyUsed: true', 'event.respondWith must set the used flag.'); + first_frame.remove(); frame.remove(); return service_worker_unregister_and_done(t, scope); }) diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-event-test-worker.js b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-event-test-worker.js index fbcc66fbcc..2cdc0f926e 100644 --- a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-event-test-worker.js +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-event-test-worker.js @@ -23,18 +23,23 @@ function handleFormPost(event) { event.respondWith(new Promise(function(resolve) { event.request.text() .then(function(result) { - resolve(new Response(event.request.method + ':' + result)); + resolve(new Response(event.request.method + ':' + + event.request.headers.get('Content-Type') + ':' + + result)); }); })); } -var logForMultipleRespondWith = ''; - function handleMultipleRespondWith(event) { + var logForMultipleRespondWith = ''; for (var i = 0; i < 3; ++i) { logForMultipleRespondWith += '(' + i + ')'; try { - event.respondWith(new Response(logForMultipleRespondWith)); + event.respondWith(new Promise(function(resolve) { + setTimeout(function() { + resolve(new Response(logForMultipleRespondWith)); + }, 0); + })); } catch (e) { logForMultipleRespondWith += '[' + e.name + ']'; } diff --git a/toolkit/devtools/responsivedesign/responsivedesign.jsm b/toolkit/devtools/responsivedesign/responsivedesign.jsm index 928e343389..56d408c7a1 100644 --- a/toolkit/devtools/responsivedesign/responsivedesign.jsm +++ b/toolkit/devtools/responsivedesign/responsivedesign.jsm @@ -231,7 +231,9 @@ function ResponsiveUI(aWindow, aTab) ResponsiveUI.prototype = { _transitionsEnabled: true, - get transitionsEnabled() this._transitionsEnabled, + get transitionsEnabled() { + return this._transitionsEnabled; + }, set transitionsEnabled(aValue) { this._transitionsEnabled = aValue; if (aValue && !this._resizing && this.stack.hasAttribute("responsivemode")) { diff --git a/toolkit/devtools/shared/AppCacheUtils.jsm b/toolkit/devtools/shared/AppCacheUtils.jsm index 1335fa2631..2f6e80d282 100644 --- a/toolkit/devtools/shared/AppCacheUtils.jsm +++ b/toolkit/devtools/shared/AppCacheUtils.jsm @@ -615,7 +615,7 @@ ManifestParser.prototype = { }, }; -XPCOMUtils.defineLazyGetter(this, "l10n", function() Services.strings +XPCOMUtils.defineLazyGetter(this, "l10n", () => Services.strings .createBundle("chrome://global/locale/devtools/appcacheutils.properties")); XPCOMUtils.defineLazyGetter(this, "appcacheservice", function() { diff --git a/toolkit/devtools/shared/SplitView.jsm b/toolkit/devtools/shared/SplitView.jsm index 5e6322ef2a..3fcdda3599 100644 --- a/toolkit/devtools/shared/SplitView.jsm +++ b/toolkit/devtools/shared/SplitView.jsm @@ -86,21 +86,30 @@ SplitView.prototype = { * * @return boolean */ - get isLandscape() this._mql.matches, + get isLandscape() + { + return this._mql.matches; + }, /** * Retrieve the root element. * * @return DOMElement */ - get rootElement() this._root, + get rootElement() + { + return this._root; + }, /** * Retrieve the active item's summary element or null if there is none. * * @return DOMElement */ - get activeSummary() this._activeSummary, + get activeSummary() + { + return this._activeSummary; + }, /** * Set the active item's summary element. diff --git a/toolkit/devtools/shared/widgets/SideMenuWidget.jsm b/toolkit/devtools/shared/widgets/SideMenuWidget.jsm index 5a1116b09e..c783dfd055 100644 --- a/toolkit/devtools/shared/widgets/SideMenuWidget.jsm +++ b/toolkit/devtools/shared/widgets/SideMenuWidget.jsm @@ -73,7 +73,7 @@ SideMenuWidget.prototype = { /** * The comparator used to sort groups. */ - groupSortPredicate: function(a, b) a.localeCompare(b), + groupSortPredicate: (a, b) => a.localeCompare(b), /** * Specifies that the container viewport should be "stuck" to the @@ -460,8 +460,12 @@ function SideMenuGroup(aWidget, aName, aOptions={}) { } SideMenuGroup.prototype = { - get _orderedGroupElementsArray() this.ownerView._orderedGroupElementsArray, - get _orderedMenuElementsArray() this.ownerView._orderedMenuElementsArray, + get _orderedGroupElementsArray() { + return this.ownerView._orderedGroupElementsArray; + }, + get _orderedMenuElementsArray() { + return this.ownerView._orderedMenuElementsArray; + }, get _itemsByElement() { return this.ownerView._itemsByElement; }, /** @@ -567,8 +571,12 @@ function SideMenuItem(aGroup, aContents, aAttachment={}, aOptions={}) { } SideMenuItem.prototype = { - get _orderedGroupElementsArray() this.ownerView._orderedGroupElementsArray, - get _orderedMenuElementsArray() this.ownerView._orderedMenuElementsArray, + get _orderedGroupElementsArray() { + return this.ownerView._orderedGroupElementsArray; + }, + get _orderedMenuElementsArray() { + return this.ownerView._orderedMenuElementsArray; + }, get _itemsByElement() { return this.ownerView._itemsByElement; }, /** diff --git a/toolkit/devtools/shared/widgets/VariablesView.jsm b/toolkit/devtools/shared/widgets/VariablesView.jsm index 0dd106cc36..4a3243c799 100644 --- a/toolkit/devtools/shared/widgets/VariablesView.jsm +++ b/toolkit/devtools/shared/widgets/VariablesView.jsm @@ -404,13 +404,17 @@ VariablesView.prototype = { * Sets if the variable and property searching is enabled. * @param boolean aFlag */ - set searchEnabled(aFlag) aFlag ? this._enableSearch() : this._disableSearch(), + set searchEnabled(aFlag) { + aFlag ? this._enableSearch() : this._disableSearch(); + }, /** * Gets if the variable and property searching is enabled. * @return boolean */ - get searchEnabled() !!this._searchboxContainer, + get searchEnabled() { + return !!this._searchboxContainer; + }, /** * Sets the text displayed for the searchbox in this container. @@ -427,7 +431,9 @@ VariablesView.prototype = { * Gets the text displayed for the searchbox in this container. * @return string */ - get searchPlaceholder() this._searchboxPlaceholder, + get searchPlaceholder() { + return this._searchboxPlaceholder; + }, /** * Enables variable and property searching in this view. @@ -988,25 +994,33 @@ VariablesView.prototype = { * Gets the parent node holding this view. * @return nsIDOMNode */ - get boxObject() this._list.boxObject, + get boxObject() { + return this._list.boxObject; + }, /** * Gets the parent node holding this view. * @return nsIDOMNode */ - get parentNode() this._parent, + get parentNode() { + return this._parent; + }, /** * Gets the owner document holding this view. * @return nsIHTMLDocument */ - get document() this._document || (this._document = this._parent.ownerDocument), + get document() { + return this._document || (this._document = this._parent.ownerDocument); + }, /** * Gets the default window holding this view. * @return nsIDOMWindow */ - get window() this._window || (this._window = this.document.defaultView), + get window() { + return this._window || (this._window = this.document.defaultView); + }, _document: null, _window: null, @@ -1578,61 +1592,81 @@ Scope.prototype = { * Gets the visibility state. * @return boolean */ - get visible() this._isContentVisible, + get visible() { + return this._isContentVisible; + }, /** * Gets the expanded state. * @return boolean */ - get expanded() this._isExpanded, + get expanded() { + return this._isExpanded; + }, /** * Gets the header visibility state. * @return boolean */ - get header() this._isHeaderVisible, + get header() { + return this._isHeaderVisible; + }, /** * Gets the twisty visibility state. * @return boolean */ - get twisty() this._isArrowVisible, + get twisty() { + return this._isArrowVisible; + }, /** * Gets the expand lock state. * @return boolean */ - get locked() this._isLocked, + get locked() { + return this._isLocked; + }, /** * Sets the visibility state. * @param boolean aFlag */ - set visible(aFlag) aFlag ? this.show() : this.hide(), + set visible(aFlag) { + aFlag ? this.show() : this.hide(); + }, /** * Sets the expanded state. * @param boolean aFlag */ - set expanded(aFlag) aFlag ? this.expand() : this.collapse(), + set expanded(aFlag) { + aFlag ? this.expand() : this.collapse(); + }, /** * Sets the header visibility state. * @param boolean aFlag */ - set header(aFlag) aFlag ? this.showHeader() : this.hideHeader(), + set header(aFlag) { + aFlag ? this.showHeader() : this.hideHeader(); + }, /** * Sets the twisty visibility state. * @param boolean aFlag */ - set twisty(aFlag) aFlag ? this.showArrow() : this.hideArrow(), + set twisty(aFlag) { + aFlag ? this.showArrow() : this.hideArrow(); + }, /** * Sets the expand lock state. * @param boolean aFlag */ - set locked(aFlag) this._isLocked = aFlag, + set locked(aFlag) { + this._isLocked = aFlag; + }, /** * Specifies if this target node may be focused. @@ -1689,31 +1723,41 @@ Scope.prototype = { * Gets the id associated with this item. * @return string */ - get id() this._idString, + get id() { + return this._idString; + }, /** * Gets the name associated with this item. * @return string */ - get name() this._nameString, + get name() { + return this._nameString; + }, /** * Gets the displayed value for this item. * @return string */ - get displayValue() this._valueString, + get displayValue() { + return this._valueString; + }, /** * Gets the class names used for the displayed value. * @return string */ - get displayValueClassName() this._valueClassName, + get displayValueClassName() { + return this._valueClassName; + }, /** * Gets the element associated with this item. * @return nsIDOMNode */ - get target() this._target, + get target() { + return this._target; + }, /** * Initializes this scope's id, view and binds event listeners. @@ -1995,33 +2039,41 @@ Scope.prototype = { * Gets top level variables view instance. * @return VariablesView */ - get _variablesView() this._topView || (this._topView = (function(self) { - let parentView = self.ownerView; - let topView; + get _variablesView() { + return this._topView || (this._topView = (() => { + let parentView = this.ownerView; + let topView; - while ((topView = parentView.ownerView)) { - parentView = topView; - } - return parentView; - })(this)), + while ((topView = parentView.ownerView)) { + parentView = topView; + } + return parentView; + })()); + }, /** * Gets the parent node holding this scope. * @return nsIDOMNode */ - get parentNode() this.ownerView._list, + get parentNode() { + return this.ownerView._list; + }, /** * Gets the owner document holding this scope. * @return nsIHTMLDocument */ - get document() this._document || (this._document = this.ownerView.document), + get document() { + return this._document || (this._document = this.ownerView.document); + }, /** * Gets the default window holding this scope. * @return nsIDOMWindow */ - get window() this._window || (this._window = this.ownerView.window), + get window() { + return this._window || (this._window = this.ownerView.window); + }, _topView: null, _document: null, @@ -2324,19 +2376,25 @@ Variable.prototype = Heritage.extend(Scope.prototype, { * Returns this variable's value from the descriptor if available. * @return any */ - get value() this._initialDescriptor.value, + get value() { + return this._initialDescriptor.value; + }, /** * Returns this variable's getter from the descriptor if available. * @return object */ - get getter() this._initialDescriptor.get, + get getter() { + return this._initialDescriptor.get; + }, /** * Returns this variable's getter from the descriptor if available. * @return object */ - get setter() this._initialDescriptor.set, + get setter() { + return this._initialDescriptor.set; + }, /** * Sets the specific grip for this variable (applies the text content and diff --git a/toolkit/devtools/shared/widgets/ViewHelpers.jsm b/toolkit/devtools/shared/widgets/ViewHelpers.jsm index 5bd92c51dc..94588aa7bb 100644 --- a/toolkit/devtools/shared/widgets/ViewHelpers.jsm +++ b/toolkit/devtools/shared/widgets/ViewHelpers.jsm @@ -770,7 +770,9 @@ this.WidgetMethods = { * Gets the element node or widget associated with this container. * @return nsIDOMNode | object */ - get widget() this._widget, + get widget() { + return this._widget; + }, /** * Prepares an item to be added to this container. This allows, for example, diff --git a/xpcom/base/ErrorList.h b/xpcom/base/ErrorList.h index 6e993f28e9..68e7317932 100644 --- a/xpcom/base/ErrorList.h +++ b/xpcom/base/ErrorList.h @@ -339,6 +339,8 @@ ERROR(NS_ERROR_BAD_OPAQUE_REDIRECT_INTERCEPTION, FAILURE(106)), /* Service worker intentionally canceled load via preventDefault(). */ ERROR(NS_ERROR_INTERCEPTION_CANCELED, FAILURE(107)), + /* Service worker passed a rejected promise to respondwith. */ + ERROR(NS_ERROR_REJECTED_RESPONSE_INTERCEPTION, FAILURE(108)), #undef MODULE