Browse Source

import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1201135 - Rename pldhash.{h,cpp} to PLDHashTable.{h,cpp}. r=mccr8. (0600308646)
- Bug 1203680 P4 Fix bug in nsStorageStream with reading streams create#d efore data is populated. r=froydnj (a51018d7c4)
- Bug 1156109 - Make nsStorageInputStream::mStorageStream an nsRefPtr; r=froydnj (ac2083b0a4)
- Bug 1158735 - FetchEvent.client asserting in onFetch when there's no document. r=bkelly (c67f9dc127)
- Bug 1187766 - Test loading plugins scenarios with fetch interception. r=bkelly (9593999e0b)
- Bug 1182103 - Test EventSource scenarios with fetch interception. r=bkelly (c45c0a9840)
- Bug 1187470 - ServiceWorker scripts should not be treated parser warnings as errors, r=bkelly (a87dcd8b46)
- Bug 1144660 - client.focus() adds window interaction checks and directly uses DOMServiceWorkerFocusClient to focus window. r=ehsan,dao (66293cab2c)
- Bug 1176988 - Patch 1 - Always hit cache irrespective of HTTP method if channel is being intercepted. r=jdm (fa57442870)
- Bug 1176988 - Patch 2 - Remove XHR cache bypass in cast of POST request. r=jdm (7009c4cfb8)
- Bug 1182120 - Test XMLDocument.load() with fetch interception. r=bkelly (fae709bda0)
- Bug 1176988 - Patch 3 - Tests. r=jdm (bfb5e84490)
- Bug 815299 - Part 1: Add an API for setting an empty request header on an HTTP channel; r=dragana (ad3846e6c6)
- Bug 815299 - Part 2: Accept empty HTTP headers in fetch; r=jdm (f4d344d4a3)
- Bug 815299 - Part 3: Accept empty HTTP headers in XHR; r=jdm (8ed9b6251b)
- Bug 1198544 - Prevent FetchDriver from creating multiple responses if OnStopRequest yields a failing status code. r=nsm (e6ce3a3621)
- Bug 1171941 - Removed an incorrect URL prefix from fetch_tests.js. r=jdm (bbc57bc7e3)
- Bug 1199693 - Test CORS preflight interception with and without an internal redirect; r=jdm (6dda8cb00e)
- Bug 1190703 - Relax scope resolution assertion in ServiceWorkerContainer::Register. r=bkelly (75a095f761)
- Bug 1181037 - Use entry settings object's base URL. r=ehsan (4be1b9e1cb)
- Bug 1194562 - Pass wide strings to ThrowTypeError. r=mccr8 (360113dbb9)
- Bug 1185640 - serviceworker register() should not accept escaped slashes. r=bkelly (3c74e3c561)
- namespace (0853d1387f)
- Bug 1187350 - update() should return a Promise. r=ehsan,catalinb (5fa3367032)
- Bug 1183628 - Update web-platform-tests expected data to revision 593fd27931d7e9d573d2796fe10df9fff778d56f, a=testonly (de41f55433)
- Bug 1180861 - Various ServiceWorker registration fixes to get test passing. r=bkelly,jgraham. (e1e5be174b)
- Bug 1203680 P1 Test file blob uploads with service worker interception. r=nsm (fa7441fd83)
- Bug 1203680 P2 Implement an NS_InputStreamIsCloneable() method. r=froydnj (5067d82f06)
- Bug 1203680 P3 Add a method to ensure an http upload stream is directly cloneable. r=mcmanus (45aed67d00)
pull/8/head
roytam1 4 months ago
parent
commit
a9171b7b23
  1. 4
      browser/base/content/content.js
  2. 2
      browser/base/content/tabbrowser.xml
  3. 5
      browser/components/build/moz.build
  4. 2
      dom/base/nsContentList.cpp
  5. 4
      dom/base/nsContentUtils.h
  6. 2
      dom/base/nsDocument.h
  7. 2
      dom/base/nsGenericDOMDataNode.cpp
  8. 2
      dom/base/nsNodeUtils.cpp
  9. 2
      dom/base/nsPropertyTable.cpp
  10. 2
      dom/base/nsScriptNameSpaceManager.h
  11. 53
      dom/base/nsXMLHttpRequest.cpp
  12. 1
      dom/bindings/Errors.msg
  13. 8
      dom/fetch/Fetch.cpp
  14. 22
      dom/fetch/FetchDriver.cpp
  15. 15
      dom/fetch/FetchDriver.h
  16. 2
      dom/html/nsHTMLDocument.h
  17. 2
      dom/plugins/base/nsJSNPRuntime.h
  18. 2
      dom/smil/nsSMILCompositor.h
  19. 5
      dom/webidl/ServiceWorkerRegistration.webidl
  20. 91
      dom/workers/ServiceWorkerContainer.cpp
  21. 6
      dom/workers/ServiceWorkerEvents.cpp
  22. 232
      dom/workers/ServiceWorkerManager.cpp
  23. 37
      dom/workers/ServiceWorkerManager.h
  24. 2
      dom/workers/ServiceWorkerManagerChild.cpp
  25. 231
      dom/workers/ServiceWorkerRegistration.cpp
  26. 8
      dom/workers/ServiceWorkerRegistration.h
  27. 36
      dom/workers/ServiceWorkerScriptCache.cpp
  28. 30
      dom/workers/ServiceWorkerWindowClient.cpp
  29. 137
      dom/workers/WorkerPrivate.cpp
  30. 24
      dom/workers/WorkerPrivate.h
  31. 3
      dom/workers/WorkerScope.cpp
  32. 21
      dom/workers/WorkerScope.h
  33. 15
      dom/workers/test/serviceworkers/client_focus_worker.js
  34. 22
      dom/workers/test/serviceworkers/eventsource/eventsource.resource
  35. 3
      dom/workers/test/serviceworkers/eventsource/eventsource.resource^headers^
  36. 75
      dom/workers/test/serviceworkers/eventsource/eventsource_cors_response.html
  37. 19
      dom/workers/test/serviceworkers/eventsource/eventsource_cors_response_intercept_worker.js
  38. 75
      dom/workers/test/serviceworkers/eventsource/eventsource_mixed_content_cors_response.html
  39. 18
      dom/workers/test/serviceworkers/eventsource/eventsource_mixed_content_cors_response_intercept_worker.js
  40. 75
      dom/workers/test/serviceworkers/eventsource/eventsource_opaque_response.html
  41. 19
      dom/workers/test/serviceworkers/eventsource/eventsource_opaque_response_intercept_worker.js
  42. 27
      dom/workers/test/serviceworkers/eventsource/eventsource_register_worker.html
  43. 75
      dom/workers/test/serviceworkers/eventsource/eventsource_synthetic_response.html
  44. 24
      dom/workers/test/serviceworkers/eventsource/eventsource_synthetic_response_intercept_worker.js
  45. 12
      dom/workers/test/serviceworkers/eventsource/eventsource_worker_helper.js
  46. 66
      dom/workers/test/serviceworkers/fetch/fetch_tests.js
  47. 27
      dom/workers/test/serviceworkers/fetch/index.html
  48. 20
      dom/workers/test/serviceworkers/fetch/interrupt.sjs
  49. 43
      dom/workers/test/serviceworkers/fetch/plugin/plugins.html
  50. 7
      dom/workers/test/serviceworkers/fetch/plugin/worker.js
  51. 6
      dom/workers/test/serviceworkers/fetch_event_client.js
  52. 48
      dom/workers/test/serviceworkers/fetch_event_worker.js
  53. 26
      dom/workers/test/serviceworkers/mochitest.ini
  54. 28
      dom/workers/test/serviceworkers/notificationclick_focus.html
  55. 40
      dom/workers/test/serviceworkers/notificationclick_focus.js
  56. 35
      dom/workers/test/serviceworkers/redirect_post.sjs
  57. 0
      dom/workers/test/serviceworkers/strict_mode_warning.js
  58. 19
      dom/workers/test/serviceworkers/sw_clients/dummy.html
  59. 77
      dom/workers/test/serviceworkers/sw_clients/file_blob_upload_frame.html
  60. 33
      dom/workers/test/serviceworkers/sw_clients/focus_stealing_client.html
  61. 4
      dom/workers/test/serviceworkers/test_client_focus.html
  62. 102
      dom/workers/test/serviceworkers/test_escapedSlashes.html
  63. 105
      dom/workers/test/serviceworkers/test_eventsource_intercept.html
  64. 71
      dom/workers/test/serviceworkers/test_fetch_event_client_postmessage.html
  65. 146
      dom/workers/test/serviceworkers/test_file_blob_upload.html
  66. 4
      dom/workers/test/serviceworkers/test_installation_simple.html
  67. 80
      dom/workers/test/serviceworkers/test_not_intercept_plugin.html
  68. 57
      dom/workers/test/serviceworkers/test_notificationclick_focus.html
  69. 8
      dom/workers/test/serviceworkers/test_strict_mode_warning.html
  70. 3
      dom/workers/test/serviceworkers/test_workerUpdate.html
  71. 19
      dom/workers/test/serviceworkers/worker_update.js
  72. 1
      dom/workers/test/test_xhr_headers.html
  73. 19
      dom/workers/test/xhr_headers_server.sjs
  74. 2
      dom/xul/templates/nsContentSupportMap.h
  75. 2
      dom/xul/templates/nsRuleNetwork.h
  76. 2
      dom/xul/templates/nsTemplateMap.h
  77. 2
      dom/xul/templates/nsTreeRows.h
  78. 2
      dom/xul/templates/nsXULContentBuilder.cpp
  79. 2
      dom/xul/templates/nsXULTemplateBuilder.cpp
  80. 2
      embedding/components/commandhandler/nsCommandParams.h
  81. 2
      gfx/thebes/gfxGradientCache.cpp
  82. 2
      js/src/devtools/rootAnalysis/annotations.js
  83. 2
      js/xpconnect/src/xpcprivate.h
  84. 2
      layout/base/nsFrameManager.cpp
  85. 2
      layout/base/nsFrameManagerBase.h
  86. 2
      layout/base/nsPresShell.cpp
  87. 2
      layout/style/nsCSSRuleProcessor.cpp
  88. 2
      layout/style/nsHTMLStyleSheet.h
  89. 2
      layout/style/nsRuleNode.cpp
  90. 2
      layout/tables/SpanningCellSorter.h
  91. 2
      modules/libpref/Preferences.cpp
  92. 2
      modules/libpref/nsPrefBranch.cpp
  93. 2
      modules/libpref/prefapi.cpp
  94. 2
      modules/libpref/prefapi.h
  95. 17
      netwerk/base/nsIUploadChannel2.idl
  96. 2
      netwerk/base/nsLoadGroup.cpp
  97. 2
      netwerk/base/nsLoadGroup.h
  98. 2
      netwerk/base/nsURIHashKey.h
  99. 2
      netwerk/cache/nsCacheEntry.h
  100. 2
      netwerk/cache/nsDiskCacheBinding.h
  101. Some files were not shown because too many files have changed in this diff Show More

4
browser/base/content/content.js

@ -285,3 +285,7 @@ addMessageListener("Finder:Initialize", function () {
addEventListener("DOMWebNotificationClicked", function(event) {
sendAsyncMessage("DOMWebNotificationClicked", {});
}, false);
addEventListener("DOMServiceWorkerFocusClient", function(event) {
sendAsyncMessage("DOMServiceWorkerFocusClient", {});
}, false);

2
browser/base/content/tabbrowser.xml

@ -3068,6 +3068,7 @@
tab.setAttribute("titlechanged", "true");
break;
}
case "DOMServiceWorkerFocusClient":
case "DOMWebNotificationClicked": {
let tab = this.getTabForBrowser(browser);
if (!tab)
@ -3143,6 +3144,7 @@
this.mCurrentBrowser);
}
messageManager.addMessageListener("DOMWebNotificationClicked", this);
messageManager.addMessageListener("DOMServiceWorkerFocusClient", this);
]]>
</constructor>

5
browser/components/build/moz.build

@ -22,6 +22,11 @@ LOCAL_INCLUDES += [
'../shell',
]
if CONFIG['JS_SHARED_LIBRARY']:
USE_LIBS += [
'js',
]
if CONFIG['OS_ARCH'] == 'WINNT':
OS_LIBS += [
'ole32',

2
dom/base/nsContentList.cpp

@ -30,7 +30,7 @@
// Form related includes
#include "nsIDOMHTMLFormElement.h"
#include "pldhash.h"
#include "PLDHashTable.h"
#ifdef DEBUG_CONTENT_LIST
#include "nsIContentIterator.h"

4
dom/base/nsContentUtils.h

@ -1702,16 +1702,12 @@ public:
/**
* Convert ASCII A-Z to a-z.
* @return NS_OK on success, or NS_ERROR_OUT_OF_MEMORY if making the string
* writable needs to allocate memory and that allocation fails.
*/
static void ASCIIToLower(nsAString& aStr);
static void ASCIIToLower(const nsAString& aSource, nsAString& aDest);
/**
* Convert ASCII a-z to A-Z.
* @return NS_OK on success, or NS_ERROR_OUT_OF_MEMORY if making the string
* writable needs to allocate memory and that allocation fails.
*/
static void ASCIIToUpper(nsAString& aStr);
static void ASCIIToUpper(const nsAString& aSource, nsAString& aDest);

2
dom/base/nsDocument.h

@ -45,7 +45,7 @@
#include "nsIApplicationCache.h"
#include "nsIApplicationCacheContainer.h"
#include "nsStyleSet.h"
#include "pldhash.h"
#include "PLDHashTable.h"
#include "nsAttrAndChildArray.h"
#include "nsDOMAttributeMap.h"
#include "nsIContentViewer.h"

2
dom/base/nsGenericDOMDataNode.cpp

@ -33,7 +33,7 @@
#include "nsCCUncollectableMarker.h"
#include "mozAutoDocUpdate.h"
#include "pldhash.h"
#include "PLDHashTable.h"
#include "prprf.h"
#include "nsWrapperCacheInlines.h"

2
dom/base/nsNodeUtils.cpp

@ -13,7 +13,7 @@
#include "nsIDocument.h"
#include "mozilla/EventListenerManager.h"
#include "nsIXPConnect.h"
#include "pldhash.h"
#include "PLDHashTable.h"
#include "nsIDOMAttr.h"
#include "nsCOMArray.h"
#include "nsPIDOMWindow.h"

2
dom/base/nsPropertyTable.cpp

@ -23,7 +23,7 @@
#include "mozilla/MemoryReporting.h"
#include "pldhash.h"
#include "PLDHashTable.h"
#include "nsError.h"
#include "nsIAtom.h"

2
dom/base/nsScriptNameSpaceManager.h

@ -26,7 +26,7 @@
#include "nsIScriptNameSpaceManager.h"
#include "nsString.h"
#include "nsID.h"
#include "pldhash.h"
#include "PLDHashTable.h"
#include "nsDOMClassInfo.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"

53
dom/base/nsXMLHttpRequest.cpp

@ -2928,26 +2928,22 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
NS_ASSERTION(listener != this,
"Using an object as a listener that can't be exposed to JS");
// Bypass the network cache in cases where it makes no sense:
// POST responses are always unique, and we provide no API that would
// allow our consumers to specify a "cache key" to access old POST
// responses, so they are not worth caching.
if (method.EqualsLiteral("POST")) {
AddLoadFlags(mChannel,
nsIRequest::LOAD_BYPASS_CACHE | nsIRequest::INHIBIT_CACHING);
} else {
// 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).
//
// Also don't block on the cache entry on async if it is busy - favoring parallelism
// over cache hit rate for xhr. This does not disable the cache everywhere -
// only in cases where more than one channel for the same URI is accessed
// simultanously.
// 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).
//
// Also don't block on the cache entry on async if it is busy - favoring parallelism
// over cache hit rate for xhr. This does not disable the cache everywhere -
// only in cases where more than one channel for the same URI is accessed
// simultanously.
AddLoadFlags(mChannel,
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
}
AddLoadFlags(mChannel,
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
// While it would be optimal to bypass the cache in case of POST requests
// since they are never cached, our ServiceWorker interception implementation
// on single-process systems is implemented via the HTTP cache, so DO NOT
// bypass the cache based on method!
// Since we expect XML data, set the type hint accordingly
// if the channel doesn't know any content type.
@ -3168,8 +3164,13 @@ nsXMLHttpRequest::SetRequestHeader(const nsACString& header,
mergeHeaders = false;
}
// Merge headers depending on what we decided above.
nsresult rv = httpChannel->SetRequestHeader(header, value, mergeHeaders);
nsresult rv;
if (value.IsEmpty()) {
rv = httpChannel->SetEmptyRequestHeader(header);
} else {
// Merge headers depending on what we decided above.
rv = httpChannel->SetRequestHeader(header, value, mergeHeaders);
}
if (rv == NS_ERROR_INVALID_ARG) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
@ -3502,9 +3503,13 @@ nsXMLHttpRequest::OnRedirectVerifyCallback(nsresult result)
// Ensure all original headers are duplicated for the new channel (bug #553888)
for (uint32_t i = mModifiedRequestHeaders.Length(); i > 0; ) {
--i;
httpChannel->SetRequestHeader(mModifiedRequestHeaders[i].header,
mModifiedRequestHeaders[i].value,
false);
if (mModifiedRequestHeaders[i].value.IsEmpty()) {
httpChannel->SetEmptyRequestHeader(mModifiedRequestHeaders[i].header);
} else {
httpChannel->SetRequestHeader(mModifiedRequestHeaders[i].header,
mModifiedRequestHeaders[i].value,
false);
}
}
}
} else {

1
dom/bindings/Errors.msg

@ -79,3 +79,4 @@ MSG_DEF(MSG_BAD_FORMDATA, 0, JSEXN_TYPEERR, "Could not parse content as FormData
MSG_DEF(MSG_NO_ACTIVE_WORKER, 1, JSEXN_TYPEERR, "No active worker for scope {0}.")
MSG_DEF(MSG_NOTIFICATION_PERMISSION_DENIED, 0, JSEXN_TYPEERR, "Permission to show Notification denied.")
MSG_DEF(MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER, 0, JSEXN_TYPEERR, "Notification constructor cannot be used in ServiceWorkerGlobalScope. Use registration.showNotification() instead.")
MSG_DEF(MSG_INVALID_SCOPE, 2, JSEXN_TYPEERR, "Invalid scope trying to resolve {0} with base URL {1}.")

8
dom/fetch/Fetch.cpp

@ -72,7 +72,7 @@ public:
}
void
OnResponseAvailable(InternalResponse* aResponse) override;
OnResponseAvailableInternal(InternalResponse* aResponse) override;
void
OnResponseEnd() override;
@ -141,7 +141,7 @@ public:
explicit MainThreadFetchResolver(Promise* aPromise);
void
OnResponseAvailable(InternalResponse* aResponse) override;
OnResponseAvailableInternal(InternalResponse* aResponse) override;
private:
~MainThreadFetchResolver();
@ -277,7 +277,7 @@ MainThreadFetchResolver::MainThreadFetchResolver(Promise* aPromise)
}
void
MainThreadFetchResolver::OnResponseAvailable(InternalResponse* aResponse)
MainThreadFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
{
NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
AssertIsOnMainThread();
@ -357,7 +357,7 @@ public:
};
void
WorkerFetchResolver::OnResponseAvailable(InternalResponse* aResponse)
WorkerFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
{
AssertIsOnMainThread();

22
dom/fetch/FetchDriver.cpp

@ -412,7 +412,11 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica
nsAutoTArray<InternalHeaders::Entry, 5> headers;
mRequest->Headers()->GetEntries(headers);
for (uint32_t i = 0; i < headers.Length(); ++i) {
httpChan->SetRequestHeader(headers[i].mName, headers[i].mValue, false /* merge */);
if (headers[i].mValue.IsEmpty()) {
httpChan->SetEmptyRequestHeader(headers[i].mName);
} else {
httpChan->SetRequestHeader(headers[i].mName, headers[i].mValue, false /* merge */);
}
}
// Step 2. Set the referrer.
@ -777,15 +781,21 @@ FetchDriver::OnStopRequest(nsIRequest* aRequest,
nsresult aStatusCode)
{
workers::AssertIsOnMainThread();
if (mPipeOutputStream) {
mPipeOutputStream->Close();
}
if (NS_FAILED(aStatusCode)) {
FailWithNetworkError();
nsCOMPtr<nsIAsyncOutputStream> outputStream = do_QueryInterface(mPipeOutputStream);
if (outputStream) {
outputStream->CloseWithStatus(NS_BINDING_FAILED);
}
// We proceed as usual here, since we've already created a successful response
// from OnStartRequest.
SucceedWithResponse();
return aStatusCode;
}
if (mPipeOutputStream) {
mPipeOutputStream->Close();
}
ContinueHttpFetchAfterNetworkFetch();
return NS_OK;
}

15
dom/fetch/FetchDriver.h

@ -31,14 +31,27 @@ class InternalResponse;
class FetchDriverObserver
{
public:
FetchDriverObserver() : mGotResponseAvailable(false)
{ }
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchDriverObserver);
virtual void OnResponseAvailable(InternalResponse* aResponse) = 0;
void OnResponseAvailable(InternalResponse* aResponse)
{
MOZ_ASSERT(!mGotResponseAvailable);
mGotResponseAvailable = true;
OnResponseAvailableInternal(aResponse);
}
virtual void OnResponseEnd()
{ };
protected:
virtual ~FetchDriverObserver()
{ };
virtual void OnResponseAvailableInternal(InternalResponse* aResponse) = 0;
private:
bool mGotResponseAvailable;
};
class FetchDriver final : public nsIStreamListener,

2
dom/html/nsHTMLDocument.h

@ -14,7 +14,7 @@
#include "nsIScriptElement.h"
#include "nsTArray.h"
#include "pldhash.h"
#include "PLDHashTable.h"
#include "nsIHttpChannel.h"
#include "nsHTMLStyleSheet.h"

2
dom/plugins/base/nsJSNPRuntime.h

@ -9,7 +9,7 @@
#include "nscore.h"
#include "npapi.h"
#include "npruntime.h"
#include "pldhash.h"
#include "PLDHashTable.h"
class nsJSNPRuntime
{

2
dom/smil/nsSMILCompositor.h

@ -13,7 +13,7 @@
#include "nsSMILAnimationFunction.h"
#include "nsSMILTargetIdentifier.h"
#include "nsSMILCompositorTable.h"
#include "pldhash.h"
#include "PLDHashTable.h"
//----------------------------------------------------------------------
// nsSMILCompositor

5
dom/webidl/ServiceWorkerRegistration.webidl

@ -17,9 +17,10 @@ interface ServiceWorkerRegistration : EventTarget {
readonly attribute USVString scope;
void update();
[Throws, NewObject]
Promise<void> update();
[Throws]
[Throws, NewObject]
Promise<boolean> unregister();
// event

91
dom/workers/ServiceWorkerContainer.cpp

@ -8,6 +8,7 @@
#include "nsIDocument.h"
#include "nsIServiceWorkerManager.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "mozilla/Preferences.h"
@ -100,6 +101,33 @@ ServiceWorkerContainer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenP
return ServiceWorkerContainerBinding::Wrap(aCx, this, aGivenProto);
}
static nsresult
CheckForSlashEscapedCharsInPath(nsIURI* aURI)
{
MOZ_ASSERT(aURI);
// A URL that can't be downcast to a standard URL is an invalid URL and should
// be treated as such and fail with SecurityError.
nsCOMPtr<nsIURL> url(do_QueryInterface(aURI));
if (NS_WARN_IF(!url)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsAutoCString path;
nsresult rv = url->GetFilePath(path);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
ToLowerCase(path);
if (path.Find("%2f") != kNotFound ||
path.Find("%5c") != kNotFound) {
return NS_ERROR_DOM_TYPE_ERR;
}
return NS_OK;
}
already_AddRefed<Promise>
ServiceWorkerContainer::Register(const nsAString& aScriptURL,
const RegistrationOptions& aOptions,
@ -113,37 +141,80 @@ ServiceWorkerContainer::Register(const nsAString& aScriptURL,
return nullptr;
}
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
MOZ_ASSERT(window);
nsCOMPtr<nsIURI> baseURI;
nsIDocument* doc = GetEntryDocument();
if (doc) {
baseURI = doc->GetBaseURI();
} else {
// XXXnsm. One of our devtools browser test calls register() from a content
// script where there is no valid entry document. Use the window to resolve
// the uri in that case.
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
nsCOMPtr<nsPIDOMWindow> outerWindow;
if (window && (outerWindow = window->GetOuterWindow()) &&
outerWindow->GetServiceWorkersTestingEnabled()) {
baseURI = window->GetDocBaseURI();
}
}
if (!baseURI) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
nsresult rv;
nsCOMPtr<nsIURI> scriptURI;
rv = NS_NewURI(getter_AddRefs(scriptURI), aScriptURL, nullptr,
window->GetDocBaseURI());
rv = NS_NewURI(getter_AddRefs(scriptURI), aScriptURL, nullptr, baseURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.ThrowTypeError(MSG_INVALID_URL, &aScriptURL);
return nullptr;
}
aRv = CheckForSlashEscapedCharsInPath(scriptURI);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
// In ServiceWorkerContainer.register() the scope argument is parsed against
// different base URLs depending on whether it was passed or not.
nsCOMPtr<nsIURI> scopeURI;
// Step 4. If none passed, parse against script's URL
if (!aOptions.mScope.WasPassed()) {
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), NS_LITERAL_CSTRING("./"),
nullptr, scriptURI);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
NS_NAMED_LITERAL_STRING(defaultScope, "./");
rv = NS_NewURI(getter_AddRefs(scopeURI), defaultScope,
nullptr, scriptURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
nsAutoCString spec;
scriptURI->GetSpec(spec);
NS_ConvertUTF8toUTF16 wSpec(spec);
aRv.ThrowTypeError(MSG_INVALID_SCOPE, &defaultScope, &wSpec);
return nullptr;
}
} else {
// Step 5. Parse against entry settings object's base URL.
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aOptions.mScope.Value(),
nullptr, window->GetDocBaseURI());
rv = NS_NewURI(getter_AddRefs(scopeURI), aOptions.mScope.Value(),
nullptr, baseURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.ThrowTypeError(MSG_INVALID_URL, &aOptions.mScope.Value());
nsAutoCString spec;
baseURI->GetSpec(spec);
NS_ConvertUTF8toUTF16 wSpec(spec);
aRv.ThrowTypeError(MSG_INVALID_SCOPE, &aOptions.mScope.Value(), &wSpec);
return nullptr;
}
aRv = CheckForSlashEscapedCharsInPath(scopeURI);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
}
// The spec says that the "client" passed to Register() must be the global
// where the ServiceWorkerContainer was retrieved from.
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
MOZ_ASSERT(window);
aRv = swm->Register(window, scopeURI, scriptURI, getter_AddRefs(promise));
if (aRv.Failed()) {
return nullptr;

6
dom/workers/ServiceWorkerEvents.cpp

@ -370,7 +370,11 @@ FetchEvent::GetClient()
return nullptr;
}
mClient = new ServiceWorkerClient(GetParentObject(), *mClientInfo);
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
nsRefPtr<nsIGlobalObject> global = worker->GlobalScope();
mClient = new ServiceWorkerClient(global, *mClientInfo);
}
nsRefPtr<ServiceWorkerClient> client = mClient;
return client.forget();

232
dom/workers/ServiceWorkerManager.cpp

@ -96,6 +96,16 @@ static_assert(nsIHttpChannelInternal::CORS_MODE_CORS_WITH_FORCED_PREFLIGHT == st
static StaticRefPtr<ServiceWorkerManager> gInstance;
// Tracks the "dom.disable_open_click_delay" preference. Modified on main
// thread, read on worker threads. This is set once in the ServiceWorkerManager
// constructor before any service workers are spawned.
// It is updated every time a "notificationclick" event is dispatched. While
// this is done without synchronization, at the worst, the thread will just get
// an older value within which a popup is allowed to be displayed, which will
// still be a valid value since it was set in the constructor. I (:nsm) don't
// think this needs to be synchronized.
Atomic<uint32_t> gDOMDisableOpenClickDelay(0);
struct ServiceWorkerManager::RegistrationDataPerPrincipal
{
// Ordered list of scopes for glob matching.
@ -386,6 +396,8 @@ ServiceWorkerManager::ServiceWorkerManager()
{
// Register this component to PBackground.
MOZ_ALWAYS_TRUE(BackgroundChild::GetOrCreateForCurrentThread(this));
gDOMDisableOpenClickDelay = Preferences::GetInt("dom.disable_open_click_delay");
}
ServiceWorkerManager::~ServiceWorkerManager()
@ -531,28 +543,6 @@ private:
};
class ServiceWorkerUpdateFinishCallback
{
protected:
virtual ~ServiceWorkerUpdateFinishCallback()
{ }
public:
NS_INLINE_DECL_REFCOUNTING(ServiceWorkerUpdateFinishCallback)
virtual
void UpdateSucceeded(ServiceWorkerRegistrationInfo* aInfo)
{ }
virtual
void UpdateFailed(nsresult aStatus)
{ }
virtual
void UpdateFailed(const ErrorEventInit& aDesc)
{ }
};
class ServiceWorkerResolveWindowPromiseOnUpdateCallback final : public ServiceWorkerUpdateFinishCallback
{
nsRefPtr<nsPIDOMWindow> mWindow;
@ -586,7 +576,7 @@ public:
}
void
UpdateFailed(const ErrorEventInit& aErrorDesc) override
UpdateFailed(JSExnType aExnType, const ErrorEventInit& aErrorDesc) override
{
AutoJSAPI jsapi;
jsapi.Init(mWindow);
@ -610,7 +600,8 @@ public:
JS::Rooted<JSString*> msg(cx, msgval.toString());
JS::Rooted<JS::Value> error(cx);
if (!JS::CreateError(cx, JSEXN_ERR, nullptr, fn, aErrorDesc.mLineno,
if ((aExnType < JSEXN_ERR) ||
!JS::CreateError(cx, aExnType, nullptr, fn, aErrorDesc.mLineno,
aErrorDesc.mColno, nullptr, msg, &error)) {
JS_ClearPendingException(cx);
mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
@ -989,13 +980,17 @@ public:
const nsACString& aMaxScope) override
{
nsRefPtr<ServiceWorkerRegisterJob> kungFuDeathGrip = this;
if (mCanceled) {
if (NS_WARN_IF(mCanceled)) {
Fail(NS_ERROR_DOM_TYPE_ERR);
return;
}
if (NS_WARN_IF(NS_FAILED(aStatus))) {
Fail(NS_ERROR_DOM_TYPE_ERR);
if (aStatus == NS_ERROR_DOM_SECURITY_ERR) {
Fail(aStatus);
} else {
Fail(NS_ERROR_DOM_TYPE_ERR);
}
return;
}
@ -1115,7 +1110,7 @@ public:
// Public so our error handling code can use it.
// Callers MUST hold a strong ref before calling this!
void
Fail(const ErrorEventInit& aError)
Fail(JSExnType aExnType, const ErrorEventInit& aError)
{
MOZ_ASSERT(mCallback);
nsRefPtr<ServiceWorkerUpdateFinishCallback> callback = mCallback.forget();
@ -1125,7 +1120,7 @@ public:
// FailCommon relies on it.
// FailCommon does check for cancellation, but let's be safe here.
nsRefPtr<ServiceWorkerRegisterJob> kungFuDeathGrip = this;
callback->UpdateFailed(aError);
callback->UpdateFailed(aExnType, aError);
FailCommon(NS_ERROR_DOM_JS_EXCEPTION);
}
@ -1617,10 +1612,11 @@ ServiceWorkerManager::AppendPendingOperation(nsIRunnable* aRunnable)
namespace {
// Just holds a ref to a ServiceWorker until the Promise is fulfilled.
class KeepAliveHandler final : public PromiseNativeHandler
class KeepAliveHandler : public PromiseNativeHandler
{
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
protected:
virtual ~KeepAliveHandler()
{}
@ -1654,6 +1650,150 @@ public:
NS_IMPL_ISUPPORTS0(KeepAliveHandler)
void
DummyCallback(nsITimer* aTimer, void* aClosure)
{
// Nothing.
}
class AllowWindowInteractionKeepAliveHandler;
class ClearWindowAllowedRunnable final : public WorkerRunnable
{
public:
ClearWindowAllowedRunnable(WorkerPrivate* aWorkerPrivate,
AllowWindowInteractionKeepAliveHandler* aHandler)
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
, mHandler(aHandler)
{ }
private:
bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
// WorkerRunnable asserts that the dispatch is from parent thread if
// the busy count modification is WorkerThreadUnchangedBusyCount.
// Since this runnable will be dispatched from the timer thread, we override
// PreDispatch and PostDispatch to skip the check.
return true;
}
void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) override
{
// Silence bad assertions.
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
nsRefPtr<AllowWindowInteractionKeepAliveHandler> mHandler;
};
class AllowWindowInteractionKeepAliveHandler final : public KeepAliveHandler
{
friend class ClearWindowAllowedRunnable;
nsCOMPtr<nsITimer> mTimer;
~AllowWindowInteractionKeepAliveHandler()
{
MOZ_ASSERT(!mTimer);
}
void
ClearWindowAllowed(WorkerPrivate* aWorkerPrivate)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
if (mTimer) {
aWorkerPrivate->GlobalScope()->ConsumeWindowInteraction();
mTimer->Cancel();
mTimer = nullptr;
MOZ_ALWAYS_TRUE(aWorkerPrivate->ModifyBusyCountFromWorker(aWorkerPrivate->GetJSContext(), false));
}
}
void
StartClearWindowTimer(WorkerPrivate* aWorkerPrivate)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(!mTimer);
nsresult rv;
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
nsRefPtr<ClearWindowAllowedRunnable> r =
new ClearWindowAllowedRunnable(aWorkerPrivate, this);
nsRefPtr<TimerThreadEventTarget> target =
new TimerThreadEventTarget(aWorkerPrivate, r);
rv = timer->SetTarget(target);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
// The important stuff that *has* to be reversed.
if (NS_WARN_IF(!aWorkerPrivate->ModifyBusyCountFromWorker(aWorkerPrivate->GetJSContext(), true))) {
return;
}
aWorkerPrivate->GlobalScope()->AllowWindowInteraction();
timer.swap(mTimer);
// We swap first and then initialize the timer so that even if initializing
// fails, we still clean the busy count and interaction count correctly.
// The timer can't be initialized before modifying the busy count since the
// timer thread could run and call the timeout but the worker may
// already be terminating and modifying the busy count could fail.
rv = mTimer->InitWithFuncCallback(DummyCallback, nullptr, gDOMDisableOpenClickDelay, nsITimer::TYPE_ONE_SHOT);
if (NS_WARN_IF(NS_FAILED(rv))) {
ClearWindowAllowed(aWorkerPrivate);
return;
}
}
public:
NS_DECL_ISUPPORTS_INHERITED
AllowWindowInteractionKeepAliveHandler(const nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
WorkerPrivate* aWorkerPrivate)
: KeepAliveHandler(aServiceWorker)
{
StartClearWindowTimer(aWorkerPrivate);
}
void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
ClearWindowAllowed(worker);
KeepAliveHandler::ResolvedCallback(aCx, aValue);
}
void
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
ClearWindowAllowed(worker);
KeepAliveHandler::RejectedCallback(aCx, aValue);
}
};
NS_IMPL_ISUPPORTS_INHERITED0(AllowWindowInteractionKeepAliveHandler, KeepAliveHandler)
bool
ClearWindowAllowedRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
mHandler->ClearWindowAllowed(aWorkerPrivate);
return true;
}
// Returns a Promise if the event was successfully dispatched and no exceptions
// were raised, otherwise returns null.
already_AddRefed<Promise>
@ -2376,12 +2516,17 @@ public:
return false;
}
aWorkerPrivate->GlobalScope()->AllowWindowInteraction();
event->SetTrusted(true);
nsRefPtr<Promise> waitUntilPromise =
DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(), event);
// If the handler calls WaitUntil(), that will manage its own interaction
// 'stack'.
aWorkerPrivate->GlobalScope()->ConsumeWindowInteraction();
if (waitUntilPromise) {
nsRefPtr<KeepAliveHandler> handler = new KeepAliveHandler(mServiceWorker);
nsRefPtr<AllowWindowInteractionKeepAliveHandler> handler =
new AllowWindowInteractionKeepAliveHandler(mServiceWorker, aWorkerPrivate);
waitUntilPromise->AppendNativeHandler(handler);
}
@ -2407,6 +2552,8 @@ ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix
return NS_ERROR_INVALID_ARG;
}
gDOMDisableOpenClickDelay = Preferences::GetInt("dom.disable_open_click_delay");
nsRefPtr<ServiceWorker> serviceWorker =
CreateServiceWorkerForScope(attrs, aScope, nullptr);
if (!serviceWorker) {
@ -2785,10 +2932,12 @@ ServiceWorkerManager::HandleError(JSContext* aCx,
nsString aLine,
uint32_t aLineNumber,
uint32_t aColumnNumber,
uint32_t aFlags)
uint32_t aFlags,
JSExnType aExnType)
{
AssertIsOnMainThread();
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(!JSREPORT_IS_WARNING(aFlags));
nsAutoCString scopeKey;
nsresult rv = PrincipalToScopeKey(aPrincipal, scopeKey);
@ -2824,7 +2973,7 @@ ServiceWorkerManager::HandleError(JSContext* aCx,
"Script error caused ServiceWorker registration to fail: %s:%u '%s'",
NS_ConvertUTF16toUTF8(aFilename).get(), aLineNumber,
NS_ConvertUTF16toUTF8(aMessage).get()).get());
regJob->Fail(init);
regJob->Fail(aExnType, init);
}
return true;
@ -4006,7 +4155,8 @@ ServiceWorkerManager::InvalidateServiceWorkerRegistrationWorker(ServiceWorkerReg
void
ServiceWorkerManager::SoftUpdate(nsIPrincipal* aPrincipal,
const nsACString& aScope)
const nsACString& aScope,
ServiceWorkerUpdateFinishCallback* aCallback)
{
MOZ_ASSERT(aPrincipal);
@ -4016,21 +4166,23 @@ ServiceWorkerManager::SoftUpdate(nsIPrincipal* aPrincipal,
return;
}
SoftUpdate(scopeKey, aScope);
SoftUpdate(scopeKey, aScope, aCallback);
}
void
ServiceWorkerManager::SoftUpdate(const OriginAttributes& aOriginAttributes,
const nsACString& aScope)
const nsACString& aScope,
ServiceWorkerUpdateFinishCallback* aCallback)
{
nsAutoCString scopeKey;
aOriginAttributes.CreateSuffix(scopeKey);
SoftUpdate(scopeKey, aScope);
SoftUpdate(scopeKey, aScope, aCallback);
}
void
ServiceWorkerManager::SoftUpdate(const nsACString& aScopeKey,
const nsACString& aScope)
const nsACString& aScope,
ServiceWorkerUpdateFinishCallback* aCallback)
{
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
GetRegistration(aScopeKey, aScope);
@ -4063,8 +4215,10 @@ ServiceWorkerManager::SoftUpdate(const nsACString& aScopeKey,
GetOrCreateJobQueue(aScopeKey, aScope);
MOZ_ASSERT(queue);
nsRefPtr<ServiceWorkerUpdateFinishCallback> cb =
new ServiceWorkerUpdateFinishCallback();
nsRefPtr<ServiceWorkerUpdateFinishCallback> cb(aCallback);
if (!cb) {
cb = new ServiceWorkerUpdateFinishCallback();
}
// "Invoke Update algorithm, or its equivalent, with client, registration as
// its argument."

37
dom/workers/ServiceWorkerManager.h

@ -128,6 +128,28 @@ public:
};
class ServiceWorkerUpdateFinishCallback
{
protected:
virtual ~ServiceWorkerUpdateFinishCallback()
{ }
public:
NS_INLINE_DECL_REFCOUNTING(ServiceWorkerUpdateFinishCallback)
virtual
void UpdateSucceeded(ServiceWorkerRegistrationInfo* aInfo)
{ }
virtual
void UpdateFailed(nsresult aStatus)
{ }
virtual
void UpdateFailed(JSExnType aExnType, const ErrorEventInit& aDesc)
{ }
};
/*
* Wherever the spec treats a worker instance and a description of said worker
* as the same thing; i.e. "Resolve foo with
@ -299,10 +321,14 @@ public:
ErrorResult& aRv);
void
SoftUpdate(nsIPrincipal* aPrincipal, const nsACString& aScope);
SoftUpdate(nsIPrincipal* aPrincipal,
const nsACString& aScope,
ServiceWorkerUpdateFinishCallback* aCallback = nullptr);
void
SoftUpdate(const OriginAttributes& aOriginAttributes, const nsACString& aScope);
SoftUpdate(const OriginAttributes& aOriginAttributes,
const nsACString& aScope,
ServiceWorkerUpdateFinishCallback* aCallback = nullptr);
void
PropagateSoftUpdate(const OriginAttributes& aOriginAttributes,
@ -347,7 +373,8 @@ public:
nsString aLine,
uint32_t aLineNumber,
uint32_t aColumnNumber,
uint32_t aFlags);
uint32_t aFlags,
JSExnType aExnType);
void
GetAllClients(nsIPrincipal* aPrincipal,
@ -402,7 +429,9 @@ private:
MaybeRemoveRegistrationInfo(const nsACString& aScopeKey);
void
SoftUpdate(const nsACString& aScopeKey, const nsACString& aScope);
SoftUpdate(const nsACString& aScopeKey,
const nsACString& aScope,
ServiceWorkerUpdateFinishCallback* aCallback = nullptr);
already_AddRefed<ServiceWorkerRegistrationInfo>
GetRegistration(const nsACString& aScopeKey,

2
dom/workers/ServiceWorkerManagerChild.cpp

@ -42,7 +42,7 @@ ServiceWorkerManagerChild::RecvNotifySoftUpdate(
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
swm->SoftUpdate(aOriginAttributes, NS_ConvertUTF16toUTF8(aScope));
swm->SoftUpdate(aOriginAttributes, NS_ConvertUTF16toUTF8(aScope), nullptr);
return true;
}

231
dom/workers/ServiceWorkerRegistration.cpp

@ -239,103 +239,167 @@ ServiceWorkerRegistrationMainThread::InvalidateWorkers(WhichServiceWorker aWhich
namespace {
void
UpdateInternal(nsIPrincipal* aPrincipal, const nsAString& aScope)
UpdateInternal(nsIPrincipal* aPrincipal,
const nsAString& aScope,
ServiceWorkerUpdateFinishCallback* aCallback)
{
AssertIsOnMainThread();
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aCallback);
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
// The spec defines ServiceWorkerRegistration.update() exactly as Soft Update.
swm->SoftUpdate(aPrincipal, NS_ConvertUTF16toUTF8(aScope));
swm->SoftUpdate(aPrincipal, NS_ConvertUTF16toUTF8(aScope), aCallback);
}
// This Runnable needs to have a valid WorkerPrivate. For this reason it is also
// a WorkerFeature that is registered before dispatching itself to the
// main-thread and it's removed with ReleaseRunnable when the operation is
// completed. This will keep the worker alive as long as necessary.
class UpdateRunnable final : public nsRunnable
, public WorkerFeature
class MainThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback
{
public:
UpdateRunnable(WorkerPrivate* aWorkerPrivate, const nsAString& aScope)
: mWorkerPrivate(aWorkerPrivate)
, mScope(aScope)
{}
nsRefPtr<Promise> mPromise;
NS_IMETHOD
Run() override
~MainThreadUpdateCallback()
{ }
public:
explicit MainThreadUpdateCallback(Promise* aPromise)
: mPromise(aPromise)
{
AssertIsOnMainThread();
UpdateInternal(mWorkerPrivate->GetPrincipal(), mScope);
}
class ReleaseRunnable final : public MainThreadWorkerControlRunnable
{
nsRefPtr<UpdateRunnable> mFeature;
public:
ReleaseRunnable(WorkerPrivate* aWorkerPrivate,
UpdateRunnable* aFeature)
: MainThreadWorkerControlRunnable(aWorkerPrivate)
, mFeature(aFeature)
{
MOZ_ASSERT(aFeature);
}
void
UpdateSucceeded(ServiceWorkerRegistrationInfo* aRegistration) override
{
mPromise->MaybeResolve(JS::UndefinedHandleValue);
}
virtual bool
WorkerRun(JSContext* aCx,
workers::WorkerPrivate* aWorkerPrivate) override
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
using ServiceWorkerUpdateFinishCallback::UpdateFailed;
aWorkerPrivate->RemoveFeature(aCx, mFeature);
return true;
}
void
UpdateFailed(nsresult aStatus) override
{
mPromise->MaybeReject(aStatus);
}
};
private:
~ReleaseRunnable()
{}
};
class UpdateResultRunnable final : public WorkerRunnable
{
nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
nsresult mStatus;
nsRefPtr<WorkerControlRunnable> runnable =
new ReleaseRunnable(mWorkerPrivate, this);
runnable->Dispatch(nullptr);
~UpdateResultRunnable()
{}
return NS_OK;
}
public:
UpdateResultRunnable(PromiseWorkerProxy* aPromiseProxy, nsresult aStatus)
: WorkerRunnable(aPromiseProxy->GetWorkerPrivate(), WorkerThreadModifyBusyCount)
, mPromiseProxy(aPromiseProxy)
, mStatus(aStatus)
{ }
virtual bool Notify(JSContext* aCx, workers::Status aStatus) override
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
// We don't care about the notification. We just want to keep the
// mWorkerPrivate alive.
Promise* promise = mPromiseProxy->GetWorkerPromise();
if (NS_SUCCEEDED(mStatus)) {
promise->MaybeResolve(JS::UndefinedHandleValue);
} else {
promise->MaybeReject(mStatus);
}
mPromiseProxy->CleanUp(aCx);
return true;
}
};
bool
Dispatch()
class WorkerThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback
{
nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
~WorkerThreadUpdateCallback()
{
mWorkerPrivate->AssertIsOnWorkerThread();
Finish(NS_ERROR_FAILURE);
}
public:
explicit WorkerThreadUpdateCallback(PromiseWorkerProxy* aPromiseProxy)
: mPromiseProxy(aPromiseProxy)
{
AssertIsOnMainThread();
}
void
UpdateSucceeded(ServiceWorkerRegistrationInfo* aRegistration) override
{
Finish(NS_OK);
}
using ServiceWorkerUpdateFinishCallback::UpdateFailed;
void
UpdateFailed(nsresult aStatus) override
{
Finish(aStatus);
}
void
Finish(nsresult aStatus)
{
if (!mPromiseProxy) {
return;
}
JSContext* cx = mWorkerPrivate->GetJSContext();
nsRefPtr<PromiseWorkerProxy> proxy = mPromiseProxy.forget();
if (NS_WARN_IF(!mWorkerPrivate->AddFeature(cx, this))) {
return false;
MutexAutoLock lock(proxy->GetCleanUpLock());
if (proxy->IsClean()) {
return;
}
nsCOMPtr<nsIRunnable> that(this);
if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(this)))) {
NS_ASSERTION(false, "Failed to dispatch update back to MainThread in ServiceWorker");
AutoJSAPI jsapi;
jsapi.Init();
nsRefPtr<UpdateResultRunnable> r =
new UpdateResultRunnable(proxy, aStatus);
if (!r->Dispatch(jsapi.cx())) {
nsRefPtr<PromiseWorkerProxyControlRunnable> r =
new PromiseWorkerProxyControlRunnable(proxy->GetWorkerPrivate(), proxy);
r->Dispatch(jsapi.cx());
}
return true;
}
};
class UpdateRunnable final : public nsRunnable
{
public:
UpdateRunnable(PromiseWorkerProxy* aPromiseProxy,
const nsAString& aScope)
: mPromiseProxy(aPromiseProxy)
, mScope(aScope)
{}
NS_IMETHOD
Run() override
{
AssertIsOnMainThread();
ErrorResult result;
MutexAutoLock lock(mPromiseProxy->GetCleanUpLock());
if (mPromiseProxy->IsClean()) {
return NS_OK;
}
nsRefPtr<WorkerThreadUpdateCallback> cb =
new WorkerThreadUpdateCallback(mPromiseProxy);
UpdateInternal(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(), mScope, cb);
return NS_OK;
}
private:
~UpdateRunnable()
{}
WorkerPrivate* mWorkerPrivate;
nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
const nsString mScope;
};
@ -523,15 +587,31 @@ public:
return NS_OK;
}
};
} // anonymous namespace
} // namespace
void
ServiceWorkerRegistrationMainThread::Update()
already_AddRefed<Promise>
ServiceWorkerRegistrationMainThread::Update(ErrorResult& aRv)
{
AssertIsOnMainThread();
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(GetOwner());
if (!go) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(go, aRv);
if (NS_WARN_IF(aRv.Failed())) {