Bug 1229056 - Implement ClientQueryOptions.includeUncontrolled; r=jdm

This commit is contained in:
Ehsan Akhgari 2015-11-30 14:29:51 -05:00
parent 5ac100af7e
commit 6c4573cf9e
6 changed files with 87 additions and 30 deletions

View File

@ -181,11 +181,14 @@ class MatchAllRunnable final : public nsRunnable
RefPtr<PromiseWorkerProxy> mPromiseProxy;
nsCString mScope;
bool mIncludeUncontrolled;
public:
MatchAllRunnable(PromiseWorkerProxy* aPromiseProxy,
const nsCString& aScope)
const nsCString& aScope,
bool aIncludeUncontrolled)
: mPromiseProxy(aPromiseProxy),
mScope(aScope)
mScope(aScope),
mIncludeUncontrolled(aIncludeUncontrolled)
{
MOZ_ASSERT(mPromiseProxy);
}
@ -203,7 +206,8 @@ public:
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
nsTArray<ServiceWorkerClientInfo> result;
swm->GetAllClients(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(), mScope, result);
swm->GetAllClients(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(), mScope,
mIncludeUncontrolled, result);
RefPtr<ResolvePromiseWorkerRunnable> r =
new ResolvePromiseWorkerRunnable(mPromiseProxy->GetWorkerPrivate(),
mPromiseProxy, result);
@ -689,7 +693,7 @@ ServiceWorkerClients::MatchAll(const ClientQueryOptions& aOptions,
nsString scope;
mWorkerScope->GetScope(scope);
if (aOptions.mIncludeUncontrolled || aOptions.mType != ClientType::Window) {
if (aOptions.mType != ClientType::Window) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
@ -708,7 +712,8 @@ ServiceWorkerClients::MatchAll(const ClientQueryOptions& aOptions,
RefPtr<MatchAllRunnable> r =
new MatchAllRunnable(promiseProxy,
NS_ConvertUTF16toUTF8(scope));
NS_ConvertUTF16toUTF8(scope),
aOptions.mIncludeUncontrolled);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
return promise.forget();
}

View File

@ -20,6 +20,7 @@
#include "nsINetworkInterceptController.h"
#include "nsIMutableArray.h"
#include "nsIScriptError.h"
#include "nsISimpleEnumerator.h"
#include "nsIUploadChannel2.h"
#include "nsPIDOMWindow.h"
#include "nsScriptLoader.h"
@ -3760,7 +3761,8 @@ ServiceWorkerManager::GetClient(nsIPrincipal* aPrincipal,
void
ServiceWorkerManager::GetAllClients(nsIPrincipal* aPrincipal,
const nsCString& aScope,
nsTArray<ServiceWorkerClientInfo>& aControlledDocuments)
bool aIncludeUncontrolled,
nsTArray<ServiceWorkerClientInfo>& aDocuments)
{
MOZ_ASSERT(aPrincipal);
@ -3772,21 +3774,65 @@ ServiceWorkerManager::GetAllClients(nsIPrincipal* aPrincipal,
return;
}
for (auto iter = mControlledDocuments.Iter(); !iter.Done(); iter.Next()) {
ServiceWorkerRegistrationInfo* thisRegistration = iter.UserData();
MOZ_ASSERT(thisRegistration);
if (!registration->mScope.Equals(thisRegistration->mScope)) {
continue;
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;
}
auto ProcessDocument = [&aDocuments](nsIPrincipal* aPrincipal, nsIDocument* aDoc) {
if (!aDoc || !aDoc->GetWindow()) {
return;
}
nsCOMPtr<nsIDocument> document = do_QueryInterface(iter.Key());
if (!document || !document->GetWindow()) {
continue;
bool equals = false;
aPrincipal->Equals(aDoc->NodePrincipal(), &equals);
if (!equals) {
return;
}
ServiceWorkerClientInfo clientInfo(document);
aControlledDocuments.AppendElement(clientInfo);
if (!Preferences::GetBool("dom.serviceWorkers.testing.enabled") &&
!IsFromAuthenticatedOrigin(aDoc)) {
return;
}
ServiceWorkerClientInfo clientInfo(aDoc);
aDocuments.AppendElement(aDoc);
};
// Since it's not simple to check whether a document is in
// mControlledDocuments, we take different code paths depending on whether we
// need to look at all documents. The common parts of the two loops are
// factored out into the ProcessDocument lambda.
if (aIncludeUncontrolled) {
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);
ProcessDocument(aPrincipal, doc);
}
} else {
for (auto iter = mControlledDocuments.Iter(); !iter.Done(); iter.Next()) {
ServiceWorkerRegistrationInfo* thisRegistration = iter.UserData();
MOZ_ASSERT(thisRegistration);
if (!registration->mScope.Equals(thisRegistration->mScope)) {
continue;
}
nsCOMPtr<nsIDocument> doc = do_QueryInterface(iter.Key());
ProcessDocument(aPrincipal, doc);
}
}
}

View File

@ -444,7 +444,8 @@ public:
void
GetAllClients(nsIPrincipal* aPrincipal,
const nsCString& aScope,
nsTArray<ServiceWorkerClientInfo>& aControlledDocuments);
bool aIncludeUncontrolled,
nsTArray<ServiceWorkerClientInfo>& aDocuments);
void
MaybeClaimClient(nsIDocument* aDocument,

View File

@ -1,6 +0,0 @@
[clients-matchall-include-uncontrolled.https.html]
type: testharness
expected: TIMEOUT
[Verify matchAll() respect includeUncontrolled]
expected: TIMEOUT

View File

@ -28,10 +28,10 @@ var expected_without_include_uncontrolled = [
var expected_with_include_uncontrolled = [
/* visibilityState, focused, url, frameType */
['visible', true, location.href, 'top-level'],
['visible', false, new URL(scope + '#1', location).toString(), 'nested'],
['visible', true, new URL(scope + '#2', location).toString(), 'nested'],
['visible', false, new URL(base_url, location).toString(), 'nested'],
['visible', true, location.href, 'top-level']
['visible', false, new URL(base_url, location).toString(), 'nested']
];
function test_matchall(frame, expected, query_options) {
@ -42,9 +42,13 @@ function test_matchall(frame, expected, query_options) {
return new Promise(function(resolve, reject) {
var channel = new MessageChannel();
channel.port1.onmessage = function(e) {
assert_equals(e.data.length, expected.length);
for (var i = 0; i < e.data.length; i++)
assert_array_equals(e.data[i], expected[i]);
// Ignore hidden clients which may be coming from background tabs.
var data = e.data.filter(function(info) {
return info[0] == 'visible';
});
assert_equals(data.length, expected.length);
for (var i = 0; i < data.length; i++)
assert_array_equals(data[i], expected[i]);
resolve(frame);
};
frame.contentWindow.navigator.serviceWorker.controller.postMessage(

View File

@ -5,10 +5,17 @@ self.onmessage = function(e) {
self.clients.matchAll(options).then(function(clients) {
var message = [];
clients.forEach(function(client) {
var frame_type = client.frameType;
if (client.url.indexOf('clients-matchall-include-uncontrolled.https.html') > -1 &&
client.frameType == 'auxiliary') {
// The test tab might be opened using window.open() by the test framework.
// In that case, just pretend it's top-level!
frame_type = 'top-level';
}
message.push([client.visibilityState,
client.focused,
client.url,
client.frameType]);
frame_type]);
});
// Sort by url
message.sort(function(a, b) { return a[2] > b[2] ? 1 : -1; });