Merge mozilla-central to autoland. r=merge a=merge on a CLOSED TREE

This commit is contained in:
Narcis Beleuzu 2017-12-13 12:22:54 +02:00
Родитель a72a31a227 b0098afaea
Коммит 0fff6b87cf
82 изменённых файлов: 1551 добавлений и 2798 удалений

Просмотреть файл

@ -1626,7 +1626,6 @@ pref("reader.errors.includeURLs", true);
pref("view_source.tab", true);
pref("dom.serviceWorkers.enabled", true);
pref("dom.serviceWorkers.openWindow.enabled", true);
// Enable Push API.
pref("dom.push.enabled", true);

Просмотреть файл

@ -994,6 +994,7 @@ add_old_configure_assignment('MOZ_BUILD_APP', build_project)
# - otherwise, we're building Release/Beta (define RELEASE_OR_BETA)
@depends(check_build_environment, '--help')
@imports(_from='__builtin__', _import='open')
@imports('re')
def milestone(build_env, _):
milestone_path = os.path.join(build_env.topsrcdir,
'config',
@ -1008,7 +1009,18 @@ def milestone(build_env, _):
elif 'a' not in milestone:
is_release_or_beta = True
major_version = milestone.split('.')[0]
m = re.search(r"([ab]\d+)", milestone)
ab_patch = m.group(1) if m else ''
# Only expose the major version milestone in the UA string and hide the
# patch leve (bugs 572659 and 870868).
#
# Only expose major milestone and alpha version in the symbolversion
# string; as the name suggests, we use it for symbol versioning on Linux.
return namespace(version=milestone,
uaversion='%s.0' % major_version,
symbolversion='%s%s' % (major_version, ab_patch),
is_nightly=is_nightly,
is_release_or_beta=is_release_or_beta)
@ -1021,6 +1033,14 @@ set_config('RELEASE_OR_BETA', milestone.is_release_or_beta)
set_define('RELEASE_OR_BETA', milestone.is_release_or_beta)
add_old_configure_assignment('RELEASE_OR_BETA',
milestone.is_release_or_beta)
set_define('MOZILLA_VERSION', depends(milestone)(lambda m: '"%s"' % m.version))
set_config('MOZILLA_VERSION', milestone.version)
set_define('MOZILLA_VERSION_U', milestone.version)
set_define('MOZILLA_UAVERSION', depends(milestone)(lambda m: '"%s"' % m.uaversion))
set_config('MOZILLA_SYMBOLVERSION', milestone.symbolversion)
# JS configure still wants to look at these.
add_old_configure_assignment('MOZILLA_VERSION', milestone.version)
add_old_configure_assignment('MOZILLA_SYMBOLVERSION', milestone.symbolversion)
# The app update channel is 'default' when not supplied. The value is used in
# the application's confvars.sh (and is made available to a project specific

Просмотреть файл

@ -5,7 +5,7 @@
# x.x.x.x
# x.x.x+
#
# Referenced by milestone.py.
# Referenced by build/moz.configure/init.configure.
# Hopefully I'll be able to automate replacement of *all*
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------

Просмотреть файл

@ -27,10 +27,6 @@
#include "sunos4.h"
#endif
#ifndef D_INO
#define D_INO d_ino
#endif
char *program;
void
@ -108,7 +104,7 @@ ino2name(ino_t ino)
for (;;) {
if (!(ep = readdir(dp)))
fail("cannot find current directory");
if (ep->D_INO == ino)
if (ep->d_ino == ino)
break;
}
name = xstrdup(ep->d_name);

Просмотреть файл

@ -47,6 +47,7 @@ skip-if = !e10s # This test is only valid in e10s
[browser_service_workers_not_compatible.js]
[browser_service_workers_push.js]
[browser_service_workers_push_service.js]
skip-if = !e10s # Bug 1424895
[browser_service_workers_start.js]
[browser_service_workers_status.js]
[browser_service_workers_timeout.js]

Просмотреть файл

@ -15279,18 +15279,13 @@ nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel)
if (!doc) {
return NS_ERROR_NOT_AVAILABLE;
}
} else {
// For top-level navigations, save a document ID which will be passed to
// the FetchEvent as the clientId later on.
rv = nsIDocument::GenerateDocumentId(mInterceptedDocumentId);
NS_ENSURE_SUCCESS(rv, rv);
}
bool isReload = mLoadType & LOAD_CMD_RELOAD;
ErrorResult error;
swm->DispatchFetchEvent(mOriginAttributes, doc, mInterceptedDocumentId,
aChannel, isReload, isSubresourceLoad, error);
swm->DispatchFetchEvent(mOriginAttributes, doc, aChannel, isReload,
isSubresourceLoad, error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}

Просмотреть файл

@ -374,11 +374,6 @@ public:
nsresult SetOriginAttributes(const mozilla::OriginAttributes& aAttrs);
void GetInterceptedDocumentId(nsAString& aId)
{
aId = mInterceptedDocumentId;
}
private:
// An observed docshell wrapper is created when recording markers is enabled.
mozilla::UniquePtr<mozilla::ObservedDocShell> mObserved;
@ -1151,8 +1146,6 @@ protected:
// origin attribute set.
uint32_t mPrivateBrowsingId;
nsString mInterceptedDocumentId;
// This represents the CSS display-mode we are currently using.
// It can be any of the following values from nsIDocShell.idl:
//

Просмотреть файл

@ -2957,6 +2957,8 @@ public:
eSessionScoped = 2,
// Allow access to the storage
eAllow = 3,
// Keep this at the end. Used for serialization, but not a valid value.
eNumValues = 4,
};
/*

Просмотреть файл

@ -1864,7 +1864,6 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIRadioGroupContainer)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIObserver)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMXPathEvaluator)
NS_INTERFACE_TABLE_END
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument)
@ -5136,28 +5135,6 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
}
swm->MaybeStopControlling(this);
}
// Remove ourself from the list of clients. We only register
// content principal documents in this list.
if (!nsContentUtils::IsSystemPrincipal(GetPrincipal()) &&
!GetPrincipal()->GetIsNullPrincipal()) {
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
os->RemoveObserver(this, "service-worker-get-client");
}
}
} else if (!mScriptGlobalObject && aScriptGlobalObject &&
mDocumentContainer && GetChannel() &&
!nsContentUtils::IsSystemPrincipal(GetPrincipal()) &&
!GetPrincipal()->GetIsNullPrincipal()) {
// This document is being activated. Register it in the list of
// clients. We only do this for content principal documents
// since we can never observe system or null principals.
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
os->AddObserver(this, "service-worker-get-client", /* ownsWeak */ false);
}
}
// BlockOnload() might be called before mScriptGlobalObject is set.
@ -5278,15 +5255,7 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (swm) {
// If this document is being resurrected from the bfcache, then we may
// already have a document ID. In that case reuse the same ID. Otherwise
// get our document ID from the docshell.
nsString documentId(GetId());
if (documentId.IsEmpty()) {
static_cast<nsDocShell*>(docShell.get())->GetInterceptedDocumentId(documentId);
}
swm->MaybeStartControlling(this, documentId);
swm->MaybeStartControlling(this);
mMaybeServiceWorkerControlled = true;
}
}
@ -12442,32 +12411,6 @@ nsIDocument::GetPointerLockElement()
return pointerLockedElement;
}
nsresult
nsDocument::Observe(nsISupports *aSubject,
const char *aTopic,
const char16_t *aData)
{
if (strcmp("service-worker-get-client", aTopic) == 0) {
// No need to generate the ID if it doesn't exist here. The ID being
// requested must already be generated in order to passed in as
// aSubject.
nsString clientId = GetId();
if (!clientId.IsEmpty() && clientId.Equals(aData)) {
nsCOMPtr<nsISupportsInterfacePointer> ifptr = do_QueryInterface(aSubject);
if (ifptr) {
#ifdef DEBUG
nsCOMPtr<nsISupports> value;
MOZ_ALWAYS_SUCCEEDS(ifptr->GetData(getter_AddRefs(value)));
MOZ_ASSERT(!value);
#endif
ifptr->SetData(static_cast<nsIDocument*>(this));
ifptr->SetDataIID(&NS_GET_IID(nsIDocument));
}
}
}
return NS_OK;
}
void
nsDocument::UpdateVisibilityState()
{
@ -13197,49 +13140,6 @@ nsIDocument::CreateHTMLElement(nsAtom* aTag)
return element.forget();
}
/* static */
nsresult
nsIDocument::GenerateDocumentId(nsAString& aId)
{
nsID id;
nsresult rv = nsContentUtils::GenerateUUIDInPlace(id);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Build a string in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} format
char buffer[NSID_LENGTH];
id.ToProvidedString(buffer);
NS_ConvertASCIItoUTF16 uuid(buffer);
// Remove {} and the null terminator
aId.Assign(Substring(uuid, 1, NSID_LENGTH - 3));
return NS_OK;
}
nsresult
nsIDocument::GetOrCreateId(nsAString& aId)
{
if (mId.IsEmpty()) {
nsresult rv = GenerateDocumentId(mId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
aId = mId;
return NS_OK;
}
void
nsIDocument::SetId(const nsAString& aId)
{
// The ID should only be set one time, but we may get the same value
// more than once if the document is controlled coming out of bfcache.
MOZ_ASSERT_IF(mId != aId, mId.IsEmpty());
mId = aId;
}
bool
MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData)
{

Просмотреть файл

@ -359,7 +359,6 @@ class nsDocument : public nsIDocument,
public nsIRadioGroupContainer,
public nsIApplicationCacheContainer,
public nsStubMutationObserver,
public nsIObserver,
public nsIDOMXPathEvaluator
{
friend class nsIDocument;
@ -698,9 +697,6 @@ public:
// nsIApplicationCacheContainer
NS_DECL_NSIAPPLICATIONCACHECONTAINER
// nsIObserver
NS_DECL_NSIOBSERVER
NS_DECL_NSIDOMXPATHEVALUATOR
virtual nsresult Init();

Просмотреть файл

@ -1087,10 +1087,6 @@ public:
return mAnonymousContents;
}
static nsresult GenerateDocumentId(nsAString& aId);
nsresult GetOrCreateId(nsAString& aId);
void SetId(const nsAString& aId);
mozilla::TimeStamp GetPageUnloadingEventTimeStamp() const
{
if (!mParentDocument) {
@ -3333,11 +3329,6 @@ protected:
FlushUserFontSet();
}
const nsString& GetId() const
{
return mId;
}
// Update our frame request callback scheduling state, if needed. This will
// schedule or unschedule them, if necessary, and update
// mFrameRequestCallbacksScheduled. aOldShell should only be passed when
@ -3696,7 +3687,6 @@ protected:
nsCOMPtr<nsIChannel> mChannel;
private:
nsCString mContentType;
nsString mId;
protected:
// The document's security info

Просмотреть файл

@ -149,16 +149,6 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::workers::ChromeWorkerPrivate',
},
'Client': {
'nativeType': 'mozilla::dom::workers::ServiceWorkerClient',
'headerFile': 'mozilla/dom/workers/bindings/ServiceWorkerClient.h',
},
'Clients': {
'nativeType': 'mozilla::dom::workers::ServiceWorkerClients',
'headerFile': 'mozilla/dom/workers/bindings/ServiceWorkerClients.h',
},
'console': {
'nativeType': 'mozilla::dom::Console',
},
@ -1111,8 +1101,7 @@ DOMInterfaces = {
},
'WindowClient': {
'nativeType': 'mozilla::dom::workers::ServiceWorkerWindowClient',
'headerFile': 'mozilla/dom/workers/bindings/ServiceWorkerWindowClient.h',
'nativeType': 'mozilla::dom::Client',
},
'WebGLActiveInfo': {

245
dom/clients/api/Client.cpp Normal file
Просмотреть файл

@ -0,0 +1,245 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "Client.h"
#include "ClientDOMUtil.h"
#include "mozilla/dom/ClientHandle.h"
#include "mozilla/dom/ClientIPCTypes.h"
#include "mozilla/dom/ClientManager.h"
#include "mozilla/dom/ClientState.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerScope.h"
#include "nsIGlobalObject.h"
namespace mozilla {
namespace dom {
using mozilla::dom::workers::Closing;
using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
using mozilla::dom::workers::WorkerHolderToken;
using mozilla::dom::workers::WorkerPrivate;
using mozilla::dom::ipc::StructuredCloneData;
NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::Client);
NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::Client);
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(mozilla::dom::Client, mGlobal);
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(mozilla::dom::Client)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
void
Client::EnsureHandle()
{
NS_ASSERT_OWNINGTHREAD(mozilla::dom::Client);
if (!mHandle) {
mHandle = ClientManager::CreateHandle(ClientInfo(mData->info()),
mGlobal->EventTargetFor(TaskCategory::Other));
}
}
Client::Client(nsIGlobalObject* aGlobal, const ClientInfoAndState& aData)
: mGlobal(aGlobal)
, mData(MakeUnique<ClientInfoAndState>(aData))
{
MOZ_DIAGNOSTIC_ASSERT(mGlobal);
}
TimeStamp
Client::CreationTime() const
{
return mData->info().creationTime();
}
TimeStamp
Client::LastFocusTime() const
{
if (mData->info().type() != ClientType::Window) {
return TimeStamp();
}
return mData->state().get_IPCClientWindowState().lastFocusTime();
}
nsContentUtils::StorageAccess
Client::GetStorageAccess() const
{
ClientState state(ClientState::FromIPC(mData->state()));
return state.GetStorageAccess();
}
JSObject*
Client::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
if (mData->info().type() == ClientType::Window) {
return WindowClientBinding::Wrap(aCx, this, aGivenProto);
}
return ClientBinding::Wrap(aCx, this, aGivenProto);
}
nsIGlobalObject*
Client::GetParentObject() const
{
return mGlobal;
}
void
Client::GetUrl(nsAString& aUrlOut) const
{
CopyUTF8toUTF16(mData->info().url(), aUrlOut);
}
void
Client::GetId(nsAString& aIdOut) const
{
char buf[NSID_LENGTH];
mData->info().id().ToProvidedString(buf);
NS_ConvertASCIItoUTF16 uuid(buf);
// Remove {} and the null terminator
aIdOut.Assign(Substring(uuid, 1, NSID_LENGTH - 3));
}
ClientType
Client::Type() const
{
return mData->info().type();
}
FrameType
Client::GetFrameType() const
{
return mData->info().frameType();
}
void
Client::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv)
{
MOZ_ASSERT(!NS_IsMainThread());
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
MOZ_DIAGNOSTIC_ASSERT(workerPrivate->IsServiceWorker());
workerPrivate->AssertIsOnWorkerThread();
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
&transferable);
if (aRv.Failed()) {
return;
}
StructuredCloneData data;
data.Write(aCx, aMessage, transferable, aRv);
if (aRv.Failed()) {
return;
}
EnsureHandle();
mHandle->PostMessage(data, workerPrivate->GetServiceWorkerDescriptor());
}
VisibilityState
Client::GetVisibilityState() const
{
return mData->state().get_IPCClientWindowState().visibilityState();
}
bool
Client::Focused() const
{
return mData->state().get_IPCClientWindowState().focused();
}
already_AddRefed<Promise>
Client::Focus(ErrorResult& aRv)
{
MOZ_ASSERT(!NS_IsMainThread());
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
MOZ_DIAGNOSTIC_ASSERT(workerPrivate->IsServiceWorker());
workerPrivate->AssertIsOnWorkerThread();
RefPtr<Promise> outerPromise = Promise::Create(mGlobal, aRv);
if (aRv.Failed()) {
return outerPromise.forget();
}
if (!workerPrivate->GlobalScope()->WindowInteractionAllowed()) {
outerPromise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return outerPromise.forget();
}
// Hold the worker thread alive while we perform the async operation
// and also avoid invoking callbacks if the worker starts shutting
// down.
RefPtr<WorkerHolderToken> token =
WorkerHolderToken::Create(GetCurrentThreadWorkerPrivate(), Closing);
EnsureHandle();
RefPtr<ClientStatePromise> innerPromise = mHandle->Focus();
RefPtr<Client> self = this;
innerPromise->Then(mGlobal->EventTargetFor(TaskCategory::Other), __func__,
[self, token, outerPromise] (const ClientState& aResult) {
if (token->IsShuttingDown()) {
return;
}
RefPtr<Client> newClient =
new Client(self->mGlobal, ClientInfoAndState(self->mData->info(), aResult.ToIPC()));
outerPromise->MaybeResolve(newClient);
}, [self, token, outerPromise] (nsresult aResult) {
if (token->IsShuttingDown()) {
return;
}
outerPromise->MaybeReject(aResult);
});
return outerPromise.forget();
}
already_AddRefed<Promise>
Client::Navigate(const nsAString& aURL, ErrorResult& aRv)
{
MOZ_ASSERT(!NS_IsMainThread());
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
MOZ_DIAGNOSTIC_ASSERT(workerPrivate->IsServiceWorker());
workerPrivate->AssertIsOnWorkerThread();
RefPtr<Promise> outerPromise = Promise::Create(mGlobal, aRv);
if (aRv.Failed()) {
return outerPromise.forget();
}
ClientNavigateArgs args(mData->info(), NS_ConvertUTF16toUTF8(aURL),
workerPrivate->GetLocationInfo().mHref);
RefPtr<Client> self = this;
StartClientManagerOp(&ClientManager::Navigate, args,
mGlobal->EventTargetFor(TaskCategory::Other),
[self, outerPromise] (const ClientOpResult& aResult) {
if (aResult.type() != ClientOpResult::TClientInfoAndState) {
outerPromise->MaybeResolve(JS::NullHandleValue);
return;
}
RefPtr<Client> newClient =
new Client(self->mGlobal, aResult.get_ClientInfoAndState());
outerPromise->MaybeResolve(newClient);
}, [self, outerPromise] (nsresult aResult) {
// TODO: Improve this error in bug 1412856. Ideally we should throw
// the TypeError in the child process and pass it back to here.
outerPromise->MaybeReject(NS_ERROR_TYPE_ERR);
});
return outerPromise.forget();
}
} // namespace dom
} // namespace mozilla

99
dom/clients/api/Client.h Normal file
Просмотреть файл

@ -0,0 +1,99 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef _mozilla_dom_Client_h
#define _mozilla_dom_Client_h
#include "mozilla/dom/ClientBinding.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nsISupports.h"
#include "nsWrapperCache.h"
class nsIGlobalObject;
namespace mozilla {
class ErrorResult;
namespace dom {
class ClientHandle;
class ClientInfoAndState;
class Promise;
template <typename t> class Sequence;
class Client final : public nsISupports
, public nsWrapperCache
{
nsCOMPtr<nsIGlobalObject> mGlobal;
UniquePtr<ClientInfoAndState> mData;
RefPtr<ClientHandle> mHandle;
~Client() = default;
void
EnsureHandle();
public:
Client(nsIGlobalObject* aGlobal, const ClientInfoAndState& aData);
TimeStamp
CreationTime() const;
TimeStamp
LastFocusTime() const;
nsContentUtils::StorageAccess
GetStorageAccess() const;
// nsWrapperCache interface methods
JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// DOM bindings methods
nsIGlobalObject*
GetParentObject() const;
// Client Bindings
void
GetUrl(nsAString& aUrlOut) const;
void
GetId(nsAString& aIdOut) const;
ClientType
Type() const;
FrameType
GetFrameType() const;
// WindowClient bindings
VisibilityState
GetVisibilityState() const;
bool
Focused() const;
already_AddRefed<Promise>
Focus(ErrorResult& aRv);
already_AddRefed<Promise>
Navigate(const nsAString& aURL, ErrorResult& aRv);
void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferrable,
ErrorResult& aRv);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(mozilla::dom::Client)
};
} // namespace dom
} // namespace mozilla
#endif // _mozilla_dom_Client_h

Просмотреть файл

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef _mozilla_dom_ClientDOMUtil_h
#define _mozilla_dom_ClientDOMUtil_h
#include "mozilla/dom/ClientIPCTypes.h"
#include "mozilla/dom/ClientOpPromise.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/workers/bindings/WorkerHolderToken.h"
class nsIGlobalObject;
namespace mozilla {
namespace dom {
// Utility method to properly execute a ClientManager operation. It
// will properly hold a worker thread alive and avoid executing callbacks
// if the thread is shutting down.
template<typename Func, typename Arg, typename Resolve, typename Reject>
void
StartClientManagerOp(Func aFunc, const Arg& aArg, nsISerialEventTarget* aTarget,
Resolve aResolve, Reject aReject)
{
using mozilla::dom::workers::Closing;
using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
using mozilla::dom::workers::WorkerHolderToken;
RefPtr<WorkerHolderToken> token;
if (!NS_IsMainThread()) {
token = WorkerHolderToken::Create(GetCurrentThreadWorkerPrivate(), Closing);
}
RefPtr<ClientOpPromise> promise = aFunc(aArg, aTarget);
promise->Then(aTarget, __func__,
[aResolve, token](const ClientOpResult& aResult) {
if (token && token->IsShuttingDown()) {
return;
}
aResolve(aResult);
}, [aReject, token](nsresult aResult) {
if (token && token->IsShuttingDown()) {
return;
}
aReject(aResult);
});
}
} // namespace dom
} // namespace mozilla
#endif // _mozilla_dom_ClientDOMUtil_h

285
dom/clients/api/Clients.cpp Normal file
Просмотреть файл

@ -0,0 +1,285 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "Clients.h"
#include "ClientDOMUtil.h"
#include "mozilla/dom/ClientIPCTypes.h"
#include "mozilla/dom/ClientManager.h"
#include "mozilla/dom/ClientsBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ServiceWorkerDescriptor.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h"
#include "mozilla/SystemGroup.h"
#include "nsIGlobalObject.h"
#include "nsString.h"
namespace mozilla {
namespace dom {
using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
using mozilla::dom::workers::WorkerPrivate;
using mozilla::dom::workers::ServiceWorkerManager;
using mozilla::ipc::PrincipalInfo;
NS_IMPL_CYCLE_COLLECTING_ADDREF(Clients);
NS_IMPL_CYCLE_COLLECTING_RELEASE(Clients);
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Clients, mGlobal);
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Clients)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
Clients::Clients(nsIGlobalObject* aGlobal)
: mGlobal(aGlobal)
{
MOZ_DIAGNOSTIC_ASSERT(mGlobal);
}
JSObject*
Clients::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return ClientsBinding::Wrap(aCx, this, aGivenProto);
}
nsIGlobalObject*
Clients::GetParentObject() const
{
return mGlobal;
}
already_AddRefed<Promise>
Clients::Get(const nsAString& aClientID, ErrorResult& aRv)
{
MOZ_ASSERT(!NS_IsMainThread());
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
MOZ_DIAGNOSTIC_ASSERT(workerPrivate->IsServiceWorker());
workerPrivate->AssertIsOnWorkerThread();
RefPtr<Promise> outerPromise = Promise::Create(mGlobal, aRv);
if (aRv.Failed()) {
return outerPromise.forget();
}
nsID id;
if (!id.Parse(NS_ConvertUTF16toUTF8(aClientID).get())) {
// Invalid ID means we will definitely not find a match, so just
// resolve with undefined indicating "not found".
outerPromise->MaybeResolveWithUndefined();
return outerPromise.forget();
}
const PrincipalInfo& principalInfo = workerPrivate->GetPrincipalInfo();
nsCOMPtr<nsISerialEventTarget> target =
mGlobal->EventTargetFor(TaskCategory::Other);
RefPtr<ClientOpPromise> innerPromise =
ClientManager::GetInfoAndState(ClientGetInfoAndStateArgs(id, principalInfo),
target);
nsCOMPtr<nsIGlobalObject> global = mGlobal;
nsCString scope = workerPrivate->ServiceWorkerScope();
innerPromise->Then(target, __func__,
[outerPromise, global, scope] (const ClientOpResult& aResult) {
RefPtr<Client> client = new Client(global, aResult.get_ClientInfoAndState());
if (client->GetStorageAccess() == nsContentUtils::StorageAccess::eAllow) {
outerPromise->MaybeResolve(Move(client));
return;
}
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("Clients::MatchAll() storage denied",
[scope] {
ServiceWorkerManager::LocalizeAndReportToAllClients(
scope, "ServiceWorkerGetClientStorageError", nsTArray<nsString>());
});
SystemGroup::Dispatch(TaskCategory::Other, r.forget());
outerPromise->MaybeResolveWithUndefined();
}, [outerPromise] (nsresult aResult) {
outerPromise->MaybeResolveWithUndefined();
});
return outerPromise.forget();
}
namespace {
class MatchAllComparator final
{
public:
bool
LessThan(Client* aLeft, Client* aRight) const
{
TimeStamp leftFocusTime = aLeft->LastFocusTime();
TimeStamp rightFocusTime = aRight->LastFocusTime();
// If the focus times are the same, then default to creation order.
// MatchAll should return oldest Clients first.
if (leftFocusTime == rightFocusTime) {
return aLeft->CreationTime() < aRight->CreationTime();
}
// Otherwise compare focus times. We reverse the logic here so
// that the most recently focused window is first in the list.
if (!leftFocusTime.IsNull() && rightFocusTime.IsNull()) {
return true;
}
if (leftFocusTime.IsNull() && !rightFocusTime.IsNull()) {
return false;
}
return leftFocusTime > rightFocusTime;
}
bool
Equals(Client* aLeft, Client* aRight) const
{
return aLeft->LastFocusTime() == aRight->LastFocusTime() &&
aLeft->CreationTime() == aRight->CreationTime();
}
};
} // anonymous namespace
already_AddRefed<Promise>
Clients::MatchAll(const ClientQueryOptions& aOptions, ErrorResult& aRv)
{
MOZ_ASSERT(!NS_IsMainThread());
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
MOZ_DIAGNOSTIC_ASSERT(workerPrivate->IsServiceWorker());
workerPrivate->AssertIsOnWorkerThread();
RefPtr<Promise> outerPromise = Promise::Create(mGlobal, aRv);
if (aRv.Failed()) {
return outerPromise.forget();
}
nsCOMPtr<nsIGlobalObject> global = mGlobal;
nsCString scope = workerPrivate->ServiceWorkerScope();
ClientMatchAllArgs args(workerPrivate->GetServiceWorkerDescriptor().ToIPC(),
aOptions.mType,
aOptions.mIncludeUncontrolled);
StartClientManagerOp(&ClientManager::MatchAll, args,
mGlobal->EventTargetFor(TaskCategory::Other),
[outerPromise, global, scope] (const ClientOpResult& aResult) {
nsTArray<RefPtr<Client>> clientList;
bool storageDenied = false;
for (const ClientInfoAndState& value : aResult.get_ClientList().values()) {
RefPtr<Client> client = new Client(global, value);
if (client->GetStorageAccess() != nsContentUtils::StorageAccess::eAllow) {
storageDenied = true;
continue;
}
clientList.AppendElement(Move(client));
}
if (storageDenied) {
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("Clients::MatchAll() storage denied",
[scope] {
ServiceWorkerManager::LocalizeAndReportToAllClients(
scope, "ServiceWorkerGetClientStorageError", nsTArray<nsString>());
});
SystemGroup::Dispatch(TaskCategory::Other, r.forget());
}
clientList.Sort(MatchAllComparator());
outerPromise->MaybeResolve(clientList);
}, [outerPromise] (nsresult aResult) {
outerPromise->MaybeReject(aResult);
});
return outerPromise.forget();
}
already_AddRefed<Promise>
Clients::OpenWindow(const nsAString& aURL, ErrorResult& aRv)
{
MOZ_ASSERT(!NS_IsMainThread());
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
MOZ_DIAGNOSTIC_ASSERT(workerPrivate->IsServiceWorker());
workerPrivate->AssertIsOnWorkerThread();
RefPtr<Promise> outerPromise = Promise::Create(mGlobal, aRv);
if (aRv.Failed()) {
return outerPromise.forget();
}
if (aURL.EqualsLiteral("about:blank")) {
// TODO: Improve this error in bug 1412856.
outerPromise->MaybeReject(NS_ERROR_DOM_TYPE_ERR);
return outerPromise.forget();
}
if (!workerPrivate->GlobalScope()->WindowInteractionAllowed()) {
outerPromise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return outerPromise.forget();
}
const PrincipalInfo& principalInfo = workerPrivate->GetPrincipalInfo();
nsCString baseURL = workerPrivate->GetLocationInfo().mHref;
ClientOpenWindowArgs args(principalInfo, NS_ConvertUTF16toUTF8(aURL),
baseURL);
nsCOMPtr<nsIGlobalObject> global = mGlobal;
StartClientManagerOp(&ClientManager::OpenWindow, args,
mGlobal->EventTargetFor(TaskCategory::Other),
[outerPromise, global] (const ClientOpResult& aResult) {
if (aResult.type() != ClientOpResult::TClientInfoAndState) {
outerPromise->MaybeResolve(JS::NullHandleValue);
return;
}
RefPtr<Client> client =
new Client(global, aResult.get_ClientInfoAndState());
outerPromise->MaybeResolve(client);
}, [outerPromise] (nsresult aResult) {
// TODO: Improve this error in bug 1412856. Ideally we should throw
// the TypeError in the child process and pass it back to here.
outerPromise->MaybeReject(NS_ERROR_TYPE_ERR);
});
return outerPromise.forget();
}
already_AddRefed<Promise>
Clients::Claim(ErrorResult& aRv)
{
MOZ_ASSERT(!NS_IsMainThread());
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
MOZ_DIAGNOSTIC_ASSERT(workerPrivate->IsServiceWorker());
workerPrivate->AssertIsOnWorkerThread();
RefPtr<Promise> outerPromise = Promise::Create(mGlobal, aRv);
if (aRv.Failed()) {
return outerPromise.forget();
}
const ServiceWorkerDescriptor& serviceWorker =
workerPrivate->GetServiceWorkerDescriptor();
if (serviceWorker.State() != ServiceWorkerState::Activating &&
serviceWorker.State() != ServiceWorkerState::Activated) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return outerPromise.forget();
}
StartClientManagerOp(&ClientManager::Claim, ClientClaimArgs(serviceWorker.ToIPC()),
mGlobal->EventTargetFor(TaskCategory::Other),
[outerPromise] (const ClientOpResult& aResult) {
outerPromise->MaybeResolveWithUndefined();
}, [outerPromise] (nsresult aResult) {
outerPromise->MaybeReject(aResult);
});
return outerPromise.forget();
}
} // namespace dom
} // namespace mozilla

61
dom/clients/api/Clients.h Normal file
Просмотреть файл

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef _mozilla_dom_Clients_h
#define _mozilla_dom_Clients_h
#include "nsCOMPtr.h"
#include "nsISupports.h"
#include "nsWrapperCache.h"
class nsIGlobalObject;
namespace mozilla {
class ErrorResult;
namespace dom {
struct ClientQueryOptions;
class Promise;
class Clients final : public nsISupports
, public nsWrapperCache
{
nsCOMPtr<nsIGlobalObject> mGlobal;
~Clients() = default;
public:
explicit Clients(nsIGlobalObject* aGlobal);
// nsWrapperCache interface methods
JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// DOM bindings methods
nsIGlobalObject*
GetParentObject() const;
already_AddRefed<Promise>
Get(const nsAString& aClientID, ErrorResult& aRv);
already_AddRefed<Promise>
MatchAll(const ClientQueryOptions& aOptions, ErrorResult& aRv);
already_AddRefed<Promise>
OpenWindow(const nsAString& aURL, ErrorResult& aRv);
already_AddRefed<Promise>
Claim(ErrorResult& aRv);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Clients)
};
} // namespace dom
} // namespace mozilla
#endif // _mozilla_dom_Clients_h

32
dom/clients/api/moz.build Normal file
Просмотреть файл

@ -0,0 +1,32 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS.mozilla.dom += [
'Client.h',
'Clients.h',
]
UNIFIED_SOURCES += [
'Client.cpp',
'Clients.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
LOCAL_INCLUDES += [
'/dom/workers',
]
FINAL_LIBRARY = 'xul'
MOCHITEST_MANIFESTS += [
]
BROWSER_CHROME_MANIFESTS += [
]
XPCSHELL_TESTS_MANIFESTS += [
]

Просмотреть файл

@ -10,6 +10,7 @@ include ProtocolTypes;
using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
using ClientType from "mozilla/dom/ClientIPCUtils.h";
using FrameType from "mozilla/dom/ClientIPCUtils.h";
using nsContentUtils::StorageAccess from "mozilla/dom/ClientIPCUtils.h";
using VisibilityState from "mozilla/dom/ClientIPCUtils.h";
namespace mozilla {
@ -37,11 +38,13 @@ struct IPCClientWindowState
{
VisibilityState visibilityState;
TimeStamp lastFocusTime;
StorageAccess storageAccess;
bool focused;
};
struct IPCClientWorkerState
{
StorageAccess storageAccess;
};
union IPCClientState

Просмотреть файл

@ -14,6 +14,7 @@
#include "mozilla/dom/ClientBinding.h"
#include "mozilla/dom/ClientsBinding.h"
#include "mozilla/dom/DocumentBinding.h"
#include "nsContentUtils.h"
namespace IPC {
template<>
@ -36,6 +37,13 @@ namespace IPC {
mozilla::dom::VisibilityState::Hidden,
mozilla::dom::VisibilityState::EndGuard_>
{};
template<>
struct ParamTraits<nsContentUtils::StorageAccess> :
public ContiguousEnumSerializer<nsContentUtils::StorageAccess,
nsContentUtils::StorageAccess::eDeny,
nsContentUtils::StorageAccess::eNumValues>
{};
} // namespace IPC
#endif // _mozilla_dom_ClientIPCUtils_h

Просмотреть файл

@ -78,7 +78,9 @@ ClientSource::SnapshotWindowState(ClientState* aStateOut)
if (!window || !window->IsCurrentInnerWindow() ||
!window->HasActiveDocument()) {
*aStateOut = ClientState(ClientWindowState(VisibilityState::Hidden,
TimeStamp(), false));
TimeStamp(),
nsContentUtils::StorageAccess::eDeny,
false));
return NS_OK;
}
@ -94,8 +96,12 @@ ClientSource::SnapshotWindowState(ClientState* aStateOut)
return rv.StealNSResult();
}
nsContentUtils::StorageAccess storage =
nsContentUtils::StorageAllowedForDocument(doc);
*aStateOut = ClientState(ClientWindowState(doc->VisibilityState(),
doc->LastFocusTime(), focused));
doc->LastFocusTime(), storage,
focused));
return NS_OK;
}
@ -355,6 +361,23 @@ ClientSource::SetController(const ServiceWorkerDescriptor& aServiceWorker)
mController.reset();
mController.emplace(aServiceWorker);
RefPtr<ServiceWorkerContainer> swc;
nsPIDOMWindowInner* window = GetInnerWindow();
if (window) {
RefPtr<Navigator> navigator =
static_cast<Navigator*>(window->GetNavigator());
if (navigator) {
swc = navigator->ServiceWorker();
}
}
// TODO: Also self.navigator.serviceWorker on workers when its exposed there
if (swc && nsContentUtils::IsSafeToRunScript()) {
IgnoredErrorResult ignored;
swc->ControllerChanged(ignored);
}
}
RefPtr<ClientOpPromise>
@ -549,11 +572,39 @@ ClientSource::PostMessage(const ClientPostMessageArgs& aArgs)
RefPtr<ClientOpPromise>
ClientSource::Claim(const ClientClaimArgs& aArgs)
{
SetController(ServiceWorkerDescriptor(aArgs.serviceWorker()));
RefPtr<ClientOpPromise> ref;
RefPtr<ClientOpPromise> ref =
ClientOpPromise::CreateAndResolve(NS_OK, __func__);
ServiceWorkerDescriptor swd(aArgs.serviceWorker());
// Today the ServiceWorkerManager maintains its own list of
// nsIDocument objects controlled by each service worker. We
// need to try to update that data structure for now. If we
// can't, however, then simply mark the Client as controlled.
// In the future this will be enough for the SWM as well since
// it will eventually hold ClientHandle objects instead of
// nsIDocuments.
nsPIDOMWindowInner* innerWindow = GetInnerWindow();
nsIDocument* doc = innerWindow ? innerWindow->GetExtantDoc() : nullptr;
RefPtr<ServiceWorkerManager> swm = doc ? ServiceWorkerManager::GetInstance()
: nullptr;
if (!swm || !doc) {
SetController(swd);
ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
return ref.forget();
}
RefPtr<ClientOpPromise::Private> outerPromise =
new ClientOpPromise::Private(__func__);
RefPtr<GenericPromise> p = swm->MaybeClaimClient(doc, swd);
p->Then(mEventTarget, __func__,
[outerPromise] (bool aResult) {
outerPromise->Resolve(NS_OK, __func__);
}, [outerPromise] (nsresult aResult) {
outerPromise->Reject(aResult, __func__);
});
ref = outerPromise;
return ref.forget();
}
@ -589,7 +640,18 @@ ClientSource::SnapshotState(ClientState* aStateOut)
return NS_OK;
}
*aStateOut = ClientState(ClientWorkerState());
WorkerPrivate* workerPrivate = GetWorkerPrivate();
if (!workerPrivate) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
// Workers only keep a boolean for storage access at the moment.
// Map this back to eAllow or eDeny for now.
nsContentUtils::StorageAccess storage =
workerPrivate->IsStorageAllowed() ? nsContentUtils::StorageAccess::eAllow
: nsContentUtils::StorageAccess::eDeny;
*aStateOut = ClientState(ClientWorkerState(storage));
return NS_OK;
}

Просмотреть файл

@ -13,9 +13,10 @@ namespace dom {
ClientWindowState::ClientWindowState(mozilla::dom::VisibilityState aVisibilityState,
const TimeStamp& aLastFocusTime,
nsContentUtils::StorageAccess aStorageAccess,
bool aFocused)
: mData(MakeUnique<IPCClientWindowState>(aVisibilityState, aLastFocusTime,
aFocused))
aStorageAccess, aFocused))
{
}
@ -72,14 +73,20 @@ ClientWindowState::Focused() const
return mData->focused();
}
nsContentUtils::StorageAccess
ClientWindowState::GetStorageAccess() const
{
return mData->storageAccess();
}
const IPCClientWindowState&
ClientWindowState::ToIPC() const
{
return *mData;
}
ClientWorkerState::ClientWorkerState()
: mData(MakeUnique<IPCClientWorkerState>())
ClientWorkerState::ClientWorkerState(nsContentUtils::StorageAccess aStorageAccess)
: mData(MakeUnique<IPCClientWorkerState>(aStorageAccess))
{
}
@ -118,6 +125,12 @@ ClientWorkerState::~ClientWorkerState()
{
}
nsContentUtils::StorageAccess
ClientWorkerState::GetStorageAccess() const
{
return mData->storageAccess();
}
const IPCClientWorkerState&
ClientWorkerState::ToIPC() const
{
@ -202,6 +215,16 @@ ClientState::AsWorkerState() const
return mData.ref().as<ClientWorkerState>();
}
nsContentUtils::StorageAccess
ClientState::GetStorageAccess() const
{
if (IsWindowState()) {
return AsWindowState().GetStorageAccess();
}
return AsWorkerState().GetStorageAccess();
}
const IPCClientState
ClientState::ToIPC() const
{

Просмотреть файл

@ -11,6 +11,7 @@
#include "mozilla/Maybe.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "nsContentUtils.h"
namespace mozilla {
namespace dom {
@ -29,6 +30,7 @@ class ClientWindowState final
public:
ClientWindowState(mozilla::dom::VisibilityState aVisibilityState,
const TimeStamp& aLastFocusTime,
nsContentUtils::StorageAccess aStorageAccess,
bool aFocused);
explicit ClientWindowState(const IPCClientWindowState& aData);
@ -53,6 +55,9 @@ public:
bool
Focused() const;
nsContentUtils::StorageAccess
GetStorageAccess() const;
const IPCClientWindowState&
ToIPC() const;
};
@ -68,7 +73,7 @@ class ClientWorkerState final
UniquePtr<IPCClientWorkerState> mData;
public:
ClientWorkerState();
explicit ClientWorkerState(nsContentUtils::StorageAccess aStorageAccess);
explicit ClientWorkerState(const IPCClientWorkerState& aData);
@ -83,6 +88,9 @@ public:
~ClientWorkerState();
nsContentUtils::StorageAccess
GetStorageAccess() const;
const IPCClientWorkerState&
ToIPC() const;
};
@ -128,6 +136,9 @@ public:
const ClientWorkerState&
AsWorkerState() const;
nsContentUtils::StorageAccess
GetStorageAccess() const;
const IPCClientState
ToIPC() const;
};

Просмотреть файл

@ -5,5 +5,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'api',
'manager',
]

Просмотреть файл

@ -139,6 +139,7 @@ namespace indexedDB {
using namespace mozilla::dom::quota;
using namespace mozilla::ipc;
using mozilla::dom::quota::Client;
namespace {

Просмотреть файл

@ -148,7 +148,7 @@ interface nsIServiceWorkerManager : nsISupports
*
* This MUST only be called once per document!
*/
[notxpcom,nostdcall] void MaybeStartControlling(in nsIDocument aDoc, in DOMString aDocumentId);
[notxpcom,nostdcall] void MaybeStartControlling(in nsIDocument aDoc);
/**
* Documents that have called MaybeStartControlling() should call this when

Просмотреть файл

@ -249,6 +249,11 @@ bool mozilla::plugins::PluginUtilsOSX::SetProcessName(const char* aProcessName)
if (!sApplicationASN) {
sApplicationASN = ::CFBundleGetFunctionPointerForName(launchServices,
CFSTR("_LSGetCurrentApplicationASN"));
if (!sApplicationASN) {
NS_WARNING("Failed to set process name: Could not get function pointer "
"for LaunchServices");
return false;
}
}
LSGetASNType getASNFunc = reinterpret_cast<LSGetASNType>

Просмотреть файл

@ -13,6 +13,7 @@ interface Client {
readonly attribute USVString url;
// Remove frameType in bug 1290936
[BinaryName="GetFrameType"]
readonly attribute FrameType frameType;
readonly attribute ClientType type;
@ -27,6 +28,7 @@ interface Client {
[Exposed=ServiceWorker]
interface WindowClient : Client {
[BinaryName="GetVisibilityState"]
readonly attribute VisibilityState visibilityState;
readonly attribute boolean focused;

Просмотреть файл

@ -15,8 +15,7 @@ interface Clients {
Promise<any> get(DOMString id);
[NewObject]
Promise<sequence<Client>> matchAll(optional ClientQueryOptions options);
[NewObject,
Func="mozilla::dom::ServiceWorkerGlobalScope::OpenWindowEnabled"]
[NewObject]
Promise<WindowClient?> openWindow(USVString url);
[NewObject]
Promise<void> claim();

Просмотреть файл

@ -15,7 +15,8 @@
[Global=(Worker,ServiceWorker),
Exposed=ServiceWorker]
interface ServiceWorkerGlobalScope : WorkerGlobalScope {
[SameObject] readonly attribute Clients clients;
[SameObject, BinaryName="GetClients"]
readonly attribute Clients clients;
[SameObject] readonly attribute ServiceWorkerRegistration registration;
[Throws, NewObject]

Просмотреть файл

@ -8,12 +8,13 @@
#include "nsIDocument.h"
#include "nsPIDOMWindow.h"
#include "ServiceWorkerClient.h"
#include "ServiceWorkerManager.h"
#include "ServiceWorkerPrivate.h"
#include "WorkerPrivate.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/ClientIPCTypes.h"
#include "mozilla/dom/ClientState.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
@ -102,9 +103,17 @@ ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
return;
}
UniquePtr<ServiceWorkerClientInfo> clientInfo(new ServiceWorkerClientInfo(window->GetExtantDoc()));
Maybe<ClientInfo> clientInfo = window->GetClientInfo();
Maybe<ClientState> clientState = window->GetClientState();
if (clientInfo.isNothing() || clientState.isNothing()) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
ServiceWorkerPrivate* workerPrivate = mInfo->WorkerPrivate();
aRv = workerPrivate->SendMessageEvent(aCx, aMessage, aTransferable, Move(clientInfo));
aRv = workerPrivate->SendMessageEvent(aCx, aMessage, aTransferable,
ClientInfoAndState(clientInfo.ref().ToIPC(),
clientState.ref().ToIPC()));
}
} // namespace workers

Просмотреть файл

@ -1,288 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/.
*/
#include "ServiceWorkerClient.h"
#include "ServiceWorkerContainer.h"
#include "mozilla/dom/MessageEvent.h"
#include "mozilla/dom/Navigator.h"
#include "nsGlobalWindow.h"
#include "nsIBrowserDOMWindow.h"
#include "nsIDocument.h"
#include "ServiceWorker.h"
#include "ServiceWorkerPrivate.h"
#include "WorkerPrivate.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::workers;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ServiceWorkerClient, mOwner)
NS_IMPL_CYCLE_COLLECTING_ADDREF(ServiceWorkerClient)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ServiceWorkerClient)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerClient)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc, uint32_t aOrdinal)
: mType(ClientType::Window)
, mOrdinal(aOrdinal)
, mWindowId(0)
, mFrameType(FrameType::None)
{
MOZ_ASSERT(aDoc);
nsresult rv = aDoc->GetOrCreateId(mClientId);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to get the UUID of the document.");
}
RefPtr<nsGlobalWindowInner> innerWindow =
nsGlobalWindowInner::Cast(aDoc->GetInnerWindow());
if (innerWindow) {
// XXXcatalinb: The inner window can be null if the document is navigating
// and was detached.
mWindowId = innerWindow->WindowID();
}
nsCOMPtr<nsIURI> originalURI = aDoc->GetOriginalURI();
if (originalURI) {
nsAutoCString spec;
originalURI->GetSpec(spec);
CopyUTF8toUTF16(spec, mUrl);
}
mVisibilityState = aDoc->VisibilityState();
mLastFocusTime = aDoc->LastFocusTime();
ErrorResult result;
mFocused = aDoc->HasFocus(result);
if (result.Failed()) {
NS_WARNING("Failed to get focus information.");
}
MOZ_ASSERT_IF(mLastFocusTime.IsNull(), !mFocused);
MOZ_ASSERT_IF(mFocused, !mLastFocusTime.IsNull());
RefPtr<nsGlobalWindowOuter> outerWindow =
nsGlobalWindowOuter::Cast(aDoc->GetWindow());
if (!outerWindow) {
MOZ_ASSERT(mFrameType == FrameType::None);
} else if (!outerWindow->IsTopLevelWindow()) {
mFrameType = FrameType::Nested;
} else if (outerWindow->HadOriginalOpener()) {
mFrameType = FrameType::Auxiliary;
} else {
mFrameType = FrameType::Top_level;
}
}
bool
ServiceWorkerClientInfo::operator<(const ServiceWorkerClientInfo& aRight) const
{
// Note: the mLastFocusTime comparisons are reversed because we need to
// put most recently focused values first. The mOrdinal comparison is
// normal, though, because otherwise we want normal creation order.
if (mLastFocusTime == aRight.mLastFocusTime) {
return mOrdinal < aRight.mOrdinal;
}
if (mLastFocusTime.IsNull()) {
return false;
}
if (aRight.mLastFocusTime.IsNull()) {
return true;
}
return mLastFocusTime > aRight.mLastFocusTime;
}
bool
ServiceWorkerClientInfo::operator==(const ServiceWorkerClientInfo& aRight) const
{
return mLastFocusTime == aRight.mLastFocusTime &&
mOrdinal == aRight.mOrdinal &&
mClientId == aRight.mClientId;
}
JSObject*
ServiceWorkerClient::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return ClientBinding::Wrap(aCx, this, aGivenProto);
}
ClientType
ServiceWorkerClient::Type() const
{
return mType;
}
namespace {
class ServiceWorkerClientPostMessageRunnable final
: public Runnable
, public StructuredCloneHolder
{
const uint64_t mSourceID;
const nsCString mSourceScope;
const uint64_t mWindowId;
public:
ServiceWorkerClientPostMessageRunnable(uint64_t aSourceID,
const nsACString& aSourceScope,
uint64_t aWindowId)
: mozilla::Runnable("ServiceWorkerClientPostMessageRunnable")
, StructuredCloneHolder(CloningSupported,
TransferringSupported,
StructuredCloneScope::SameProcessDifferentThread)
, mSourceID(aSourceID)
, mSourceScope(aSourceScope)
, mWindowId(aWindowId)
{}
NS_IMETHOD
Run() override
{
AssertIsOnMainThread();
nsGlobalWindowInner* window = nsGlobalWindowInner::GetInnerWindowWithId(mWindowId);
if (!window) {
return NS_ERROR_FAILURE;
}
dom::Navigator* navigator = window->Navigator();
if (!navigator) {
return NS_ERROR_FAILURE;
}
RefPtr<ServiceWorkerContainer> container = navigator->ServiceWorker();
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(window))) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
return DispatchDOMEvent(cx, window->AsInner(), container);
}
private:
NS_IMETHOD
DispatchDOMEvent(JSContext* aCx, nsPIDOMWindowInner* aWindow,
ServiceWorkerContainer* aTargetContainer)
{
AssertIsOnMainThread();
MOZ_ASSERT(aTargetContainer->GetParentObject(),
"How come we don't have a window here?!");
JS::Rooted<JS::Value> messageData(aCx);
ErrorResult rv;
Read(aTargetContainer->GetParentObject(), aCx, &messageData, rv);
if (NS_WARN_IF(rv.Failed())) {
xpc::Throw(aCx, rv.StealNSResult());
return NS_ERROR_FAILURE;
}
RootedDictionary<MessageEventInit> init(aCx);
nsCOMPtr<nsIPrincipal> principal = aTargetContainer->GetParentObject()->PrincipalOrNull();
NS_WARNING_ASSERTION(principal, "Why is the principal null here?");
bool isNullPrincipal = false;
bool isSystemPrincipal = false;
if (principal) {
isNullPrincipal = principal->GetIsNullPrincipal();
MOZ_ASSERT(!isNullPrincipal);
isSystemPrincipal = principal->GetIsSystemPrincipal();
MOZ_ASSERT(!isSystemPrincipal);
}
init.mData = messageData;
nsAutoCString origin;
if (principal && !isNullPrincipal && !isSystemPrincipal) {
principal->GetOrigin(origin);
}
init.mOrigin = NS_ConvertUTF8toUTF16(origin);
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (swm) {
RefPtr<ServiceWorkerRegistrationInfo> reg =
swm->GetRegistration(principal, mSourceScope);
if (reg) {
RefPtr<ServiceWorkerInfo> serviceWorker = reg->GetByID(mSourceID);
if (serviceWorker) {
init.mSource.SetValue().SetAsServiceWorker() =
serviceWorker->GetOrCreateInstance(aWindow);
}
}
}
if (!TakeTransferredPortsAsSequence(init.mPorts)) {
return NS_ERROR_OUT_OF_MEMORY;
}
RefPtr<MessageEvent> event =
MessageEvent::Constructor(aTargetContainer, NS_LITERAL_STRING("message"),
init);
event->SetTrusted(true);
bool status = false;
aTargetContainer->DispatchEvent(static_cast<dom::Event*>(event.get()),
&status);
if (!status) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
};
} // namespace
void
ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv)
{
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
&transferable);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
// At the moment we only expose Client on ServiceWorker globals.
MOZ_ASSERT(workerPrivate->IsServiceWorker());
uint32_t serviceWorkerID = workerPrivate->ServiceWorkerID();
nsCString scope = workerPrivate->ServiceWorkerScope();
RefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
new ServiceWorkerClientPostMessageRunnable(serviceWorkerID, scope,
mWindowId);
runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy().denySharedArrayBuffer(),
aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
aRv = workerPrivate->DispatchToMainThread(runnable.forget());
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}

Просмотреть файл

@ -1,128 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/.
*/
#ifndef mozilla_dom_workers_serviceworkerclient_h
#define mozilla_dom_workers_serviceworkerclient_h
#include "nsCOMPtr.h"
#include "nsWrapperCache.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ClientBinding.h"
class nsIDocument;
namespace mozilla {
namespace dom {
namespace workers {
class ServiceWorkerClient;
class ServiceWorkerWindowClient;
// Used as a container object for information needed to create
// client objects.
class ServiceWorkerClientInfo final
{
friend class ServiceWorkerClient;
friend class ServiceWorkerWindowClient;
public:
explicit ServiceWorkerClientInfo(nsIDocument* aDoc, uint32_t aOrdinal = 0);
const nsString& ClientId() const
{
return mClientId;
}
bool operator<(const ServiceWorkerClientInfo& aRight) const;
bool operator==(const ServiceWorkerClientInfo& aRight) const;
private:
const mozilla::dom::ClientType mType;
const uint32_t mOrdinal;
nsString mClientId;
uint64_t mWindowId;
nsString mUrl;
// Window Clients
VisibilityState mVisibilityState;
FrameType mFrameType;
TimeStamp mLastFocusTime;
bool mFocused;
};
class ServiceWorkerClient : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ServiceWorkerClient)
ServiceWorkerClient(nsISupports* aOwner,
const ServiceWorkerClientInfo& aClientInfo)
: mOwner(aOwner)
, mType(aClientInfo.mType)
, mId(aClientInfo.mClientId)
, mUrl(aClientInfo.mUrl)
, mWindowId(aClientInfo.mWindowId)
, mFrameType(aClientInfo.mFrameType)
{
MOZ_ASSERT(aOwner);
}
nsISupports*
GetParentObject() const
{
return mOwner;
}
void GetId(nsString& aRetval) const
{
aRetval = mId;
}
void
GetUrl(nsAString& aUrl) const
{
aUrl.Assign(mUrl);
}
mozilla::dom::FrameType
FrameType() const
{
return mFrameType;
}
mozilla::dom::ClientType
Type() const;
void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable, ErrorResult& aRv);
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
protected:
virtual ~ServiceWorkerClient()
{ }
private:
nsCOMPtr<nsISupports> mOwner;
const ClientType mType;
nsString mId;
nsString mUrl;
protected:
uint64_t mWindowId;
mozilla::dom::FrameType mFrameType;
};
} // namespace workers
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_workers_serviceworkerclient_h

Просмотреть файл

@ -1,940 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "ServiceWorkerClients.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseWorkerProxy.h"
#include "mozilla/JSObjectHolder.h"
#include "ServiceWorkerClient.h"
#include "ServiceWorkerManager.h"
#include "ServiceWorkerPrivate.h"
#include "ServiceWorkerWindowClient.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#include "WorkerScope.h"
#include "nsContentUtils.h"
#include "nsIBrowserDOMWindow.h"
#include "nsIDocShell.h"
#include "nsIDOMChromeWindow.h"
#include "nsIDOMWindow.h"
#include "nsIWebNavigation.h"
#include "nsIWebProgress.h"
#include "nsIWebProgressListener.h"
#include "nsIWindowMediator.h"
#include "nsIWindowWatcher.h"
#include "nsNetUtil.h"
#include "nsPIWindowWatcher.h"
#include "nsWindowWatcher.h"
#include "nsWeakReference.h"
#ifdef MOZ_WIDGET_ANDROID
#include "FennecJNIWrappers.h"
#endif
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::workers;
NS_IMPL_CYCLE_COLLECTING_ADDREF(ServiceWorkerClients)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ServiceWorkerClients)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ServiceWorkerClients, mWorkerScope)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerClients)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
ServiceWorkerClients::ServiceWorkerClients(ServiceWorkerGlobalScope* aWorkerScope)
: mWorkerScope(aWorkerScope)
{
MOZ_ASSERT(mWorkerScope);
}
JSObject*
ServiceWorkerClients::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return ClientsBinding::Wrap(aCx, this, aGivenProto);
}
namespace {
class GetRunnable final : public Runnable
{
class ResolvePromiseWorkerRunnable final : public WorkerRunnable
{
RefPtr<PromiseWorkerProxy> mPromiseProxy;
UniquePtr<ServiceWorkerClientInfo> mValue;
nsresult mRv;
public:
ResolvePromiseWorkerRunnable(WorkerPrivate* aWorkerPrivate,
PromiseWorkerProxy* aPromiseProxy,
UniquePtr<ServiceWorkerClientInfo>&& aValue,
nsresult aRv)
: WorkerRunnable(aWorkerPrivate),
mPromiseProxy(aPromiseProxy),
mValue(Move(aValue)),
mRv(Move(aRv))
{
AssertIsOnMainThread();
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
Promise* promise = mPromiseProxy->WorkerPromise();
MOZ_ASSERT(promise);
if (NS_FAILED(mRv)) {
promise->MaybeReject(mRv);
} else if (mValue) {
RefPtr<ServiceWorkerWindowClient> windowClient =
new ServiceWorkerWindowClient(promise->GetParentObject(), *mValue);
promise->MaybeResolve(windowClient.get());
} else {
promise->MaybeResolveWithUndefined();
}
mPromiseProxy->CleanUp();
return true;
}
};
RefPtr<PromiseWorkerProxy> mPromiseProxy;
nsString mClientId;
public:
GetRunnable(PromiseWorkerProxy* aPromiseProxy, const nsAString& aClientId)
: mozilla::Runnable("GetRunnable")
, mPromiseProxy(aPromiseProxy)
, mClientId(aClientId)
{
}
NS_IMETHOD
Run() override
{
AssertIsOnMainThread();
MutexAutoLock lock(mPromiseProxy->Lock());
if (mPromiseProxy->CleanedUp()) {
return NS_OK;
}
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
MOZ_ASSERT(workerPrivate);
UniquePtr<ServiceWorkerClientInfo> result;
ErrorResult rv;
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
rv = NS_ERROR_FAILURE;
} else {
result = swm->GetClient(workerPrivate->GetPrincipal(), mClientId, rv);
}
RefPtr<ResolvePromiseWorkerRunnable> r =
new ResolvePromiseWorkerRunnable(mPromiseProxy->GetWorkerPrivate(),
mPromiseProxy, Move(result),
rv.StealNSResult());
rv.SuppressException();
r->Dispatch();
return NS_OK;
}
};
class MatchAllRunnable final : public Runnable
{
class ResolvePromiseWorkerRunnable final : public WorkerRunnable
{
RefPtr<PromiseWorkerProxy> mPromiseProxy;
nsTArray<ServiceWorkerClientInfo> mValue;
public:
ResolvePromiseWorkerRunnable(WorkerPrivate* aWorkerPrivate,
PromiseWorkerProxy* aPromiseProxy,
nsTArray<ServiceWorkerClientInfo>& aValue)
: WorkerRunnable(aWorkerPrivate),
mPromiseProxy(aPromiseProxy)
{
AssertIsOnMainThread();
mValue.SwapElements(aValue);
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
Promise* promise = mPromiseProxy->WorkerPromise();
MOZ_ASSERT(promise);
nsTArray<RefPtr<ServiceWorkerClient>> ret;
for (size_t i = 0; i < mValue.Length(); i++) {
ret.AppendElement(RefPtr<ServiceWorkerClient>(
new ServiceWorkerWindowClient(promise->GetParentObject(),
mValue.ElementAt(i))));
}
promise->MaybeResolve(ret);
mPromiseProxy->CleanUp();
return true;
}
};
RefPtr<PromiseWorkerProxy> mPromiseProxy;
const nsCString mScope;
const uint64_t mServiceWorkerID;
const bool mIncludeUncontrolled;
public:
MatchAllRunnable(PromiseWorkerProxy* aPromiseProxy,
const nsCString& aScope,
uint64_t aServiceWorkerID,
bool aIncludeUncontrolled)
: mozilla::Runnable("MatchAllRunnable")
, mPromiseProxy(aPromiseProxy)
, mScope(aScope)
, mServiceWorkerID(aServiceWorkerID)
, mIncludeUncontrolled(aIncludeUncontrolled)
{
MOZ_ASSERT(mPromiseProxy);
}
NS_IMETHOD
Run() override
{
AssertIsOnMainThread();
MutexAutoLock lock(mPromiseProxy->Lock());
if (mPromiseProxy->CleanedUp()) {
return NS_OK;
}
nsTArray<ServiceWorkerClientInfo> result;
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (swm) {
swm->GetAllClients(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(),
mScope, mServiceWorkerID, mIncludeUncontrolled,
result);
}
RefPtr<ResolvePromiseWorkerRunnable> r =
new ResolvePromiseWorkerRunnable(mPromiseProxy->GetWorkerPrivate(),
mPromiseProxy, result);
r->Dispatch();
return NS_OK;
}
};
class ResolveClaimRunnable final : public WorkerRunnable
{
RefPtr<PromiseWorkerProxy> mPromiseProxy;
nsresult mResult;
public:
ResolveClaimRunnable(WorkerPrivate* aWorkerPrivate,
PromiseWorkerProxy* aPromiseProxy,
nsresult aResult)
: WorkerRunnable(aWorkerPrivate)
, mPromiseProxy(aPromiseProxy)
, mResult(aResult)
{
AssertIsOnMainThread();
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
RefPtr<Promise> promise = mPromiseProxy->WorkerPromise();
MOZ_ASSERT(promise);
if (NS_SUCCEEDED(mResult)) {
promise->MaybeResolveWithUndefined();
} else {
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
}
mPromiseProxy->CleanUp();
return true;
}
};
class ClaimRunnable final : public Runnable
{
RefPtr<PromiseWorkerProxy> mPromiseProxy;
nsCString mScope;
uint64_t mServiceWorkerID;
public:
ClaimRunnable(PromiseWorkerProxy* aPromiseProxy, const nsCString& aScope)
: mozilla::Runnable("ClaimRunnable")
, mPromiseProxy(aPromiseProxy)
, mScope(aScope)
// Safe to call GetWorkerPrivate() since we are being called on the worker
// thread via script (so no clean up has occured yet).
, mServiceWorkerID(aPromiseProxy->GetWorkerPrivate()->ServiceWorkerID())
{
MOZ_ASSERT(aPromiseProxy);
}
NS_IMETHOD
Run() override
{
MutexAutoLock lock(mPromiseProxy->Lock());
if (mPromiseProxy->CleanedUp()) {
return NS_OK;
}
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
MOZ_ASSERT(workerPrivate);
nsresult rv = NS_OK;
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
// browser shutdown
rv = NS_ERROR_FAILURE;
} else {
rv = swm->ClaimClients(workerPrivate->GetPrincipal(), mScope,
mServiceWorkerID);
}
RefPtr<ResolveClaimRunnable> r =
new ResolveClaimRunnable(workerPrivate, mPromiseProxy, rv);
r->Dispatch();
return NS_OK;
}
};
class ResolveOpenWindowRunnable final : public WorkerRunnable
{
public:
ResolveOpenWindowRunnable(PromiseWorkerProxy* aPromiseProxy,
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
const nsresult aStatus)
: WorkerRunnable(aPromiseProxy->GetWorkerPrivate())
, mPromiseProxy(aPromiseProxy)
, mClientInfo(Move(aClientInfo))
, mStatus(aStatus)
{
AssertIsOnMainThread();
MOZ_ASSERT(aPromiseProxy);
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
Promise* promise = mPromiseProxy->WorkerPromise();
if (NS_WARN_IF(NS_FAILED(mStatus))) {
promise->MaybeReject(mStatus);
} else if (mClientInfo) {
RefPtr<ServiceWorkerWindowClient> client =
new ServiceWorkerWindowClient(promise->GetParentObject(),
*mClientInfo);
promise->MaybeResolve(client);
} else {
promise->MaybeResolve(JS::NullHandleValue);
}
mPromiseProxy->CleanUp();
return true;
}
private:
RefPtr<PromiseWorkerProxy> mPromiseProxy;
UniquePtr<ServiceWorkerClientInfo> mClientInfo;
const nsresult mStatus;
};
class WebProgressListener final : public nsIWebProgressListener,
public nsSupportsWeakReference
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(WebProgressListener, nsIWebProgressListener)
WebProgressListener(PromiseWorkerProxy* aPromiseProxy,
ServiceWorkerPrivate* aServiceWorkerPrivate,
nsPIDOMWindowOuter* aWindow,
nsIURI* aBaseURI)
: mPromiseProxy(aPromiseProxy)
, mServiceWorkerPrivate(aServiceWorkerPrivate)
, mWindow(aWindow)
, mBaseURI(aBaseURI)
{
MOZ_ASSERT(aPromiseProxy);
MOZ_ASSERT(aServiceWorkerPrivate);
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aBaseURI);
AssertIsOnMainThread();
mServiceWorkerPrivate->StoreISupports(static_cast<nsIWebProgressListener*>(this));
}
NS_IMETHOD
OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t aStateFlags, nsresult aStatus) override
{
if (!(aStateFlags & STATE_IS_DOCUMENT) ||
!(aStateFlags & (STATE_STOP | STATE_TRANSFERRING))) {
return NS_OK;
}
// Our caller keeps a strong reference, so it is safe to remove the listener
// from ServiceWorkerPrivate.
mServiceWorkerPrivate->RemoveISupports(static_cast<nsIWebProgressListener*>(this));
aWebProgress->RemoveProgressListener(this);
MutexAutoLock lock(mPromiseProxy->Lock());
if (mPromiseProxy->CleanedUp()) {
return NS_OK;
}
nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
UniquePtr<ServiceWorkerClientInfo> clientInfo;
if (doc) {
// Check same origin.
nsCOMPtr<nsIScriptSecurityManager> securityManager =
nsContentUtils::GetSecurityManager();
nsresult rv = securityManager->CheckSameOriginURI(doc->GetOriginalURI(),
mBaseURI, false);
if (NS_SUCCEEDED(rv)) {
clientInfo.reset(new ServiceWorkerClientInfo(doc));
}
}
RefPtr<ResolveOpenWindowRunnable> r =
new ResolveOpenWindowRunnable(mPromiseProxy,
Move(clientInfo),
NS_OK);
r->Dispatch();
return NS_OK;
}
NS_IMETHOD
OnProgressChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
int32_t aCurSelfProgress,
int32_t aMaxSelfProgress,
int32_t aCurTotalProgress,
int32_t aMaxTotalProgress) override
{
MOZ_ASSERT(false, "Unexpected notification.");
return NS_OK;
}
NS_IMETHOD
OnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsIURI* aLocation,
uint32_t aFlags) override
{
MOZ_ASSERT(false, "Unexpected notification.");
return NS_OK;
}
NS_IMETHOD
OnStatusChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsresult aStatus, const char16_t* aMessage) override
{
MOZ_ASSERT(false, "Unexpected notification.");
return NS_OK;
}
NS_IMETHOD
OnSecurityChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t aState) override
{
MOZ_ASSERT(false, "Unexpected notification.");
return NS_OK;
}
private:
~WebProgressListener()
{ }
RefPtr<PromiseWorkerProxy> mPromiseProxy;
RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
nsCOMPtr<nsPIDOMWindowOuter> mWindow;
nsCOMPtr<nsIURI> mBaseURI;
};
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebProgressListener)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebProgressListener)
NS_IMPL_CYCLE_COLLECTION(WebProgressListener, mPromiseProxy,
mServiceWorkerPrivate, mWindow)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebProgressListener)
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END
class OpenWindowRunnable final : public Runnable
, public nsIObserver
, public nsSupportsWeakReference
{
RefPtr<PromiseWorkerProxy> mPromiseProxy;
nsString mUrl;
nsString mScope;
public:
NS_DECL_ISUPPORTS_INHERITED
// Note: |OpenWindowRunnable| cannot be cycle collected because it inherits
// thread safe reference counting from |mozilla::Runnable|. On Fennec, we
// might use |ServiceWorkerPrivate::StoreISupports| to keep this object alive
// while waiting for an event from the observer service. As such, to avoid
// creating a cycle that will leak, |OpenWindowRunnable| must not hold a strong
// reference to |ServiceWorkerPrivate|.
OpenWindowRunnable(PromiseWorkerProxy* aPromiseProxy,
const nsAString& aUrl,
const nsAString& aScope)
: mozilla::Runnable("OpenWindowRunnable")
, mPromiseProxy(aPromiseProxy)
, mUrl(aUrl)
, mScope(aScope)
{
MOZ_ASSERT(aPromiseProxy);
MOZ_ASSERT(aPromiseProxy->GetWorkerPrivate());
aPromiseProxy->GetWorkerPrivate()->AssertIsOnWorkerThread();
}
NS_IMETHOD
Observe(nsISupports* aSubject, const char* aTopic, const char16_t* /* aData */) override
{
AssertIsOnMainThread();
nsCString topic(aTopic);
if (!topic.EqualsLiteral("BrowserChrome:Ready")) {
MOZ_ASSERT(false, "Unexpected topic.");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
NS_ENSURE_STATE(os);
os->RemoveObserver(this, "BrowserChrome:Ready");
RefPtr<ServiceWorkerPrivate> swp = GetServiceWorkerPrivate();
NS_ENSURE_STATE(swp);
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
swp->RemoveISupports(static_cast<nsIObserver*>(this));
return NS_OK;
}
NS_IMETHOD
Run() override
{
AssertIsOnMainThread();
MutexAutoLock lock(mPromiseProxy->Lock());
if (mPromiseProxy->CleanedUp()) {
return NS_OK;
}
#ifdef MOZ_WIDGET_ANDROID
// This fires an intent that will start launching Fennec and foreground it,
// if necessary.
if (jni::IsFennec()) {
java::GeckoApp::LaunchOrBringToFront();
}
#endif
nsCOMPtr<nsPIDOMWindowOuter> window;
nsresult rv = OpenWindow(getter_AddRefs(window));
if (NS_SUCCEEDED(rv)) {
MOZ_ASSERT(window);
rv = nsContentUtils::DispatchFocusChromeEvent(window);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
MOZ_ASSERT(workerPrivate);
WorkerPrivate::LocationInfo& info = workerPrivate->GetLocationInfo();
nsCOMPtr<nsIURI> baseURI;
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), info.mHref);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
if (!webProgress) {
return NS_ERROR_FAILURE;
}
RefPtr<ServiceWorkerPrivate> swp = GetServiceWorkerPrivate();
NS_ENSURE_STATE(swp);
nsCOMPtr<nsIWebProgressListener> listener =
new WebProgressListener(mPromiseProxy, swp, window, baseURI);
rv = webProgress->AddProgressListener(listener,
nsIWebProgress::NOTIFY_STATE_DOCUMENT);
MOZ_ASSERT(NS_SUCCEEDED(rv));
return NS_OK;
}
#ifdef MOZ_WIDGET_ANDROID
else if (rv == NS_ERROR_NOT_AVAILABLE && jni::IsFennec()) {
// We couldn't get a browser window, so Fennec must not be running.
// Send an Intent to launch Fennec and wait for "BrowserChrome:Ready"
// to try opening a window again.
RefPtr<ServiceWorkerPrivate> swp = GetServiceWorkerPrivate();
NS_ENSURE_STATE(swp);
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
NS_ENSURE_STATE(os);
rv = os->AddObserver(this, "BrowserChrome:Ready", /* weakRef */ true);
NS_ENSURE_SUCCESS(rv, rv);
swp->StoreISupports(static_cast<nsIObserver*>(this));
return NS_OK;
}
#endif
RefPtr<ResolveOpenWindowRunnable> resolveRunnable =
new ResolveOpenWindowRunnable(mPromiseProxy, nullptr, rv);
Unused << NS_WARN_IF(!resolveRunnable->Dispatch());
return NS_OK;
}
private:
~OpenWindowRunnable()
{ }
ServiceWorkerPrivate*
GetServiceWorkerPrivate() const
{
AssertIsOnMainThread();
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
// browser shutdown
return nullptr;
}
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
MOZ_ASSERT(workerPrivate);
nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
MOZ_DIAGNOSTIC_ASSERT(principal);
RefPtr<ServiceWorkerRegistrationInfo> registration =
swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope));
if (NS_WARN_IF(!registration)) {
return nullptr;
}
RefPtr<ServiceWorkerInfo> serviceWorkerInfo =
registration->GetServiceWorkerInfoById(workerPrivate->ServiceWorkerID());
if (NS_WARN_IF(!serviceWorkerInfo)) {
return nullptr;
}
return serviceWorkerInfo->WorkerPrivate();
}
nsresult
OpenWindow(nsPIDOMWindowOuter** aWindow)
{
MOZ_DIAGNOSTIC_ASSERT(aWindow);
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
nsCOMPtr<nsIPrincipal> triggeringPrincipal = workerPrivate->GetPrincipal();
MOZ_DIAGNOSTIC_ASSERT(triggeringPrincipal);
// [[1. Let url be the result of parsing url with entry settings object's API
// base URL.]]
nsCOMPtr<nsIURI> uri;
WorkerPrivate::LocationInfo& info = workerPrivate->GetLocationInfo();
nsCOMPtr<nsIURI> baseURI;
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), info.mHref);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_TYPE_ERR;
}
rv = NS_NewURI(getter_AddRefs(uri), mUrl, nullptr, baseURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_TYPE_ERR;
}
// [[6.1 Open Window]]
nsCOMPtr<nsIWindowMediator> wm = do_GetService(NS_WINDOWMEDIATOR_CONTRACTID,
&rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (XRE_IsContentProcess()) {
// Let's create a sandbox in order to have a valid JSContext and correctly
// propagate the SubjectPrincipal.
AutoJSAPI jsapi;
jsapi.Init();
JSContext* cx = jsapi.cx();
nsIXPConnect* xpc = nsContentUtils::XPConnect();
MOZ_ASSERT(xpc, "This should never be null!");
JS::Rooted<JSObject*> sandbox(cx);
rv = xpc->CreateSandbox(cx, triggeringPrincipal, sandbox.address());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
JSAutoCompartment ac(cx, sandbox);
// ContentProcess
nsCOMPtr<nsIWindowWatcher> wwatch =
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
NS_ENSURE_STATE(pwwatch);
nsCString spec;
rv = uri->GetSpec(spec);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<mozIDOMWindowProxy> newWindow;
rv = pwwatch->OpenWindow2(nullptr,
spec.get(),
nullptr,
nullptr,
false, false, true, nullptr,
// Not a spammy popup; we got permission, we swear!
/* aIsPopupSpam = */ false,
// Don't force noopener. We're not passing in an
// opener anyway, and we _do_ want the returned
// window.
/* aForceNoOpener = */ false,
/* aLoadInfp = */ nullptr,
getter_AddRefs(newWindow));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsPIDOMWindowOuter> pwindow = nsPIDOMWindowOuter::From(newWindow);
pwindow.forget(aWindow);
MOZ_DIAGNOSTIC_ASSERT(*aWindow);
return NS_OK;
}
// Find the most recent browser window and open a new tab in it.
nsCOMPtr<nsPIDOMWindowOuter> browserWindow =
nsContentUtils::GetMostRecentNonPBWindow();
if (!browserWindow) {
// It is possible to be running without a browser window on Mac OS, so
// we need to open a new chrome window.
// TODO(catalinb): open new chrome window. Bug 1218080
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(browserWindow);
if (NS_WARN_IF(!chromeWin)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIBrowserDOMWindow> bwin;
chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
if (NS_WARN_IF(!bwin)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<mozIDOMWindowProxy> win;
rv = bwin->OpenURI(uri, nullptr,
nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW,
nsIBrowserDOMWindow::OPEN_NEW,
triggeringPrincipal,
getter_AddRefs(win));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
NS_ENSURE_STATE(win);
nsCOMPtr<nsPIDOMWindowOuter> pWin = nsPIDOMWindowOuter::From(win);
pWin.forget(aWindow);
MOZ_DIAGNOSTIC_ASSERT(*aWindow);
return NS_OK;
}
};
NS_IMPL_ADDREF_INHERITED(OpenWindowRunnable, Runnable) \
NS_IMPL_RELEASE_INHERITED(OpenWindowRunnable, Runnable)
NS_INTERFACE_MAP_BEGIN(OpenWindowRunnable)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsIRunnable)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
NS_INTERFACE_MAP_END
} // namespace
already_AddRefed<Promise>
ServiceWorkerClients::Get(const nsAString& aClientId, ErrorResult& aRv)
{
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
RefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<PromiseWorkerProxy> promiseProxy =
PromiseWorkerProxy::Create(workerPrivate, promise);
if (!promiseProxy) {
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
return promise.forget();
}
RefPtr<GetRunnable> r =
new GetRunnable(promiseProxy, aClientId);
MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
return promise.forget();
}
already_AddRefed<Promise>
ServiceWorkerClients::MatchAll(const ClientQueryOptions& aOptions,
ErrorResult& aRv)
{
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
nsString scope;
mWorkerScope->GetScope(scope);
if (aOptions.mType != ClientType::Window) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
RefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<PromiseWorkerProxy> promiseProxy =
PromiseWorkerProxy::Create(workerPrivate, promise);
if (!promiseProxy) {
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
return promise.forget();
}
RefPtr<MatchAllRunnable> r =
new MatchAllRunnable(promiseProxy,
NS_ConvertUTF16toUTF8(scope),
workerPrivate->ServiceWorkerID(),
aOptions.mIncludeUncontrolled);
MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
return promise.forget();
}
already_AddRefed<Promise>
ServiceWorkerClients::OpenWindow(const nsAString& aUrl,
ErrorResult& aRv)
{
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
RefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
if (aUrl.EqualsLiteral("about:blank")) {
promise->MaybeReject(NS_ERROR_TYPE_ERR);
return promise.forget();
}
// [[4. If this algorithm is not allowed to show a popup ..]]
// In Gecko the service worker is allowed to show a popup only if the user
// just clicked on a notification.
if (!workerPrivate->GlobalScope()->WindowInteractionAllowed()) {
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return promise.forget();
}
RefPtr<PromiseWorkerProxy> promiseProxy =
PromiseWorkerProxy::Create(workerPrivate, promise);
if (!promiseProxy) {
return nullptr;
}
nsString scope;
mWorkerScope->GetScope(scope);
RefPtr<OpenWindowRunnable> r = new OpenWindowRunnable(promiseProxy,
aUrl, scope);
MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
return promise.forget();
}
already_AddRefed<Promise>
ServiceWorkerClients::Claim(ErrorResult& aRv)
{
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
RefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<PromiseWorkerProxy> promiseProxy =
PromiseWorkerProxy::Create(workerPrivate, promise);
if (!promiseProxy) {
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
return promise.forget();
}
nsString scope;
mWorkerScope->GetScope(scope);
RefPtr<ClaimRunnable> runnable =
new ClaimRunnable(promiseProxy, NS_ConvertUTF16toUTF8(scope));
MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(runnable.forget()));
return promise.forget();
}

Просмотреть файл

@ -1,64 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/.
*/
#ifndef mozilla_dom_workers_serviceworkerclients_h
#define mozilla_dom_workers_serviceworkerclients_h
#include "nsWrapperCache.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ClientsBinding.h"
#include "mozilla/ErrorResult.h"
namespace mozilla {
namespace dom {
namespace workers {
class ServiceWorkerClients final : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ServiceWorkerClients)
explicit ServiceWorkerClients(ServiceWorkerGlobalScope* aWorkerScope);
already_AddRefed<Promise>
Get(const nsAString& aClientId, ErrorResult& aRv);
already_AddRefed<Promise>
MatchAll(const ClientQueryOptions& aOptions, ErrorResult& aRv);
already_AddRefed<Promise>
OpenWindow(const nsAString& aUrl, ErrorResult& aRv);
already_AddRefed<Promise>
Claim(ErrorResult& aRv);
JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
ServiceWorkerGlobalScope*
GetParentObject() const
{
return mWorkerScope;
}
private:
~ServiceWorkerClients()
{
}
RefPtr<ServiceWorkerGlobalScope> mWorkerScope;
};
} // namespace workers
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_workers_serviceworkerclients_h

Просмотреть файл

@ -24,13 +24,13 @@
#include "nsNetUtil.h"
#include "nsSerializationHelper.h"
#include "nsQueryObject.h"
#include "ServiceWorkerClient.h"
#include "ServiceWorkerManager.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/BodyUtil.h"
#include "mozilla/dom/Client.h"
#include "mozilla/dom/FetchEventBinding.h"
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/PromiseNativeHandler.h"

Просмотреть файл

@ -25,6 +25,7 @@ class nsIInterceptedChannel;
namespace mozilla {
namespace dom {
class Blob;
class Client;
class MessagePort;
class Request;
class ResponseOrPromise;
@ -269,7 +270,7 @@ class ExtendableMessageEvent final : public ExtendableEvent
JS::Heap<JS::Value> mData;
nsString mOrigin;
nsString mLastEventId;
RefPtr<ServiceWorkerClient> mClient;
RefPtr<Client> mClient;
RefPtr<ServiceWorker> mServiceWorker;
RefPtr<MessagePort> mMessagePort;
nsTArray<RefPtr<MessagePort>> mPorts;

Просмотреть файл

@ -68,7 +68,6 @@
#include "RuntimeService.h"
#include "ServiceWorker.h"
#include "ServiceWorkerClient.h"
#include "ServiceWorkerContainer.h"
#include "ServiceWorkerInfo.h"
#include "ServiceWorkerJobQueue.h"
@ -2302,8 +2301,7 @@ ServiceWorkerManager::MaybeRemoveRegistrationInfo(const nsACString& aScopeKey)
}
void
ServiceWorkerManager::MaybeStartControlling(nsIDocument* aDoc,
const nsAString& aDocumentId)
ServiceWorkerManager::MaybeStartControlling(nsIDocument* aDoc)
{
AssertIsOnMainThread();
MOZ_ASSERT(aDoc);
@ -2311,7 +2309,7 @@ ServiceWorkerManager::MaybeStartControlling(nsIDocument* aDoc,
GetServiceWorkerRegistrationInfo(aDoc);
if (registration) {
MOZ_ASSERT(!mControlledDocuments.Contains(aDoc));
StartControllingADocument(registration, aDoc, aDocumentId);
StartControllingADocument(registration, aDoc);
}
}
@ -2353,8 +2351,7 @@ ServiceWorkerManager::MaybeCheckNavigationUpdate(nsIDocument* aDoc)
RefPtr<GenericPromise>
ServiceWorkerManager::StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration,
nsIDocument* aDoc,
const nsAString& aDocumentId)
nsIDocument* aDoc)
{
MOZ_ASSERT(aRegistration);
MOZ_ASSERT(aDoc);
@ -2368,9 +2365,6 @@ ServiceWorkerManager::StartControllingADocument(ServiceWorkerRegistrationInfo* a
aRegistration->StartControllingADocument();
mControlledDocuments.Put(aDoc, aRegistration);
if (!aDocumentId.IsEmpty()) {
aDoc->SetId(aDocumentId);
}
// Mark the document's ClientSource as controlled using the ClientHandle
// interface. While we could get at the ClientSource directly from the
@ -2564,20 +2558,17 @@ class ContinueDispatchFetchEventRunnable : public Runnable
RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
nsCOMPtr<nsIInterceptedChannel> mChannel;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsString mDocumentId;
bool mIsReload;
public:
ContinueDispatchFetchEventRunnable(
ServiceWorkerPrivate* aServiceWorkerPrivate,
nsIInterceptedChannel* aChannel,
nsILoadGroup* aLoadGroup,
const nsAString& aDocumentId,
bool aIsReload)
: Runnable("dom::workers::ContinueDispatchFetchEventRunnable")
, mServiceWorkerPrivate(aServiceWorkerPrivate)
, mChannel(aChannel)
, mLoadGroup(aLoadGroup)
, mDocumentId(aDocumentId)
, mIsReload(aIsReload)
{
MOZ_ASSERT(aServiceWorkerPrivate);
@ -2618,8 +2609,19 @@ public:
return NS_OK;
}
rv = mServiceWorkerPrivate->SendFetchEvent(mChannel, mLoadGroup,
mDocumentId, mIsReload);
nsString clientId;
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
if (loadInfo) {
Maybe<ClientInfo> clientInfo = loadInfo->GetClientInfo();
if (clientInfo.isSome()) {
char buf[NSID_LENGTH];
clientInfo.ref().Id().ToProvidedString(buf);
CopyUTF8toUTF16(nsDependentCString(buf), clientId);
}
}
rv = mServiceWorkerPrivate->SendFetchEvent(mChannel, mLoadGroup, clientId,
mIsReload);
if (NS_WARN_IF(NS_FAILED(rv))) {
HandleError();
}
@ -2633,7 +2635,6 @@ public:
void
ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttributes,
nsIDocument* aDoc,
const nsAString& aDocumentIdForTopLevelNavigation,
nsIInterceptedChannel* aChannel,
bool aIsReload,
bool aIsSubresourceLoad,
@ -2644,7 +2645,6 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut
RefPtr<ServiceWorkerInfo> serviceWorker;
nsCOMPtr<nsILoadGroup> loadGroup;
nsAutoString documentId;
if (aIsSubresourceLoad) {
MOZ_ASSERT(aDoc);
@ -2656,10 +2656,6 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut
}
loadGroup = aDoc->GetDocumentLoadGroup();
nsresult rv = aDoc->GetOrCreateId(documentId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
} else {
nsCOMPtr<nsIChannel> internalChannel;
aRv = aChannel->GetChannel(getter_AddRefs(internalChannel));
@ -2669,9 +2665,6 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut
internalChannel->GetLoadGroup(getter_AddRefs(loadGroup));
// TODO: Use aDocumentIdForTopLevelNavigation for potentialClientId, pending
// the spec change.
nsCOMPtr<nsIURI> uri;
aRv = aChannel->GetSecureUpgradedChannelURI(getter_AddRefs(uri));
if (NS_WARN_IF(aRv.Failed())) {
@ -2751,8 +2744,7 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut
nsCOMPtr<nsIRunnable> continueRunnable =
new ContinueDispatchFetchEventRunnable(serviceWorker->WorkerPrivate(),
aChannel, loadGroup,
documentId, aIsReload);
aChannel, loadGroup, aIsReload);
// When this service worker was registered, we also sent down the permissions
// for the runnable. They should have arrived by now, but we still need to
@ -2846,22 +2838,42 @@ ServiceWorkerManager::GetDocumentController(nsPIDOMWindowInner* aWindow,
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
if (!doc) {
Maybe<ServiceWorkerDescriptor> controller = aWindow->GetController();
if (controller.isNothing()) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
RefPtr<ServiceWorkerRegistrationInfo> registration;
nsresult rv = GetDocumentRegistration(doc, getter_AddRefs(registration));
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
if (NS_WARN_IF(!principal)) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
nsAutoCString scopeKey;
nsresult rv = PrincipalToScopeKey(principal, scopeKey);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(registration->GetActive());
RefPtr<ServiceWorker> serviceWorker =
registration->GetActive()->GetOrCreateInstance(aWindow);
RefPtr<ServiceWorkerRegistrationInfo> registration =
GetRegistration(scopeKey, controller.ref().Scope());
if (NS_WARN_IF(!registration)) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
RefPtr<ServiceWorkerInfo> active = registration->GetActive();
if (NS_WARN_IF(!active) ||
NS_WARN_IF(active->Descriptor().Id() != controller.ref().Id())) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
RefPtr<ServiceWorker> serviceWorker = active->GetOrCreateInstance(aWindow);
serviceWorker.forget(aServiceWorker);
return NS_OK;
}
@ -3166,208 +3178,19 @@ ServiceWorkerManager::UpdateInternal(nsIPrincipal* aPrincipal,
queue->ScheduleJob(job);
}
namespace {
static void
FireControllerChangeOnDocument(nsIDocument* aDocument)
{
AssertIsOnMainThread();
MOZ_ASSERT(aDocument);
nsCOMPtr<nsPIDOMWindowInner> w = aDocument->GetInnerWindow();
if (!w) {
NS_WARNING("Failed to dispatch controllerchange event");
return;
}
auto* window = nsGlobalWindowInner::Cast(w.get());
dom::Navigator* navigator = window->Navigator();
if (!navigator) {
return;
}
RefPtr<ServiceWorkerContainer> container = navigator->ServiceWorker();
ErrorResult result;
container->ControllerChanged(result);
if (result.Failed()) {
NS_WARNING("Failed to dispatch controllerchange event");
}
}
} // anonymous namespace
UniquePtr<ServiceWorkerClientInfo>
ServiceWorkerManager::GetClient(nsIPrincipal* aPrincipal,
const nsAString& aClientId,
ErrorResult& aRv)
{
AssertIsOnMainThread();
UniquePtr<ServiceWorkerClientInfo> clientInfo;
nsCOMPtr<nsISupportsInterfacePointer> ifptr =
do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID);
if (NS_WARN_IF(!ifptr)) {
return clientInfo;
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return clientInfo;
}
nsresult rv = obs->NotifyObservers(ifptr, "service-worker-get-client",
PromiseFlatString(aClientId).get());
if (NS_WARN_IF(NS_FAILED(rv))) {
return clientInfo;
}
nsCOMPtr<nsISupports> ptr;
ifptr->GetData(getter_AddRefs(ptr));
nsCOMPtr<nsIDocument> doc = do_QueryInterface(ptr);
if (NS_WARN_IF(!doc || !doc->GetInnerWindow())) {
return clientInfo;
}
bool equals = false;
aPrincipal->Equals(doc->NodePrincipal(), &equals);
if (!equals) {
return clientInfo;
}
if (!IsFromAuthenticatedOrigin(doc)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return clientInfo;
}
// Don't let service worker see 3rd party iframes that are denied storage
// access. We don't want these to communicate.
auto storageAccess =
nsContentUtils::StorageAllowedForWindow(doc->GetInnerWindow());
if (storageAccess != nsContentUtils::StorageAccess::eAllow) {
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Service Workers"), doc,
nsContentUtils::eDOM_PROPERTIES,
"ServiceWorkerGetClientStorageError");
return clientInfo;
}
clientInfo.reset(new ServiceWorkerClientInfo(doc));
return clientInfo;
}
void
ServiceWorkerManager::GetAllClients(nsIPrincipal* aPrincipal,
const nsCString& aScope,
uint64_t aServiceWorkerID,
bool aIncludeUncontrolled,
nsTArray<ServiceWorkerClientInfo>& aDocuments)
{
AssertIsOnMainThread();
MOZ_ASSERT(aPrincipal);
RefPtr<ServiceWorkerRegistrationInfo> registration =
GetRegistration(aPrincipal, aScope);
if (!registration) {
// The registration was removed, leave the array empty.
return;
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return;
}
nsCOMPtr<nsISimpleEnumerator> enumerator;
nsresult rv = obs->EnumerateObservers("service-worker-get-client",
getter_AddRefs(enumerator));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
// Get a list of Client documents out of the observer service
AutoTArray<nsCOMPtr<nsIDocument>, 32> docList;
bool loop = true;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&loop)) && loop) {
nsCOMPtr<nsISupports> ptr;
rv = enumerator->GetNext(getter_AddRefs(ptr));
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
nsCOMPtr<nsIDocument> doc = do_QueryInterface(ptr);
if (!doc || !doc->GetWindow() || !doc->GetInnerWindow()) {
continue;
}
bool equals = false;
Unused << aPrincipal->Equals(doc->NodePrincipal(), &equals);
if (!equals) {
continue;
}
// Treat http windows with devtools opened as secure if the correct devtools
// setting is enabled.
if (!doc->GetWindow()->GetServiceWorkersTestingEnabled() &&
!Preferences::GetBool("dom.serviceWorkers.testing.enabled") &&
!IsFromAuthenticatedOrigin(doc)) {
continue;
}
// Don't let service worker find 3rd party iframes that are denied storage
// access. We don't want these to communicate.
auto storageAccess =
nsContentUtils::StorageAllowedForWindow(doc->GetInnerWindow());
if (storageAccess != nsContentUtils::StorageAccess::eAllow) {
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Service Workers"),
doc, nsContentUtils::eDOM_PROPERTIES,
"ServiceWorkerGetClientStorageError");
continue;
}
// If we are only returning controlled Clients then skip any documents
// that are for different registrations. We also skip service workers
// that don't match the ID of our calling service worker. We should
// only return Clients controlled by that precise service worker.
if (!aIncludeUncontrolled) {
ServiceWorkerRegistrationInfo* reg = mControlledDocuments.GetWeak(doc);
if (!reg || reg->mScope != aScope || !reg->GetActive() ||
reg->GetActive()->ID() != aServiceWorkerID) {
continue;
}
}
if (!aIncludeUncontrolled && !mControlledDocuments.Contains(doc)) {
continue;
}
docList.AppendElement(doc.forget());
}
// The observer service gives us the list in reverse creation order.
// We need to maintain creation order, so reverse the list before
// processing.
docList.Reverse();
// Finally convert to the list of ServiceWorkerClientInfo objects.
uint32_t ordinal = 0;
for (uint32_t i = 0; i < docList.Length(); ++i) {
aDocuments.AppendElement(ServiceWorkerClientInfo(docList[i], ordinal));
ordinal += 1;
}
aDocuments.Sort();
}
void
already_AddRefed<GenericPromise>
ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDocument,
ServiceWorkerRegistrationInfo* aWorkerRegistration)
{
MOZ_ASSERT(aWorkerRegistration);
MOZ_ASSERT(aWorkerRegistration->GetActive());
RefPtr<GenericPromise> ref;
// Same origin check
if (!aWorkerRegistration->mPrincipal->Equals(aDocument->NodePrincipal())) {
return;
ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_SECURITY_ERR, __func__);
return ref.forget();
}
// The registration that should be controlling the client
@ -3379,56 +3202,41 @@ ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDocument,
GetDocumentRegistration(aDocument, getter_AddRefs(controllingRegistration));
if (aWorkerRegistration != matchingRegistration ||
aWorkerRegistration == controllingRegistration) {
return;
aWorkerRegistration == controllingRegistration) {
ref = GenericPromise::CreateAndResolve(true, __func__);
return ref.forget();
}
if (controllingRegistration) {
StopControllingADocument(controllingRegistration);
}
StartControllingADocument(aWorkerRegistration, aDocument, NS_LITERAL_STRING(""));
FireControllerChangeOnDocument(aDocument);
ref = StartControllingADocument(aWorkerRegistration, aDocument);
return ref.forget();
}
nsresult
ServiceWorkerManager::ClaimClients(nsIPrincipal* aPrincipal,
const nsCString& aScope, uint64_t aId)
already_AddRefed<GenericPromise>
ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDoc,
const ServiceWorkerDescriptor& aServiceWorker)
{
RefPtr<GenericPromise> ref;
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(aServiceWorker.PrincipalInfo());
if (!principal) {
ref = GenericPromise::CreateAndResolve(false, __func__);
return ref.forget();
}
RefPtr<ServiceWorkerRegistrationInfo> registration =
GetRegistration(aPrincipal, aScope);
if (!registration || !registration->GetActive() ||
!(registration->GetActive()->ID() == aId)) {
// The worker is not active.
return NS_ERROR_DOM_INVALID_STATE_ERR;
GetRegistration(principal, aServiceWorker.Scope());
if (!registration) {
ref = GenericPromise::CreateAndResolve(false, __func__);
return ref.forget();
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsISimpleEnumerator> enumerator;
nsresult rv = obs->EnumerateObservers("service-worker-get-client",
getter_AddRefs(enumerator));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
bool loop = true;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&loop)) && loop) {
nsCOMPtr<nsISupports> ptr;
rv = enumerator->GetNext(getter_AddRefs(ptr));
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
nsCOMPtr<nsIDocument> doc = do_QueryInterface(ptr);
MaybeClaimClient(doc, registration);
}
return NS_OK;
ref = MaybeClaimClient(aDoc, registration);
return ref.forget();
}
void
@ -3457,11 +3265,14 @@ ServiceWorkerManager::SetSkipWaitingFlag(nsIPrincipal* aPrincipal,
}
void
ServiceWorkerManager::FireControllerChange(ServiceWorkerRegistrationInfo* aRegistration)
ServiceWorkerManager::UpdateClientControllers(ServiceWorkerRegistrationInfo* aRegistration)
{
AssertIsOnMainThread();
AutoTArray<nsCOMPtr<nsIDocument>, 16> documents;
RefPtr<ServiceWorkerInfo> activeWorker = aRegistration->GetActive();
MOZ_DIAGNOSTIC_ASSERT(activeWorker);
AutoTArray<nsCOMPtr<nsPIDOMWindowInner>, 16> innerWindows;
for (auto iter = mControlledDocuments.Iter(); !iter.Done(); iter.Next()) {
if (iter.UserData() != aRegistration) {
continue;
@ -3472,13 +3283,24 @@ ServiceWorkerManager::FireControllerChange(ServiceWorkerRegistrationInfo* aRegis
continue;
}
documents.AppendElement(doc);
nsPIDOMWindowInner* innerWindow = doc->GetInnerWindow();
if (NS_WARN_IF(!innerWindow)) {
continue;
}
innerWindows.AppendElement(innerWindow);
}
// Fire event after iterating mControlledDocuments is done to prevent
// modification by reentering from the event handlers during iteration.
for (auto& doc : documents) {
FireControllerChangeOnDocument(doc);
for (auto& innerWindow : innerWindows) {
Maybe<ClientInfo> clientInfo = innerWindow->GetClientInfo();
if (clientInfo.isSome()) {
RefPtr<ClientHandle> clientHandle =
ClientManager::CreateHandle(clientInfo.ref(),
innerWindow->EventTargetFor(TaskCategory::Other));
clientHandle->Control(activeWorker->Descriptor());
}
}
}

Просмотреть файл

@ -46,7 +46,6 @@ class ServiceWorkerRegistrationListener;
namespace workers {
class ServiceWorkerClientInfo;
class ServiceWorkerInfo;
class ServiceWorkerJobQueue;
class ServiceWorkerManagerChild;
@ -151,7 +150,6 @@ public:
void
DispatchFetchEvent(const OriginAttributes& aOriginAttributes,
nsIDocument* aDoc,
const nsAString& aDocumentIdForTopLevelNavigation,
nsIInterceptedChannel* aChannel,
bool aIsReload,
bool aIsSubresourceLoad,
@ -273,24 +271,13 @@ public:
uint32_t aFlags,
JSExnType aExnType);
UniquePtr<ServiceWorkerClientInfo>
GetClient(nsIPrincipal* aPrincipal,
const nsAString& aClientId,
ErrorResult& aRv);
void
GetAllClients(nsIPrincipal* aPrincipal,
const nsCString& aScope,
uint64_t aServiceWorkerID,
bool aIncludeUncontrolled,
nsTArray<ServiceWorkerClientInfo>& aDocuments);
void
already_AddRefed<GenericPromise>
MaybeClaimClient(nsIDocument* aDocument,
ServiceWorkerRegistrationInfo* aWorkerRegistration);
nsresult
ClaimClients(nsIPrincipal* aPrincipal, const nsCString& aScope, uint64_t aId);
already_AddRefed<GenericPromise>
MaybeClaimClient(nsIDocument* aDoc,
const ServiceWorkerDescriptor& aServiceWorker);
void
SetSkipWaitingFlag(nsIPrincipal* aPrincipal, const nsCString& aScope,
@ -393,8 +380,7 @@ private:
RefPtr<GenericPromise>
StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration,
nsIDocument* aDoc,
const nsAString& aDocumentId);
nsIDocument* aDoc);
void
StopControllingADocument(ServiceWorkerRegistrationInfo* aRegistration);
@ -441,7 +427,7 @@ private:
FireUpdateFoundOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration);
void
FireControllerChange(ServiceWorkerRegistrationInfo* aRegistration);
UpdateClientControllers(ServiceWorkerRegistrationInfo* aRegistration);
void
StorePendingReadyPromise(nsPIDOMWindowInner* aWindow, nsIURI* aURI,

Просмотреть файл

@ -9,6 +9,7 @@
#include "nsISupportsImpl.h"
#include "nsHashKeys.h"
#include "nsTArray.h"
#include "nsTHashtable.h"
namespace mozilla {

Просмотреть файл

@ -7,7 +7,6 @@
#include "ServiceWorkerPrivate.h"
#include "ServiceWorkerManager.h"
#include "ServiceWorkerWindowClient.h"
#include "nsContentUtils.h"
#include "nsICacheInfoChannel.h"
#include "nsIHttpChannelInternal.h"
@ -26,6 +25,8 @@
#include "WorkerRunnable.h"
#include "WorkerScope.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/Client.h"
#include "mozilla/dom/ClientIPCTypes.h"
#include "mozilla/dom/FetchUtil.h"
#include "mozilla/dom/IndexedDatabaseManager.h"
#include "mozilla/dom/InternalHeaders.h"
@ -40,6 +41,8 @@ using namespace mozilla::dom;
BEGIN_WORKERS_NAMESPACE
using mozilla::ipc::PrincipalInfo;
NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(ServiceWorkerPrivate)
NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(ServiceWorkerPrivate)
NS_IMPL_CYCLE_COLLECTION(ServiceWorkerPrivate, mSupportsArray)
@ -484,22 +487,21 @@ public:
}
};
class SendMesssageEventRunnable final : public ExtendableEventWorkerRunnable
, public StructuredCloneHolder
class SendMessageEventRunnable final : public ExtendableEventWorkerRunnable
, public StructuredCloneHolder
{
UniquePtr<ServiceWorkerClientInfo> mEventSource;
const ClientInfoAndState mClientInfoAndState;
public:
SendMesssageEventRunnable(WorkerPrivate* aWorkerPrivate,
KeepAliveToken* aKeepAliveToken,
UniquePtr<ServiceWorkerClientInfo>&& aEventSource)
SendMessageEventRunnable(WorkerPrivate* aWorkerPrivate,
KeepAliveToken* aKeepAliveToken,
const ClientInfoAndState& aClientInfoAndState)
: ExtendableEventWorkerRunnable(aWorkerPrivate, aKeepAliveToken)
, StructuredCloneHolder(CloningSupported, TransferringSupported,
StructuredCloneScope::SameProcessDifferentThread)
, mEventSource(Move(aEventSource))
, mClientInfoAndState(aClientInfoAndState)
{
AssertIsOnMainThread();
MOZ_ASSERT(mEventSource);
}
bool
@ -518,8 +520,6 @@ public:
return true;
}
RefPtr<ServiceWorkerClient> client = new ServiceWorkerWindowClient(sgo,
*mEventSource);
RootedDictionary<ExtendableMessageEventInit> init(aCx);
init.mBubbles = false;
@ -527,7 +527,8 @@ public:
init.mData = messageData;
init.mPorts = ports;
init.mSource.SetValue().SetAsClient() = client;
init.mSource.SetValue().SetAsClient() =
new Client(sgo, mClientInfoAndState);
RefPtr<EventTarget> target = aWorkerPrivate->GlobalScope();
RefPtr<ExtendableMessageEvent> extendableEvent =
@ -553,7 +554,7 @@ nsresult
ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
const ClientInfoAndState& aClientInfoAndState)
{
AssertIsOnMainThread();
@ -571,8 +572,8 @@ ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx,
}
RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
RefPtr<SendMesssageEventRunnable> runnable =
new SendMesssageEventRunnable(mWorkerPrivate, token, Move(aClientInfo));
RefPtr<SendMessageEventRunnable> runnable =
new SendMessageEventRunnable(mWorkerPrivate, token, aClientInfoAndState);
runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy(), rv);
if (NS_WARN_IF(rv.Failed())) {
@ -1334,6 +1335,7 @@ class FetchEventRunnable : public ExtendableFunctionalEventWorkerRunnable
RequestCredentials mRequestCredentials;
nsContentPolicyType mContentPolicyType;
nsCOMPtr<nsIInputStream> mUploadStream;
int64_t mUploadStreamContentLength;
nsCString mReferrer;
ReferrerPolicy mReferrerPolicy;
nsString mIntegrity;
@ -1345,14 +1347,14 @@ public:
// later on.
const nsACString& aScriptSpec,
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
const nsAString& aDocumentId,
const nsAString& aClientId,
bool aIsReload,
bool aMarkLaunchServiceWorkerEnd)
: ExtendableFunctionalEventWorkerRunnable(
aWorkerPrivate, aKeepAliveToken, aRegistration)
, mInterceptedChannel(aChannel)
, mScriptSpec(aScriptSpec)
, mClientId(aDocumentId)
, mClientId(aClientId)
, mIsReload(aIsReload)
, mMarkLaunchServiceWorkerEnd(aMarkLaunchServiceWorkerEnd)
, mCacheMode(RequestCache::Default)
@ -1362,6 +1364,7 @@ public:
// send credentials to same-origin websites unless explicitly forbidden.
, mRequestCredentials(RequestCredentials::Same_origin)
, mContentPolicyType(nsIContentPolicy::TYPE_INVALID)
, mUploadStreamContentLength(-1)
, mReferrer(kFETCH_CLIENT_REFERRER_STR)
, mReferrerPolicy(ReferrerPolicy::_empty)
{
@ -1495,7 +1498,8 @@ public:
if (uploadChannel) {
MOZ_ASSERT(!mUploadStream);
nsCOMPtr<nsIInputStream> uploadStream;
rv = uploadChannel->CloneUploadStream(getter_AddRefs(uploadStream));
rv = uploadChannel->CloneUploadStream(&mUploadStreamContentLength,
getter_AddRefs(uploadStream));
NS_ENSURE_SUCCESS(rv, rv);
mUploadStream = uploadStream;
}
@ -1605,7 +1609,7 @@ private:
mReferrerPolicy,
mContentPolicyType,
mIntegrity);
internalReq->SetBody(mUploadStream, -1);
internalReq->SetBody(mUploadStream, mUploadStreamContentLength);
// For Telemetry, note that this Request object was created by a Fetch event.
internalReq->SetCreatedByFetchEvent();
@ -1637,7 +1641,11 @@ private:
init.mRequest = request;
init.mBubbles = false;
init.mCancelable = true;
if (!mClientId.IsEmpty()) {
// Only expose the FetchEvent.clientId on subresource requests for now.
// Once we implement .resultingClientId and .targetClientId we can then
// start exposing .clientId on non-subresource requests as well. See
// bug 1264177.
if (!mClientId.IsEmpty() && !internalReq->IsNavigationRequest()) {
init.mClientId = mClientId;
}
init.mIsReload = mIsReload;
@ -1683,8 +1691,7 @@ NS_IMPL_ISUPPORTS_INHERITED(FetchEventRunnable, WorkerRunnable, nsIHttpHeaderVis
nsresult
ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
nsILoadGroup* aLoadGroup,
const nsAString& aDocumentId,
bool aIsReload)
const nsAString& aClientId, bool aIsReload)
{
AssertIsOnMainThread();
@ -1761,7 +1768,7 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
RefPtr<FetchEventRunnable> r =
new FetchEventRunnable(mWorkerPrivate, token, handle,
mInfo->ScriptSpec(), regInfo,
aDocumentId, aIsReload, newWorkerCreated);
aClientId, aIsReload, newWorkerCreated);
rv = r->Init();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -1910,7 +1917,7 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
scriptSpec,
false, WorkerTypeService,
VoidString(),
mInfo->Scope(),
EmptyCString(),
&info, error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();

Просмотреть файл

@ -18,6 +18,9 @@ class nsIInterceptedChannel;
namespace mozilla {
namespace dom {
class ClientInfoAndState;
namespace workers {
class ServiceWorkerInfo;
@ -85,7 +88,7 @@ public:
nsresult
SendMessageEvent(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo);
const ClientInfoAndState& aClientInfoAndState);
// This is used to validate the worker script and continue the installation
// process.
@ -119,10 +122,8 @@ public:
const nsAString& aScope);
nsresult
SendFetchEvent(nsIInterceptedChannel* aChannel,
nsILoadGroup* aLoadGroup,
const nsAString& aDocumentId,
bool aIsReload);
SendFetchEvent(nsIInterceptedChannel* aChannel, nsILoadGroup* aLoadGroup,
const nsAString& aClientId, bool aIsReload);
void
StoreISupports(nsISupports* aSupports);

Просмотреть файл

@ -274,13 +274,8 @@ ServiceWorkerRegistrationInfo::Activate()
// FIXME(nsm): Unlink appcache if there is one.
// "Queue a task to fire a simple event named controllerchange..."
nsCOMPtr<nsIRunnable> controllerChangeRunnable =
NewRunnableMethod<RefPtr<ServiceWorkerRegistrationInfo>>(
"dom::workers::ServiceWorkerManager::FireControllerChange",
swm,
&ServiceWorkerManager::FireControllerChange,
this);
NS_DispatchToMainThread(controllerChangeRunnable);
MOZ_DIAGNOSTIC_ASSERT(mActiveWorker);
swm->UpdateClientControllers(this);
nsCOMPtr<nsIRunnable> failRunnable = NewRunnableMethod<bool>(
"dom::workers::ServiceWorkerRegistrationInfo::FinishActivate",

Просмотреть файл

@ -1,556 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/.
*/
#include "ServiceWorkerWindowClient.h"
#include "js/Value.h"
#include "mozilla/Mutex.h"
#include "mozilla/dom/ClientBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseWorkerProxy.h"
#include "mozilla/UniquePtr.h"
#include "nsContentUtils.h"
#include "nsGlobalWindow.h"
#include "nsIDocShell.h"
#include "nsIDocShellLoadInfo.h"
#include "nsIDocument.h"
#include "nsIGlobalObject.h"
#include "nsIPrincipal.h"
#include "nsIScriptSecurityManager.h"
#include "nsIWebNavigation.h"
#include "nsIWebProgress.h"
#include "nsIWebProgressListener.h"
#include "nsString.h"
#include "nsWeakReference.h"
#include "ServiceWorker.h"
#include "ServiceWorkerInfo.h"
#include "ServiceWorkerManager.h"
#include "WorkerPrivate.h"
#include "WorkerScope.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::workers;
using mozilla::UniquePtr;
JSObject*
ServiceWorkerWindowClient::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return WindowClientBinding::Wrap(aCx, this, aGivenProto);
}
namespace {
class ResolveOrRejectPromiseRunnable final : public WorkerRunnable
{
RefPtr<PromiseWorkerProxy> mPromiseProxy;
UniquePtr<ServiceWorkerClientInfo> mClientInfo;
nsresult mRv;
public:
// Passing a null clientInfo will resolve the promise with a null value.
ResolveOrRejectPromiseRunnable(
WorkerPrivate* aWorkerPrivate, PromiseWorkerProxy* aPromiseProxy,
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
: WorkerRunnable(aWorkerPrivate)
, mPromiseProxy(aPromiseProxy)
, mClientInfo(Move(aClientInfo))
, mRv(NS_OK)
{
AssertIsOnMainThread();
}
// Reject the promise with passed nsresult.
ResolveOrRejectPromiseRunnable(WorkerPrivate* aWorkerPrivate,
PromiseWorkerProxy* aPromiseProxy,
nsresult aRv)
: WorkerRunnable(aWorkerPrivate)
, mPromiseProxy(aPromiseProxy)
, mClientInfo(nullptr)
, mRv(aRv)
{
MOZ_ASSERT(NS_FAILED(aRv));
AssertIsOnMainThread();
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
RefPtr<Promise> promise = mPromiseProxy->WorkerPromise();
MOZ_ASSERT(promise);
if (NS_WARN_IF(NS_FAILED(mRv))) {
promise->MaybeReject(mRv);
} else if (mClientInfo) {
RefPtr<ServiceWorkerWindowClient> client =
new ServiceWorkerWindowClient(promise->GetParentObject(), *mClientInfo);
promise->MaybeResolve(client);
} else {
promise->MaybeResolve(JS::NullHandleValue);
}
// Release the reference on the worker thread.
mPromiseProxy->CleanUp();
return true;
}
};
class ClientFocusRunnable final : public Runnable
{
uint64_t mWindowId;
RefPtr<PromiseWorkerProxy> mPromiseProxy;
public:
ClientFocusRunnable(uint64_t aWindowId, PromiseWorkerProxy* aPromiseProxy)
: mozilla::Runnable("ClientFocusRunnable")
, mWindowId(aWindowId)
, mPromiseProxy(aPromiseProxy)
{
MOZ_ASSERT(mPromiseProxy);
}
NS_IMETHOD
Run() override
{
AssertIsOnMainThread();
nsGlobalWindowInner* window =
nsGlobalWindowInner::GetInnerWindowWithId(mWindowId);
UniquePtr<ServiceWorkerClientInfo> clientInfo;
if (window) {
nsCOMPtr<nsIDocument> doc = window->GetDocument();
if (doc) {
nsContentUtils::DispatchFocusChromeEvent(window->GetOuterWindow());
clientInfo.reset(new ServiceWorkerClientInfo(doc));
}
}
DispatchResult(Move(clientInfo));
return NS_OK;
}
private:
void
DispatchResult(UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
{
AssertIsOnMainThread();
MutexAutoLock lock(mPromiseProxy->Lock());
if (mPromiseProxy->CleanedUp()) {
return;
}
RefPtr<ResolveOrRejectPromiseRunnable> resolveRunnable;
if (aClientInfo) {
resolveRunnable = new ResolveOrRejectPromiseRunnable(
mPromiseProxy->GetWorkerPrivate(), mPromiseProxy, Move(aClientInfo));
} else {
resolveRunnable = new ResolveOrRejectPromiseRunnable(
mPromiseProxy->GetWorkerPrivate(), mPromiseProxy,
NS_ERROR_DOM_INVALID_ACCESS_ERR);
}
resolveRunnable->Dispatch();
}
};
} // namespace
already_AddRefed<Promise>
ServiceWorkerWindowClient::Focus(ErrorResult& aRv) const
{
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
MOZ_ASSERT(global);
RefPtr<Promise> promise = Promise::Create(global, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
if (workerPrivate->GlobalScope()->WindowInteractionAllowed()) {
RefPtr<PromiseWorkerProxy> promiseProxy =
PromiseWorkerProxy::Create(workerPrivate, promise);
if (promiseProxy) {
RefPtr<ClientFocusRunnable> r = new ClientFocusRunnable(mWindowId,
promiseProxy);
MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
} else {
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
}
} else {
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
}
return promise.forget();
}
class WebProgressListener final : public nsIWebProgressListener,
public nsSupportsWeakReference
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(WebProgressListener,
nsIWebProgressListener)
WebProgressListener(PromiseWorkerProxy* aPromiseProxy,
ServiceWorkerPrivate* aServiceWorkerPrivate,
nsPIDOMWindowOuter* aWindow, nsIURI* aBaseURI)
: mPromiseProxy(aPromiseProxy)
, mServiceWorkerPrivate(aServiceWorkerPrivate)
, mWindow(aWindow)
, mBaseURI(aBaseURI)
{
MOZ_ASSERT(aPromiseProxy);
MOZ_ASSERT(aServiceWorkerPrivate);
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aBaseURI);
AssertIsOnMainThread();
mServiceWorkerPrivate->StoreISupports(static_cast<nsIWebProgressListener*>(this));
}
NS_IMETHOD
OnStateChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
uint32_t aStateFlags, nsresult aStatus) override
{
if (!(aStateFlags & STATE_IS_DOCUMENT) ||
!(aStateFlags & (STATE_STOP | STATE_TRANSFERRING))) {
return NS_OK;
}
// This is safe because our caller holds a strong ref.
mServiceWorkerPrivate->RemoveISupports(static_cast<nsIWebProgressListener*>(this));
aWebProgress->RemoveProgressListener(this);
WorkerPrivate* workerPrivate;
{
MutexAutoLock lock(mPromiseProxy->Lock());
if (mPromiseProxy->CleanedUp()) {
return NS_OK;
}
workerPrivate = mPromiseProxy->GetWorkerPrivate();
}
nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
RefPtr<ResolveOrRejectPromiseRunnable> resolveRunnable;
UniquePtr<ServiceWorkerClientInfo> clientInfo;
if (!doc) {
resolveRunnable = new ResolveOrRejectPromiseRunnable(
workerPrivate, mPromiseProxy, NS_ERROR_TYPE_ERR);
resolveRunnable->Dispatch();
return NS_OK;
}
// Check same origin.
nsCOMPtr<nsIScriptSecurityManager> securityManager =
nsContentUtils::GetSecurityManager();
nsresult rv = securityManager->CheckSameOriginURI(doc->GetOriginalURI(),
mBaseURI, false);
if (NS_SUCCEEDED(rv)) {
nsContentUtils::DispatchFocusChromeEvent(mWindow->GetOuterWindow());
clientInfo.reset(new ServiceWorkerClientInfo(doc));
}
resolveRunnable = new ResolveOrRejectPromiseRunnable(
workerPrivate, mPromiseProxy, Move(clientInfo));
resolveRunnable->Dispatch();
return NS_OK;
}
NS_IMETHOD
OnProgressChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
int32_t aCurSelfProgress, int32_t aMaxSelfProgress,
int32_t aCurTotalProgress,
int32_t aMaxTotalProgress) override
{
MOZ_CRASH("Unexpected notification.");
return NS_OK;
}
NS_IMETHOD
OnLocationChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
nsIURI* aLocation, uint32_t aFlags) override
{
MOZ_CRASH("Unexpected notification.");
return NS_OK;
}
NS_IMETHOD
OnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
nsresult aStatus, const char16_t* aMessage) override
{
MOZ_CRASH("Unexpected notification.");
return NS_OK;
}
NS_IMETHOD
OnSecurityChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
uint32_t aState) override
{
MOZ_CRASH("Unexpected notification.");
return NS_OK;
}
private:
~WebProgressListener() {}
RefPtr<PromiseWorkerProxy> mPromiseProxy;
RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
nsCOMPtr<nsPIDOMWindowOuter> mWindow;
nsCOMPtr<nsIURI> mBaseURI;
};
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebProgressListener)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebProgressListener)
NS_IMPL_CYCLE_COLLECTION(WebProgressListener, mPromiseProxy,
mServiceWorkerPrivate, mWindow)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebProgressListener)
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END
class ClientNavigateRunnable final : public Runnable
{
uint64_t mWindowId;
nsString mUrl;
nsCString mBaseUrl;
nsString mScope;
RefPtr<PromiseWorkerProxy> mPromiseProxy;
MOZ_INIT_OUTSIDE_CTOR WorkerPrivate* mWorkerPrivate;
public:
ClientNavigateRunnable(uint64_t aWindowId,
const nsAString& aUrl,
const nsAString& aScope,
PromiseWorkerProxy* aPromiseProxy)
: mozilla::Runnable("ClientNavigateRunnable")
, mWindowId(aWindowId)
, mUrl(aUrl)
, mScope(aScope)
, mPromiseProxy(aPromiseProxy)
, mWorkerPrivate(nullptr)
{
MOZ_ASSERT(aPromiseProxy);
MOZ_ASSERT(aPromiseProxy->GetWorkerPrivate());
aPromiseProxy->GetWorkerPrivate()->AssertIsOnWorkerThread();
}
NS_IMETHOD
Run() override
{
AssertIsOnMainThread();
nsCOMPtr<nsIPrincipal> principal;
{
MutexAutoLock lock(mPromiseProxy->Lock());
if (mPromiseProxy->CleanedUp()) {
return NS_OK;
}
mWorkerPrivate = mPromiseProxy->GetWorkerPrivate();
WorkerPrivate::LocationInfo& info = mWorkerPrivate->GetLocationInfo();
mBaseUrl = info.mHref;
principal = mWorkerPrivate->GetPrincipal();
MOZ_DIAGNOSTIC_ASSERT(principal);
}
nsCOMPtr<nsIURI> baseUrl;
nsCOMPtr<nsIURI> url;
nsresult rv = ParseUrl(getter_AddRefs(baseUrl), getter_AddRefs(url));
if (NS_WARN_IF(NS_FAILED(rv))) {
return RejectPromise(NS_ERROR_TYPE_ERR);
}
nsGlobalWindowInner* window;
rv = Navigate(url, principal, &window);
if (NS_WARN_IF(NS_FAILED(rv))) {
return RejectPromise(rv);
}
nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
if (NS_WARN_IF(!webProgress)) {
return NS_ERROR_FAILURE;
}
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
return NS_ERROR_FAILURE;
}
RefPtr<ServiceWorkerRegistrationInfo> registration =
swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope));
if (NS_WARN_IF(!registration)) {
return NS_ERROR_FAILURE;
}
RefPtr<ServiceWorkerInfo> serviceWorkerInfo =
registration->GetServiceWorkerInfoById(mWorkerPrivate->ServiceWorkerID());
if (NS_WARN_IF(!serviceWorkerInfo)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIWebProgressListener> listener =
new WebProgressListener(mPromiseProxy, serviceWorkerInfo->WorkerPrivate(),
window->GetOuterWindow(), baseUrl);
rv = webProgress->AddProgressListener(
listener, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
if (NS_WARN_IF(NS_FAILED(rv))) {
return RejectPromise(rv);
}
return NS_OK;
}
private:
nsresult
RejectPromise(nsresult aRv)
{
MOZ_ASSERT(mWorkerPrivate);
RefPtr<ResolveOrRejectPromiseRunnable> resolveRunnable =
new ResolveOrRejectPromiseRunnable(mWorkerPrivate, mPromiseProxy, aRv);
resolveRunnable->Dispatch();
return NS_OK;
}
nsresult
ResolvePromise(UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
{
MOZ_ASSERT(mWorkerPrivate);
RefPtr<ResolveOrRejectPromiseRunnable> resolveRunnable =
new ResolveOrRejectPromiseRunnable(mWorkerPrivate, mPromiseProxy,
Move(aClientInfo));
resolveRunnable->Dispatch();
return NS_OK;
}
nsresult
ParseUrl(nsIURI** aBaseUrl, nsIURI** aUrl)
{
MOZ_ASSERT(aBaseUrl);
MOZ_ASSERT(aUrl);
AssertIsOnMainThread();
nsCOMPtr<nsIURI> baseUrl;
nsresult rv = NS_NewURI(getter_AddRefs(baseUrl), mBaseUrl);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> url;
rv = NS_NewURI(getter_AddRefs(url), mUrl, nullptr, baseUrl);
NS_ENSURE_SUCCESS(rv, rv);
baseUrl.forget(aBaseUrl);
url.forget(aUrl);
return NS_OK;
}
nsresult
Navigate(nsIURI* aUrl, nsIPrincipal* aPrincipal, nsGlobalWindowInner** aWindow)
{
MOZ_ASSERT(aWindow);
nsGlobalWindowInner* window =
nsGlobalWindowInner::GetInnerWindowWithId(mWindowId);
if (NS_WARN_IF(!window)) {
return NS_ERROR_TYPE_ERR;
}
nsCOMPtr<nsIDocument> doc = window->GetDocument();
if (NS_WARN_IF(!doc)) {
return NS_ERROR_TYPE_ERR;
}
if (NS_WARN_IF(!doc->IsActive())) {
return NS_ERROR_TYPE_ERR;
}
nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
if (NS_WARN_IF(!docShell)) {
return NS_ERROR_TYPE_ERR;
}
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
nsresult rv = docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_TYPE_ERR;
}
loadInfo->SetTriggeringPrincipal(aPrincipal);
loadInfo->SetReferrerPolicy(doc->GetReferrerPolicy());
loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContent);
loadInfo->SetSourceDocShell(docShell);
rv =
docShell->LoadURI(aUrl, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_TYPE_ERR;
}
*aWindow = window;
return NS_OK;
}
};
already_AddRefed<Promise>
ServiceWorkerWindowClient::Navigate(const nsAString& aUrl, ErrorResult& aRv)
{
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
MOZ_ASSERT(global);
RefPtr<Promise> promise = Promise::Create(global, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
if (aUrl.EqualsLiteral("about:blank")) {
promise->MaybeReject(NS_ERROR_TYPE_ERR);
return promise.forget();
}
ServiceWorkerGlobalScope* globalScope =
static_cast<ServiceWorkerGlobalScope*>(workerPrivate->GlobalScope());
nsString scope;
globalScope->GetScope(scope);
RefPtr<PromiseWorkerProxy> promiseProxy =
PromiseWorkerProxy::Create(workerPrivate, promise);
if (promiseProxy) {
RefPtr<ClientNavigateRunnable> r =
new ClientNavigateRunnable(mWindowId, aUrl, scope, promiseProxy);
MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
} else {
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
}
return promise.forget();
}

Просмотреть файл

@ -1,64 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/.
*/
#ifndef mozilla_dom_workers_serviceworkerwindowclient_h
#define mozilla_dom_workers_serviceworkerwindowclient_h
#include "ServiceWorkerClient.h"
namespace mozilla {
namespace dom {
class Promise;
namespace workers {
class ServiceWorkerWindowClient final : public ServiceWorkerClient
{
public:
ServiceWorkerWindowClient(nsISupports* aOwner,
const ServiceWorkerClientInfo& aClientInfo)
: ServiceWorkerClient(aOwner, aClientInfo),
mVisibilityState(aClientInfo.mVisibilityState),
mFocused(aClientInfo.mFocused)
{
}
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
mozilla::dom::VisibilityState
VisibilityState() const
{
return mVisibilityState;
}
bool
Focused() const
{
return mFocused;
}
already_AddRefed<Promise>
Focus(ErrorResult& aRv) const;
already_AddRefed<Promise>
Navigate(const nsAString& aUrl, ErrorResult& aRv);
private:
~ServiceWorkerWindowClient()
{ }
mozilla::dom::VisibilityState mVisibilityState;
bool mFocused;
};
} // namespace workers
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_workers_serviceworkerwindowclient_h

Просмотреть файл

@ -33,7 +33,6 @@ WORKER_SIMPLE_PREF("dom.webnotifications.serviceworker.enabled", DOMServiceWorke
WORKER_SIMPLE_PREF("dom.webnotifications.requireinteraction.enabled", DOMWorkerNotificationRIEnabled, DOM_WORKERNOTIFICATIONRI)
WORKER_SIMPLE_PREF("dom.serviceWorkers.enabled", ServiceWorkersEnabled, SERVICEWORKERS_ENABLED)
WORKER_SIMPLE_PREF("dom.serviceWorkers.testing.enabled", ServiceWorkersTestingEnabled, SERVICEWORKERS_TESTING_ENABLED)
WORKER_SIMPLE_PREF("dom.serviceWorkers.openWindow.enabled", OpenWindowEnabled, OPEN_WINDOW_ENABLED)
WORKER_SIMPLE_PREF("dom.storageManager.enabled", StorageManagerEnabled, STORAGEMANAGER_ENABLED)
WORKER_SIMPLE_PREF("dom.promise_rejection_events.enabled", PromiseRejectionEventsEnabled, PROMISE_REJECTION_EVENTS_ENABLED)
WORKER_SIMPLE_PREF("dom.push.enabled", PushEnabled, PUSH_ENABLED)

Просмотреть файл

@ -9,6 +9,7 @@
#include "jsapi.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/Clients.h"
#include "mozilla/dom/Console.h"
#include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h"
#include "mozilla/dom/Fetch.h"
@ -44,7 +45,6 @@
#include "ScriptLoader.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#include "ServiceWorkerClients.h"
#include "ServiceWorkerManager.h"
#include "ServiceWorkerRegistration.h"
@ -634,14 +634,15 @@ ServiceWorkerGlobalScope::WrapGlobalObject(JSContext* aCx,
true, aReflector);
}
ServiceWorkerClients*
ServiceWorkerGlobalScope::Clients()
already_AddRefed<Clients>
ServiceWorkerGlobalScope::GetClients()
{
if (!mClients) {
mClients = new ServiceWorkerClients(this);
mClients = new Clients(this);
}
return mClients;
RefPtr<Clients> ref = mClients;
return ref.forget();
}
ServiceWorkerRegistration*
@ -848,15 +849,6 @@ ServiceWorkerGlobalScope::SkipWaiting(ErrorResult& aRv)
return promise.forget();
}
bool
ServiceWorkerGlobalScope::OpenWindowEnabled(JSContext* aCx, JSObject* aObj)
{
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
return worker->OpenWindowEnabled();
}
WorkerDebuggerGlobalScope::WorkerDebuggerGlobalScope(
WorkerPrivate* aWorkerPrivate)
: mWorkerPrivate(aWorkerPrivate)

Просмотреть файл

@ -19,6 +19,7 @@ namespace dom {
class AnyCallback;
struct ChannelPixelLayout;
class Clients;
class Console;
class Crypto;
class Function;
@ -40,7 +41,6 @@ class CacheStorage;
namespace workers {
class ServiceWorkerClients;
class WorkerPrivate;
} // namespace workers
@ -282,7 +282,7 @@ public:
class ServiceWorkerGlobalScope final : public WorkerGlobalScope
{
const nsString mScope;
RefPtr<workers::ServiceWorkerClients> mClients;
RefPtr<Clients> mClients;
RefPtr<ServiceWorkerRegistration> mRegistration;
~ServiceWorkerGlobalScope();
@ -300,17 +300,14 @@ public:
WrapGlobalObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aReflector) override;
static bool
OpenWindowEnabled(JSContext* aCx, JSObject* aObj);
void
GetScope(nsString& aScope) const
{
aScope = mScope;
}
workers::ServiceWorkerClients*
Clients();
already_AddRefed<Clients>
GetClients();
ServiceWorkerRegistration*
Registration();

Просмотреть файл

@ -37,9 +37,6 @@ EXPORTS.mozilla.dom.workers += [
# Stuff needed for the bindings, not really public though.
EXPORTS.mozilla.dom.workers.bindings += [
'ServiceWorker.h',
'ServiceWorkerClient.h',
'ServiceWorkerClients.h',
'ServiceWorkerWindowClient.h',
'SharedWorker.h',
'WorkerHolder.h',
'WorkerHolderToken.h',
@ -60,8 +57,6 @@ UNIFIED_SOURCES += [
'RuntimeService.cpp',
'ScriptLoader.cpp',
'ServiceWorker.cpp',
'ServiceWorkerClient.cpp',
'ServiceWorkerClients.cpp',
'ServiceWorkerContainer.cpp',
'ServiceWorkerDescriptor.cpp',
'ServiceWorkerEvents.cpp',
@ -82,7 +77,6 @@ UNIFIED_SOURCES += [
'ServiceWorkerUpdateJob.cpp',
'ServiceWorkerUpdaterChild.cpp',
'ServiceWorkerUpdaterParent.cpp',
'ServiceWorkerWindowClient.cpp',
'SharedWorker.cpp',
'WorkerDebuggerManager.cpp',
'WorkerHolder.cpp',

Просмотреть файл

@ -60,9 +60,9 @@ onmessage = function(event) {
promises.push(testForUrl("about:blank", "TypeError", null, results));
promises.push(testForUrl("http://example.com", "InvalidAccessError", null, results));
promises.push(testForUrl("_._*`InvalidURL", "InvalidAccessError", null, results));
Promise.all(promises).then(function(e) {
event.waitUntil(Promise.all(promises).then(function(e) {
client.postMessage(results);
});
}));
}
if (event.data == "NEW_WINDOW") {
window_count += 1;
@ -72,7 +72,7 @@ onmessage = function(event) {
}
if (event.data == "CHECK_NUMBER_OF_WINDOWS") {
got_all_windows.then(function() {
event.waitUntil(got_all_windows.then(function() {
return clients.matchAll();
}).then(function(cl) {
event.source.postMessage({result: cl.length == expected_window_count,
@ -80,7 +80,7 @@ onmessage = function(event) {
for (i = 0; i < cl.length; i++) {
cl[i].postMessage("CLOSE");
}
});
}));
}
}
@ -101,16 +101,16 @@ onnotificationclick = function(e) {
// redirect tests
promises.push(testForUrl(redirect + "open_window/client.html", null,
{url: same_origin}, results));
{url: same_origin}, results));
promises.push(testForUrl(redirect + different_origin, null, null, results));
promises.push(testForUrl(redirect_xorigin + "open_window/client.html", null,
null, results));
null, results));
promises.push(testForUrl(redirect_xorigin + same_origin, null,
{url: same_origin}, results));
{url: same_origin}, results));
Promise.all(promises).then(function(e) {
e.waitUntil(Promise.all(promises).then(function(e) {
client.postMessage(results);
});
}));
}

Просмотреть файл

@ -41,13 +41,18 @@ SourceSurfaceD2D1::IsValid() const
already_AddRefed<DataSourceSurface>
SourceSurfaceD2D1::GetDataSurface()
{
HRESULT hr;
Maybe<MutexAutoLock> lock;
if (mSnapshotLock) {
lock.emplace(*mSnapshotLock);
}
if (!EnsureRealizedBitmap()) {
gfxCriticalError() << "Failed to realize a bitmap, device " << hexa(mDevice);
return nullptr;
}
HRESULT hr;
RefPtr<ID2D1Bitmap1> softwareBitmap;
D2D1_BITMAP_PROPERTIES1 props;
props.dpiX = 96;

Просмотреть файл

@ -46,7 +46,7 @@ static const uint32_t gLBClass20[32] = {
0x77775555, // U+2008 - U+200F
0x777277B7, // U+2010 - U+2017
0x77A777A7, // U+2018 - U+201F
0xAAAA7777, // U+2020 - U+2027
0xA1117777, // U+2020 - U+2027
0xB7777777, // U+2028 - U+202F
0x77744444, // U+2030 - U+2037
0x7A115107, // U+2038 - U+203F

Просмотреть файл

@ -96,10 +96,10 @@ Analysis of JIS X 4051 to Unicode General Category Mapping
<TD>32</TD>
<TD>2</TD>
<TD></TD>
<TD>28</TD>
<TD>31</TD>
<TD>3</TD>
<TD></TD>
<TD BGCOLOR=white>65</TD>
<TD BGCOLOR=white>68</TD>
<TD></TD>
<TD></TD>
<TD></TD>
@ -120,7 +120,7 @@ Analysis of JIS X 4051 to Unicode General Category Mapping
<TD>12</TD>
<TD>1</TD>
<TD></TD>
<TD>14</TD>
<TD>17</TD>
<TD></TD>
<TD></TD>
<TD>2</TD>
@ -447,10 +447,10 @@ Analysis of JIS X 4051 to Unicode General Category Mapping
<TD>2</TD>
<TD></TD>
<TD>6</TD>
<TD>28</TD>
<TD>25</TD>
<TD>14</TD>
<TD></TD>
<TD BGCOLOR=white>51</TD>
<TD BGCOLOR=white>48</TD>
<TD></TD>
<TD>1</TD>
<TD></TD>
@ -471,7 +471,7 @@ Analysis of JIS X 4051 to Unicode General Category Mapping
<TD>3</TD>
<TD>3</TD>
<TD></TD>
<TD>22</TD>
<TD>19</TD>
<TD></TD>
<TD>2</TD>
<TD>3</TD>
@ -623,7 +623,7 @@ Analysis of JIS X 4051 to Unicode General Category Mapping
</TR>
<TR><TH>20<TH>
<TD>2</TD>
<TD>8</TD>
<TD>11</TD>
<TD>1</TD>
<TD></TD>
<TD>5</TD>
@ -632,7 +632,7 @@ Analysis of JIS X 4051 to Unicode General Category Mapping
<TD>100</TD>
<TD></TD>
<TD></TD>
<TD>7</TD>
<TD>4</TD>
<TD>4</TD>
<TD></TD>
</TR>

Просмотреть файл

@ -50,8 +50,8 @@ open ( OUT , "> anzx4051.html")
# Open the output file
#
######################################################################
open ( HEADER , "> ../src/jisx4051class.h")
|| die "cannot open output ../src/jisx4051class.h file";
open ( HEADER , "> ../jisx4051class.h")
|| die "cannot open output ../jisx4051class.h file";
######################################################################
#
@ -86,7 +86,7 @@ $npl = <<END_OF_NPL;
/* 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/. */
/*
/*
DO NOT EDIT THIS DOCUMENT !!! THIS DOCUMENT IS GENERATED BY
mozilla/intl/lwbrk/tools/anzx4051.pl
*/

Просмотреть файл

@ -61,7 +61,7 @@
201D;;23
2018;201F;18
2020;2023;18
2024;2026;23
2024;2026;2
2027;;23
2028;202E;18
202F;;24

Просмотреть файл

@ -226,11 +226,9 @@ class HashMap
return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf);
}
#ifdef JS_DEBUG
Generation generation() const {
return impl.generation();
}
#endif
/************************************************** Shorthand operations */
@ -475,11 +473,9 @@ class HashSet
return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf);
}
#ifdef JS_DEBUG
Generation generation() const {
return impl.generation();
}
#endif
/************************************************** Shorthand operations */
@ -1129,9 +1125,7 @@ class HashTable : private AllocPolicy
// Potentially rehashes the table.
~Enum() {
if (rekeyed) {
#ifdef JS_DEBUG
table_.gen++;
#endif
table_.checkOverRemoved();
}
@ -1164,14 +1158,13 @@ class HashTable : private AllocPolicy
static const size_t CAP_BITS = 30;
public:
uint64_t gen:56; // entry storage generation number
uint64_t hashShift:8; // multiplicative hash shift
Entry* table; // entry storage
uint32_t hashShift; // multiplicative hash shift
uint32_t minCapacity; // minimum table capacity
uint32_t entryCount; // number of entries in table
uint32_t removedCount; // removed entry sentinels in table
#ifdef JS_DEBUG
uint64_t gen; // entry storage generation number
uint64_t mutationCount;
mutable bool mEntered;
// Note that some updates to these stats are not thread-safe. See the
@ -1264,12 +1257,12 @@ class HashTable : private AllocPolicy
public:
explicit HashTable(AllocPolicy ap)
: AllocPolicy(ap)
, table(nullptr)
, gen(0)
, hashShift(sHashBits)
, table(nullptr)
, entryCount(0)
, removedCount(0)
#ifdef JS_DEBUG
, gen(0)
, mutationCount(0)
, mEntered(false)
#endif
@ -1307,11 +1300,11 @@ class HashTable : private AllocPolicy
++roundUpLog2;
}
minCapacity = roundUp;
MOZ_ASSERT(minCapacity >= length);
MOZ_ASSERT(minCapacity <= sMaxCapacity);
newCapacity = roundUp;
MOZ_ASSERT(newCapacity >= length);
MOZ_ASSERT(newCapacity <= sMaxCapacity);
table = createTable(*this, minCapacity);
table = createTable(*this, newCapacity);
if (!table)
return false;
@ -1366,19 +1359,18 @@ class HashTable : private AllocPolicy
capacity() * sMaxAlphaNumerator / sAlphaDenominator;
}
// Considering its current entryCount, would the table be underloaded if it
// had the given capacity?
bool wouldBeUnderloaded(uint32_t capacity)
// Would the table be underloaded if it had the given capacity and entryCount?
static bool wouldBeUnderloaded(uint32_t capacity, uint32_t entryCount)
{
static_assert(sMaxCapacity <= UINT32_MAX / sMinAlphaNumerator,
"multiplication below could overflow");
return capacity > minCapacity &&
return capacity > sMinCapacity &&
entryCount <= capacity * sMinAlphaNumerator / sAlphaDenominator;
}
bool underloaded()
{
return wouldBeUnderloaded(capacity());
return wouldBeUnderloaded(capacity(), entryCount);
}
static MOZ_ALWAYS_INLINE bool match(Entry& e, const Lookup& l)
@ -1511,11 +1503,8 @@ class HashTable : private AllocPolicy
// We can't fail from here on, so update table parameters.
setTableSizeLog2(newLog2);
removedCount = 0;
table = newTable;
#ifdef JS_DEBUG
gen++;
#endif
table = newTable;
// Copy only live entries, leaving removed ones behind.
Entry* end = oldTable + oldCap;
@ -1598,7 +1587,7 @@ class HashTable : private AllocPolicy
{
int32_t resizeLog2 = 0;
uint32_t newCapacity = capacity();
while (wouldBeUnderloaded(newCapacity)) {
while (wouldBeUnderloaded(newCapacity, entryCount)) {
newCapacity = newCapacity >> 1;
resizeLog2--;
}
@ -1616,9 +1605,7 @@ class HashTable : private AllocPolicy
{
METER(stats.rehashes++);
removedCount = 0;
#ifdef JS_DEBUG
gen++;
#endif
for (size_t i = 0; i < capacity(); ++i)
table[i].unsetCollision();
@ -1714,10 +1701,10 @@ class HashTable : private AllocPolicy
destroyTable(*this, table, capacity());
table = nullptr;
gen++;
entryCount = 0;
removedCount = 0;
#ifdef JS_DEBUG
gen++;
mutationCount++;
#endif
}
@ -1746,13 +1733,11 @@ class HashTable : private AllocPolicy
return JS_BIT(sHashBits - hashShift);
}
#ifdef JS_DEBUG
Generation generation() const
{
MOZ_ASSERT(table);
return Generation(gen);
}
#endif
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{

Просмотреть файл

@ -3101,6 +3101,17 @@ HelperThreadCount(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
EnableShapeConsistencyChecks(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
#ifdef DEBUG
NativeObject::enableShapeConsistencyChecks();
#endif
args.rval().setUndefined();
return true;
}
#ifdef JS_TRACE_LOGGING
static bool
EnableTraceLogger(JSContext* cx, unsigned argc, Value* vp)
@ -5353,6 +5364,10 @@ gc::ZealModeHelpText),
"helperThreadCount()",
" Returns the number of helper threads available for off-thread tasks."),
JS_FN_HELP("enableShapeConsistencyChecks", EnableShapeConsistencyChecks, 0, 0,
"enableShapeConsistencyChecks()",
" Enable some slow Shape assertions.\n"),
#ifdef JS_TRACE_LOGGING
JS_FN_HELP("startTraceLogger", EnableTraceLogger, 0, 0,
"startTraceLogger()",

Просмотреть файл

@ -77,20 +77,14 @@ class StoreBuffer
*/
T last_;
/*
* Maximum number of entries before we request a minor GC.
*
* This is passed to HashSet::init(), which will pre-allocate a hash
* table capable of holding this many entries before rehashing, which is
* currently 4/3 this value.
*/
const static size_t MaxEntries = 8192;
/* Maximum number of entries before we request a minor GC. */
const static size_t MaxEntries = 48 * 1024 / sizeof(T);
explicit MonoTypeBuffer() : last_(T()) {}
~MonoTypeBuffer() { stores_.finish(); }
MOZ_MUST_USE bool init() {
if (!stores_.initialized() && !stores_.init(MaxEntries))
if (!stores_.initialized() && !stores_.init())
return false;
clear();
return true;
@ -100,7 +94,6 @@ class StoreBuffer
last_ = T();
if (stores_.initialized())
stores_.clear();
MOZ_ASSERT(stores_.capacity() > MaxEntries);
}
/* Add one item to the buffer. */

Просмотреть файл

@ -0,0 +1,8 @@
enableShapeConsistencyChecks();
var o = {};
for (var i = 0; i < 50; i++) {
o["x" + i] = i;
}
for (var i = 0; i < 50; i += 2) {
delete o["x" + i];
}

Просмотреть файл

@ -0,0 +1,58 @@
function sparse() {
var o = {0: 0, 0x10000: 0};
var tests = [[1, false], [0, true], [-2, false], [0x10000, true], [0x20000, false]];
for (var [key, has] of tests) {
assertEq(key in o, has);
assertEq(o.hasOwnProperty(key), has);
}
}
function typedArray() {
var o = {0: 0, 0x10000: 0};
var t = new Int32Array(0x10001)
// Only use Int32Array after we attached the sparse stub
// in o, in t
var tests = [[1, [false, true]],
[0, [true, true]],
[-2, [false, false]],
[0x10000, [true, true]],
[0x20000, [false, false]]];
for (var i = 0; i < 10; i++) {
for (var [key, has] of tests) {
assertEq(key in o, has[i > 5 ? 1 : 0]);
assertEq(o.hasOwnProperty(key), has[i > 5 ? 1 : 0]);
}
if (i == 5)
o = t;
}
}
function protoChange() {
var o = {0: 0, 0x10000: 0};
var tests = [[1, [false, true]],
[0, [true, true]],
[-2, [false, false]],
[0x10000, [true, true]],
[0x20000, [false, false]]];
for (var i = 0; i < 10; i++) {
for (var [key, has] of tests) {
assertEq(key in o, has[i > 5 ? 1 : 0]);
// Proto change doesn't affect hasOwnProperty.
assertEq(o.hasOwnProperty(key), has[0]);
}
if (i == 5)
o.__proto__ = [1, 1, 1, 1];
}
}
sparse();
typedArray();
protoChange();

Просмотреть файл

@ -1730,7 +1730,7 @@ GetPropIRGenerator::tryAttachDenseElement(HandleObject obj, ObjOperandId objId,
}
static bool
CanAttachDenseElementHole(JSObject* obj, bool ownProp)
CanAttachDenseElementHole(NativeObject* obj, bool ownProp, bool allowIndexedReceiver = false)
{
// Make sure the objects on the prototype don't have any indexed properties
// or that such properties can't appear without a shape change.
@ -1738,8 +1738,9 @@ CanAttachDenseElementHole(JSObject* obj, bool ownProp)
// because we would have to lookup a property on the prototype instead.
do {
// The first two checks are also relevant to the receiver object.
if (obj->isNative() && obj->as<NativeObject>().isIndexed())
if (!allowIndexedReceiver && obj->isIndexed())
return false;
allowIndexedReceiver = false;
if (ClassCanHaveExtraProperties(obj->getClass()))
return false;
@ -1759,7 +1760,7 @@ CanAttachDenseElementHole(JSObject* obj, bool ownProp)
if (proto->as<NativeObject>().getDenseInitializedLength() != 0)
return false;
obj = proto;
obj = &proto->as<NativeObject>();
} while (true);
return true;
@ -1775,7 +1776,7 @@ GetPropIRGenerator::tryAttachDenseElementHole(HandleObject obj, ObjOperandId obj
if (obj->as<NativeObject>().containsDenseElement(index))
return false;
if (!CanAttachDenseElementHole(obj, false))
if (!CanAttachDenseElementHole(&obj->as<NativeObject>(), false))
return false;
// Guard on the shape, to prevent non-dense elements from appearing.
@ -2430,7 +2431,7 @@ HasPropIRGenerator::tryAttachDenseHole(HandleObject obj, ObjOperandId objId,
return false;
if (obj->as<NativeObject>().containsDenseElement(index))
return false;
if (!CanAttachDenseElementHole(obj, hasOwn))
if (!CanAttachDenseElementHole(&obj->as<NativeObject>(), hasOwn))
return false;
// Guard shape to ensure class is NativeObject and to prevent non-dense
@ -2450,6 +2451,46 @@ HasPropIRGenerator::tryAttachDenseHole(HandleObject obj, ObjOperandId objId,
return true;
}
bool
HasPropIRGenerator::tryAttachSparse(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId)
{
bool hasOwn = (cacheKind_ == CacheKind::HasOwn);
if (!obj->isNative())
return false;
if (!obj->as<NativeObject>().isIndexed())
return false;
if (!CanAttachDenseElementHole(&obj->as<NativeObject>(), hasOwn,
/* allowIndexedReceiver = */ true))
{
return false;
}
// Guard that this is a native object.
writer.guardIsNativeObject(objId);
// Generate prototype guards if needed. This includes monitoring that
// properties were not added in the chain.
if (!hasOwn) {
if (!obj->hasUncacheableProto()) {
// Make sure the proto does not change without checking the shape.
writer.guardProto(objId, obj->staticPrototype());
}
GeneratePrototypeHoleGuards(writer, obj, objId);
}
// Because of the prototype guard we know that the prototype chain
// does not include any dense or sparse (i.e indexed) properties.
writer.callObjectHasSparseElementResult(objId, indexId);
writer.returnFromIC();
trackAttached("Sparse");
return true;
}
bool
HasPropIRGenerator::tryAttachNamedProp(HandleObject obj, ObjOperandId objId,
HandleId key, ValOperandId keyId)
@ -2718,6 +2759,8 @@ HasPropIRGenerator::tryAttachStub()
return true;
if (tryAttachTypedArray(obj, objId, index, indexId))
return true;
if (tryAttachSparse(obj, objId, index, indexId))
return true;
trackNotAttached();
return false;

Просмотреть файл

@ -175,6 +175,7 @@ extern const char* CacheKindNames[];
_(GuardAnyClass) /* Guard an arbitrary class for an object */ \
_(GuardCompartment) \
_(GuardIsNativeFunction) \
_(GuardIsNativeObject) \
_(GuardIsProxy) \
_(GuardHasProxyHandler) \
_(GuardNotDOMProxy) \
@ -259,6 +260,7 @@ extern const char* CacheKindNames[];
_(CallProxyGetResult) \
_(CallProxyGetByValueResult) \
_(CallProxyHasPropResult) \
_(CallObjectHasSparseElementResult) \
_(LoadUndefinedResult) \
_(LoadBooleanResult) \
_(LoadStringResult) \
@ -556,6 +558,9 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
writeOpWithOperandId(CacheOp::GuardIsNativeFunction, obj);
writePointer(JS_FUNC_TO_DATA_PTR(void*, nativeFunc));
}
void guardIsNativeObject(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardIsNativeObject, obj);
}
void guardIsProxy(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardIsProxy, obj);
}
@ -975,6 +980,10 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
writeOperandId(idVal);
buffer_.writeByte(uint32_t(hasOwn));
}
void callObjectHasSparseElementResult(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::CallObjectHasSparseElementResult, obj);
writeOperandId(index);
}
void loadEnvironmentFixedSlotResult(ObjOperandId obj, size_t offset) {
writeOpWithOperandId(CacheOp::LoadEnvironmentFixedSlotResult, obj);
addStubField(offset, StubField::Type::RawWord);
@ -1447,6 +1456,8 @@ class MOZ_RAII HasPropIRGenerator : public IRGenerator
uint32_t index, Int32OperandId indexId);
bool tryAttachTypedArray(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
bool tryAttachSparse(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
bool tryAttachNamedProp(HandleObject obj, ObjOperandId objId,
HandleId key, ValOperandId keyId);
bool tryAttachMegamorphic(ObjOperandId objId, ValOperandId keyId);

Просмотреть файл

@ -1416,6 +1416,22 @@ CacheIRCompiler::emitGuardIsNativeFunction()
return true;
}
bool
CacheIRCompiler::emitGuardIsNativeObject()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
AutoScratchRegister scratch(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
masm.loadObjClass(obj, scratch);
masm.branchTest32(Assembler::NonZero, Address(scratch, Class::offsetOfFlags()),
Imm32(Class::NON_NATIVE), failure->label());
return true;
}
bool
CacheIRCompiler::emitGuardIsProxy()
{
@ -2565,3 +2581,49 @@ CacheIRCompiler::emitMegamorphicHasPropResult()
masm.adjustStack(sizeof(Value));
return true;
}
bool
CacheIRCompiler::emitCallObjectHasSparseElementResult()
{
AutoOutputRegister output(*this);
Register obj = allocator.useRegister(masm, reader.objOperandId());
Register index = allocator.useRegister(masm, reader.int32OperandId());
AutoScratchRegisterMaybeOutput scratch1(allocator, masm, output);
AutoScratchRegister scratch2(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
masm.reserveStack(sizeof(Value));
masm.moveStackPtrTo(scratch2.get());
LiveRegisterSet volatileRegs(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
volatileRegs.takeUnchecked(scratch1);
volatileRegs.takeUnchecked(index);
masm.PushRegsInMask(volatileRegs);
masm.setupUnalignedABICall(scratch1);
masm.loadJSContext(scratch1);
masm.passABIArg(scratch1);
masm.passABIArg(obj);
masm.passABIArg(index);
masm.passABIArg(scratch2);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, HasNativeElement));
masm.mov(ReturnReg, scratch1);
masm.PopRegsInMask(volatileRegs);
Label ok;
uint32_t framePushed = masm.framePushed();
masm.branchIfTrueBool(scratch1, &ok);
masm.adjustStack(sizeof(Value));
masm.jump(failure->label());
masm.bind(&ok);
masm.setFramePushed(framePushed);
masm.loadTypedOrValue(Address(masm.getStackPointer(), 0), output);
masm.adjustStack(sizeof(Value));
return true;
}

Просмотреть файл

@ -23,6 +23,7 @@ namespace jit {
_(GuardType) \
_(GuardClass) \
_(GuardIsNativeFunction) \
_(GuardIsNativeObject) \
_(GuardIsProxy) \
_(GuardNotDOMProxy) \
_(GuardSpecificInt32Immediate) \
@ -62,6 +63,7 @@ namespace jit {
_(Breakpoint) \
_(MegamorphicLoadSlotByValueResult) \
_(MegamorphicHasPropResult) \
_(CallObjectHasSparseElementResult) \
_(WrapResult)
// Represents a Value on the Baseline frame's expression stack. Slot 0 is the

Просмотреть файл

@ -1234,7 +1234,6 @@ IonCacheIRCompiler::emitCallProxyHasPropResult()
return true;
}
bool
IonCacheIRCompiler::emitLoadUnboxedPropertyResult()
{

Просмотреть файл

@ -1842,6 +1842,45 @@ HasNativeDataProperty<true>(JSContext* cx, JSObject* obj, Value* vp);
template bool
HasNativeDataProperty<false>(JSContext* cx, JSObject* obj, Value* vp);
bool
HasNativeElement(JSContext* cx, NativeObject* obj, int32_t index, Value* vp)
{
AutoUnsafeCallWithABI unsafe;
MOZ_ASSERT(obj->getClass()->isNative());
MOZ_ASSERT(!obj->getOpsHasProperty());
MOZ_ASSERT(!obj->getOpsLookupProperty());
MOZ_ASSERT(!obj->getOpsGetOwnPropertyDescriptor());
if (MOZ_UNLIKELY(index < 0))
return false;
if (obj->containsDenseElement(index)) {
vp[0].setBoolean(true);
return true;
}
jsid id = INT_TO_JSID(index);
if (obj->lastProperty()->search(cx, id)) {
vp[0].setBoolean(true);
return true;
}
// Fail if there's a resolve hook, unless the mayResolve hook tells
// us the resolve hook won't define a property with this id.
if (MOZ_UNLIKELY(ClassMayResolveId(cx->names(), obj->getClass(), id, obj)))
return false;
// TypedArrayObject are also native and contain indexed properties.
if (MOZ_UNLIKELY(obj->is<TypedArrayObject>())) {
vp[0].setBoolean(uint32_t(index) < obj->as<TypedArrayObject>().length());
return true;
}
vp[0].setBoolean(false);
return true;
}
JSString*
TypeOfObject(JSObject* obj, JSRuntime* rt)
{

Просмотреть файл

@ -925,6 +925,9 @@ template <bool HasOwn>
bool
HasNativeDataProperty(JSContext* cx, JSObject* obj, Value* vp);
bool
HasNativeElement(JSContext* cx, NativeObject* obj, int32_t index, Value* vp);
template <bool NeedsTypeBarrier>
bool
SetNativeDataProperty(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);

Просмотреть файл

@ -356,21 +356,6 @@ XCFLAGS="$X_CFLAGS"
fi # COMPILE_ENVIRONMENT
dnl ==============================================================
dnl Get mozilla version from central milestone file
dnl ==============================================================
MOZILLA_VERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir`
MOZILLA_UAVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --uaversion`
MOZILLA_SYMBOLVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --symbolversion`
if test -z "$MOZILLA_VERSION"; then
AC_MSG_ERROR([failed to read version info from milestone file])
fi
AC_DEFINE_UNQUOTED(MOZILLA_VERSION,"$MOZILLA_VERSION")
AC_DEFINE_UNQUOTED(MOZILLA_VERSION_U,$MOZILLA_VERSION)
AC_DEFINE_UNQUOTED(MOZILLA_UAVERSION,"$MOZILLA_UAVERSION")
AC_SUBST(MOZILLA_SYMBOLVERSION)
# Separate version into components for use in shared object naming etc
changequote(,)
MOZJS_MAJOR_VERSION=`echo $MOZILLA_VERSION | sed "s|\(^[0-9]*\)\.[0-9]*.*|\1|"`
@ -412,7 +397,6 @@ AS_BIN=$AS
AR_EXTRACT='$(AR) x'
AS='$(CC)'
AS_DASH_C_FLAG='-c'
DIRENT_INO=d_ino
MOZ_USER_DIR=".mozilla"
MOZ_FIX_LINK_PATHS="-Wl,-rpath-link,${DIST}/bin -Wl,-rpath-link,${prefix}/lib"
@ -883,10 +867,6 @@ if test -z "$MOZ_OPTIMIZE_FLAGS"; then
MOZ_OPTIMIZE_FLAGS="-O"
fi
dnl Only one oddball right now (QNX), but this gives us flexibility
dnl if any other platforms need to override this in the future.
AC_DEFINE_UNQUOTED(D_INO,$DIRENT_INO)
if test -z "$COMPILE_ENVIRONMENT"; then
SKIP_COMPILER_CHECKS=1
SKIP_LIBRARY_CHECKS=1
@ -1931,8 +1911,6 @@ MOZ_CHECK_ALLOCATOR
AC_CHECK_FUNCS(setlocale localeconv)
AC_SUBST(MOZILLA_VERSION)
AC_SUBST(ac_configure_args)
if test -n "$JS_STANDALONE"; then

Просмотреть файл

@ -125,17 +125,18 @@ ObjectElements::FreezeElements(JSContext* cx, HandleNativeObject obj)
}
#ifdef DEBUG
static mozilla::Atomic<bool, mozilla::Relaxed> gShapeConsistencyChecksEnabled(false);
/* static */ void
js::NativeObject::enableShapeConsistencyChecks()
{
gShapeConsistencyChecksEnabled = true;
}
void
js::NativeObject::checkShapeConsistency()
{
static int throttle = -1;
if (throttle < 0) {
if (const char* var = getenv("JS_CHECK_SHAPE_THROTTLE"))
throttle = atoi(var);
if (throttle < 0)
throttle = 0;
}
if (throttle == 0)
if (!gShapeConsistencyChecksEnabled)
return;
MOZ_ASSERT(isNative());
@ -153,18 +154,20 @@ js::NativeObject::checkShapeConsistency()
MOZ_ASSERT(fslot < slotSpan());
}
for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) {
while (shape->parent) {
MOZ_ASSERT_IF(lastProperty() != shape, !shape->hasTable());
ShapeTable::Entry& entry = table->search<MaybeAdding::NotAdding>(shape->propid(),
nogc);
MOZ_ASSERT(entry.shape() == shape);
shape = shape->parent;
}
}
shape = lastProperty();
for (int n = throttle; --n >= 0 && shape; shape = shape->parent) {
MOZ_ASSERT_IF(shape->slot() != SHAPE_INVALID_SLOT, shape->slot() < slotSpan());
while (shape) {
MOZ_ASSERT_IF(!shape->isEmptyShape() && shape->isDataProperty(),
shape->slot() < slotSpan());
if (!prev) {
MOZ_ASSERT(lastProperty() == shape);
MOZ_ASSERT(shape->listp == &shape_);
@ -172,9 +175,10 @@ js::NativeObject::checkShapeConsistency()
MOZ_ASSERT(shape->listp == &prev->parent);
}
prev = shape;
shape = shape->parent;
}
} else {
for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) {
while (shape->parent) {
if (ShapeTable* table = shape->maybeTable(nogc)) {
MOZ_ASSERT(shape->parent);
for (Shape::Range<NoGC> r(shape); !r.empty(); r.popFront()) {
@ -184,10 +188,11 @@ js::NativeObject::checkShapeConsistency()
}
}
if (prev) {
MOZ_ASSERT(prev->maybeSlot() >= shape->maybeSlot());
MOZ_ASSERT_IF(shape->isDataProperty(), prev->maybeSlot() >= shape->maybeSlot());
shape->kids.checkConsistency(prev);
}
prev = shape;
shape = shape->parent;
}
}
}

Просмотреть файл

@ -550,6 +550,10 @@ class NativeObject : public ShapedObject
static inline JS::Result<NativeObject*, JS::OOM&>
createWithTemplate(JSContext* cx, js::gc::InitialHeap heap, HandleObject templateObject);
#ifdef DEBUG
static void enableShapeConsistencyChecks();
#endif
protected:
#ifdef DEBUG
friend class js::AutoCheckShapeConsistency;

Просмотреть файл

@ -5,13 +5,22 @@
<body>
<!-- U+2024 is ONE DOT LEADER -->
<p>abcdef&#x2024;&#x2024;&#x2024;abcdef</p>
<p>abcdef&#x2024;&#x2024;&#x2024;<br>abcdef</p>
<p>abcdef&#x2024;<br>abcdef</p>
<p>abcdef&#x2024; <br>abcdef</p>
<p>abcdef <br>&#x2024;abcdef</p>
<!-- U+2025 is TWO DOT LEADER -->
<p>abcdef&#x2025;&#x2025;&#x2025;abcdef</p>
<p>abcdef&#x2025;&#x2025;&#x2025;<br>abcdef</p>
<p>abcdef&#x2025;<br>abcdef</p>
<p>abcdef&#x2025; <br>abcdef</p>
<p>abcdef <br>&#x2025;abcdef</p>
<!-- U+2026 is HORIZONTAL ELLIPSIS -->
<p>abcdef&#x2026;&#x2026;&#x2026;abcdef</p>
<p>abcdef&#x2026;&#x2026;&#x2026;<br>abcdef</p>
<p>abcdef&#x2026;<br>abcdef</p>
<p>abcdef&#x2026; <br>abcdef</p>
<p>abcdef <br>&#x2026;abcdef</p>
</body>
</html>

Просмотреть файл

@ -6,12 +6,21 @@
<!-- U+2024 is ONE DOT LEADER -->
<p>abcdef&#x2024;&#x2024;&#x2024;abcdef</p>
<p>abcdef&#x2024;abcdef</p>
<p>abcdef&#x2024; abcdef</p>
<p>abcdef &#x2024;abcdef</p> <!-- no break after the leader in this case -->
<!-- U+2025 is TWO DOT LEADER -->
<p>abcdef&#x2025;&#x2025;&#x2025;abcdef</p>
<p>abcdef&#x2025;abcdef</p>
<p>abcdef&#x2025; abcdef</p>
<p>abcdef &#x2025;abcdef</p> <!-- no break after the leader in this case -->
<!-- U+2026 is HORIZONTAL ELLIPSIS -->
<p>abcdef&#x2026;&#x2026;&#x2026;abcdef</p>
<p>abcdef&#x2026;abcdef</p>
<p>abcdef&#x2026; abcdef</p>
<p>abcdef &#x2026;abcdef</p> <!-- no break after the ellipsis in this case -->
</body>
</html>

Просмотреть файл

@ -851,7 +851,6 @@ pref("browser.tabs.showAudioPlayingIcon", true);
pref("dom.serviceWorkers.enabled", true);
pref("dom.serviceWorkers.interception.enabled", true);
pref("dom.serviceWorkers.openWindow.enabled", true);
// Allow service workers to open windows for a longer period after a notification
// click on mobile. This is to account for some devices being quite slow.

Просмотреть файл

@ -293,6 +293,7 @@ NS_INTERFACE_MAP_BEGIN(nsBufferedInputStream)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream, IsIPCSerializable())
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream, IsAsyncInputStream())
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamCallback, IsAsyncInputStream())
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream, IsCloneableInputStream())
NS_IMPL_QUERY_CLASSINFO(nsBufferedInputStream)
NS_INTERFACE_MAP_END_INHERITING(nsBufferedStream)
@ -641,6 +642,13 @@ nsBufferedInputStream::IsAsyncInputStream() const
return !!stream;
}
bool
nsBufferedInputStream::IsCloneableInputStream() const
{
nsCOMPtr<nsICloneableInputStream> stream = do_QueryInterface(mStream);
return !!stream;
}
NS_IMETHODIMP
nsBufferedInputStream::CloseWithStatus(nsresult aStatus)
{
@ -695,6 +703,50 @@ nsBufferedInputStream::GetData(nsIInputStream **aResult)
return NS_OK;
}
// nsICloneableInputStream interface
NS_IMETHODIMP
nsBufferedInputStream::GetCloneable(bool* aCloneable)
{
*aCloneable = false;
// If we don't have the buffer, the inputStream has been already closed.
// If mBufferStartOffset is not 0, the stream has been seeked or read.
// In both case the cloning is not supported.
if (!mBuffer || mBufferStartOffset) {
return NS_OK;
}
nsCOMPtr<nsICloneableInputStream> stream = do_QueryInterface(mStream);
// GetCloneable is infallible.
NS_ENSURE_TRUE(stream, NS_OK);
return stream->GetCloneable(aCloneable);
}
NS_IMETHODIMP
nsBufferedInputStream::Clone(nsIInputStream** aResult)
{
if (!mBuffer || mBufferStartOffset) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsICloneableInputStream> stream = do_QueryInterface(mStream);
NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE);
nsCOMPtr<nsIInputStream> clonedStream;
nsresult rv = stream->Clone(getter_AddRefs(clonedStream));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIBufferedInputStream> bis = new nsBufferedInputStream();
rv = bis->Init(clonedStream, mBufferSize);
NS_ENSURE_SUCCESS(rv, rv);
bis.forget(aResult);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsBufferedOutputStream

Просмотреть файл

@ -15,6 +15,7 @@
#include "nsCOMPtr.h"
#include "nsIIPCSerializableInputStream.h"
#include "nsIAsyncInputStream.h"
#include "nsICloneableInputStream.h"
////////////////////////////////////////////////////////////////////////////////
@ -65,7 +66,8 @@ class nsBufferedInputStream : public nsBufferedStream,
public nsIStreamBufferAccess,
public nsIIPCSerializableInputStream,
public nsIAsyncInputStream,
public nsIInputStreamCallback
public nsIInputStreamCallback,
public nsICloneableInputStream
{
public:
NS_DECL_ISUPPORTS_INHERITED
@ -75,6 +77,7 @@ public:
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
NS_DECL_NSIASYNCINPUTSTREAM
NS_DECL_NSIINPUTSTREAMCALLBACK
NS_DECL_NSICLONEABLEINPUTSTREAM
nsBufferedInputStream() : nsBufferedStream() {}
@ -90,6 +93,7 @@ protected:
bool IsIPCSerializable() const;
bool IsAsyncInputStream() const;
bool IsCloneableInputStream() const;
NS_IMETHOD Fill() override;
NS_IMETHOD Flush() override { return NS_OK; } // no-op for input streams

Просмотреть файл

@ -61,7 +61,9 @@ interface nsIUploadChannel2 : nsISupports
* Clones the upload stream. May return failure if the upload stream
* is not cloneable. If this is not acceptable, use the
* ensureUploadStreamIsCloneable() method first.
* aContentLength could be -1 in case the size of the stream is unknown,
* otherwise it will contain the known size of the stream.
*/
[noscript]
nsIInputStream cloneUploadStream();
nsIInputStream cloneUploadStream(out long long aContentLength);
};

Просмотреть файл

@ -995,8 +995,10 @@ HttpBaseChannel::EnsureUploadStreamIsCloneableComplete(nsresult aStatus)
}
NS_IMETHODIMP
HttpBaseChannel::CloneUploadStream(nsIInputStream** aClonedStream)
HttpBaseChannel::CloneUploadStream(int64_t* aContentLength,
nsIInputStream** aClonedStream)
{
NS_ENSURE_ARG_POINTER(aContentLength);
NS_ENSURE_ARG_POINTER(aClonedStream);
*aClonedStream = nullptr;
@ -1010,6 +1012,12 @@ HttpBaseChannel::CloneUploadStream(nsIInputStream** aClonedStream)
clonedStream.forget(aClonedStream);
if (mReqContentLengthDetermined) {
*aContentLength = mReqContentLength;
} else {
*aContentLength = -1;
}
return NS_OK;
}

Просмотреть файл

@ -457,7 +457,6 @@ AS_BIN=$AS
AR_EXTRACT='$(AR) x'
AS='$(CC)'
AS_DASH_C_FLAG='-c'
DIRENT_INO=d_ino
MOZ_USER_DIR=".mozilla"
MOZ_FIX_LINK_PATHS="-Wl,-rpath-link,${DIST}/bin -Wl,-rpath-link,${prefix}/lib"
@ -749,16 +748,6 @@ case "$host" in
;;
esac
dnl ==============================================================
dnl Get mozilla version from central milestone file
dnl ==============================================================
MOZILLA_VERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir`
MOZILLA_UAVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --uaversion`
MOZILLA_SYMBOLVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --symbolversion`
if test -z "$MOZILLA_VERSION"; then
AC_MSG_ERROR([failed to read version info from milestone file])
fi
dnl Get version of various core apps from the version files.
FIREFOX_VERSION=`cat $_topsrcdir/browser/config/version.txt`
FIREFOX_VERSION_DISPLAY=`cat $_topsrcdir/browser/config/version_display.txt`
@ -771,11 +760,6 @@ if test -z "$FIREFOX_VERSION_DISPLAY"; then
AC_MSG_ERROR([FIREFOX_VERSION_DISPLAY is unexpectedly blank.])
fi
AC_DEFINE_UNQUOTED(MOZILLA_VERSION,"$MOZILLA_VERSION")
AC_DEFINE_UNQUOTED(MOZILLA_VERSION_U,$MOZILLA_VERSION)
AC_DEFINE_UNQUOTED(MOZILLA_UAVERSION,"$MOZILLA_UAVERSION")
AC_SUBST(MOZILLA_SYMBOLVERSION)
MOZ_DOING_LTO(lto_is_enabled)
dnl ========================================================
@ -1151,10 +1135,6 @@ if test -n "$MOZ_LINKER"; then
AC_CHECK_PROGS(XZ, xz)
fi
dnl Only one oddball right now (QNX), but this gives us flexibility
dnl if any other platforms need to override this in the future.
AC_DEFINE_UNQUOTED(D_INO,$DIRENT_INO)
if test -z "$COMPILE_ENVIRONMENT"; then
SKIP_COMPILER_CHECKS=1
SKIP_LIBRARY_CHECKS=1
@ -4848,8 +4828,6 @@ if test -n "$A11Y_LOG"; then
AC_DEFINE(A11Y_LOG)
fi
AC_SUBST(MOZILLA_VERSION)
dnl Spit out some output
dnl ========================================================

Просмотреть файл

@ -1,75 +0,0 @@
# 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/.
from __future__ import absolute_import, print_function, unicode_literals
import argparse
import os
import re
import sys
def get_milestone_ab_with_num(milestone):
"""
Returns the alpha and beta tag with its number (a1, a2, b3, ...).
"""
match = re.search(r"([ab]\d+)", milestone)
if match:
return match.group(1)
return ""
def get_official_milestone(path):
"""
Returns the contents of the first line in `path` that starts with a digit.
"""
with open(path) as fp:
for line in fp:
line = line.strip()
if line[:1].isdigit():
return line
raise Exception("Didn't find a line that starts with a digit.")
def get_milestone_major(milestone):
"""
Returns the major (first) part of the milestone.
"""
return milestone.split('.')[0]
def main(args):
parser = argparse.ArgumentParser()
parser.add_argument('--uaversion', default=False, action='store_true')
parser.add_argument('--symbolversion', default=False, action='store_true')
parser.add_argument('--topsrcdir', metavar='TOPSRCDIR', required=True)
options = parser.parse_args(args)
milestone_file = os.path.join(options.topsrcdir, 'config', 'milestone.txt')
milestone = get_official_milestone(milestone_file)
if options.uaversion:
# Only expose the major milestone in the UA string, hide the patch
# level (bugs 572659 and 870868).
uaversion = "%s.0" % (get_milestone_major(milestone),)
print(uaversion)
elif options.symbolversion:
# Only expose major milestone and alpha version. Used for symbol
# versioning on Linux.
symbolversion = "%s%s" % (get_milestone_major(milestone),
get_milestone_ab_with_num(milestone))
print(symbolversion)
else:
print(milestone)
if __name__ == '__main__':
main(sys.argv[1:])

Просмотреть файл

@ -1,10 +0,0 @@
[about-blank-replacement.https.html]
[Initial about:blank is controlled, exposed to clients.matchAll(), and matches final Client.]
expected: FAIL
[Initial about:blank modified by parent is controlled, exposed to clients.matchAll(), and matches final Client.]
expected: FAIL
[Popup initial about:blank is controlled, exposed to clients.matchAll(), and matches final Client.]
expected: FAIL

Просмотреть файл

@ -1,8 +0,0 @@
[clients-matchall-client-types.https.html]
type: testharness
[Verify matchAll() with window and sharedworker client types]
expected: FAIL
[Verify matchAll() with {window, sharedworker, worker} client types]
expected: FAIL

Просмотреть файл

@ -40,6 +40,54 @@ TEST(CloneInputStream, CloneableInput)
testing::ConsumeAndValidateStream(clone, inputString);
}
class NonCloneableInputStream final : public nsIInputStream
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
explicit NonCloneableInputStream(already_AddRefed<nsIInputStream> aInputStream)
: mStream(aInputStream)
{}
NS_IMETHOD
Available(uint64_t* aLength) override
{
return mStream->Available(aLength);
}
NS_IMETHOD
Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) override
{
return mStream->Read(aBuffer, aCount, aReadCount);
}
NS_IMETHOD
ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
uint32_t aCount, uint32_t *aResult) override
{
return mStream->ReadSegments(aWriter, aClosure, aCount, aResult);
}
NS_IMETHOD
Close() override
{
return mStream->Close();
}
NS_IMETHOD
IsNonBlocking(bool* aNonBlocking) override
{
return mStream->IsNonBlocking(aNonBlocking);
}
private:
~NonCloneableInputStream() = default;
nsCOMPtr<nsIInputStream> mStream;
};
NS_IMPL_ISUPPORTS(NonCloneableInputStream, nsIInputStream)
TEST(CloneInputStream, NonCloneableInput_NoFallback)
{
nsTArray<char> inputData;
@ -50,12 +98,7 @@ TEST(CloneInputStream, NonCloneableInput_NoFallback)
nsresult rv = NS_NewCStringInputStream(getter_AddRefs(base), inputString);
ASSERT_TRUE(NS_SUCCEEDED(rv));
// Take advantage of nsBufferedInputStream being non-cloneable right
// now. If this changes in the future, then we need a different stream
// type in this test.
nsCOMPtr<nsIInputStream> stream;
rv = NS_NewBufferedInputStream(getter_AddRefs(stream), base.forget(), 4096);
ASSERT_TRUE(NS_SUCCEEDED(rv));
nsCOMPtr<nsIInputStream> stream = new NonCloneableInputStream(base.forget());
nsCOMPtr<nsICloneableInputStream> cloneable = do_QueryInterface(stream);
ASSERT_TRUE(cloneable == nullptr);
@ -78,12 +121,7 @@ TEST(CloneInputStream, NonCloneableInput_Fallback)
nsresult rv = NS_NewCStringInputStream(getter_AddRefs(base), inputString);
ASSERT_TRUE(NS_SUCCEEDED(rv));
// Take advantage of nsBufferedInputStream being non-cloneable right
// now. If this changes in the future, then we need a different stream
// type in this test.
nsCOMPtr<nsIInputStream> stream;
rv = NS_NewBufferedInputStream(getter_AddRefs(stream), base.forget(), 4096);
ASSERT_TRUE(NS_SUCCEEDED(rv));
nsCOMPtr<nsIInputStream> stream = new NonCloneableInputStream(base.forget());
nsCOMPtr<nsICloneableInputStream> cloneable = do_QueryInterface(stream);
ASSERT_TRUE(cloneable == nullptr);