Commit 350845d8 authored by Istiaque Ahmed's avatar Istiaque Ahmed Committed by Commit Bot

Extension SW: Add filtered event listener support.

The primary change is to send worker information to
EventRouter::Add/RemoveFilteredEventListener. EventRouter creates
worker specific event listeners when worker information is present
(identified by a base::Optional param).

The other changes are:
 - Added the ability to call MakeLazy() on service worker specific
event listeners.
 - Since routing id matching is not done deliberately on service
worker filtered events, added routing id retrieving function
GetRoutingIDForFilteredEvents() to ScriptContext.

An end-to-end browsertest with webNavigation API to exercise event
filters was also added.

IPC changes:
This CL adds an optional param to Add/RemoveFilteredListener. The
presence of this param denotes that the listener being added/removed
belongs to an extension service worker. And the value of the param
(ExtensionHostMsg_ServiceWorkerIdentifier) contains the identifying
bits of a service worker. The absence of this param indicates that
the message is for vanilla (non service worker) extension event
listeners.

Bug: 721147
Change-Id: I2ff3c26db54ae1e1fd7d10b8afcb277d382e83c2
Reviewed-on: https://chromium-review.googlesource.com/666222
Commit-Queue: Istiaque Ahmed <lazyboy@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#503298}
parent c050720e
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "extensions/browser/event_router_factory.h" #include "extensions/browser/event_router_factory.h"
#include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry.h"
#include "extensions/common/extension_messages.h"
#include "extensions/common/manifest_constants.h" #include "extensions/common/manifest_constants.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -364,15 +365,15 @@ TEST_F(MDnsAPITest, ExtensionRespectsWhitelist) { ...@@ -364,15 +365,15 @@ TEST_F(MDnsAPITest, ExtensionRespectsWhitelist) {
.Times(0); .Times(0);
EventRouter::Get(browser_context()) EventRouter::Get(browser_context())
->AddFilteredEventListener(api::mdns::OnServiceList::kEventName, ->AddFilteredEventListener(api::mdns::OnServiceList::kEventName,
render_process_host(), kExtId, filter, render_process_host(), kExtId, base::nullopt,
false); filter, false);
EXPECT_CALL(*dns_sd_registry(), UnregisterDnsSdListener("_trex._tcp.local")) EXPECT_CALL(*dns_sd_registry(), UnregisterDnsSdListener("_trex._tcp.local"))
.Times(0); .Times(0);
EventRouter::Get(browser_context()) EventRouter::Get(browser_context())
->RemoveFilteredEventListener(api::mdns::OnServiceList::kEventName, ->RemoveFilteredEventListener(api::mdns::OnServiceList::kEventName,
render_process_host(), kExtId, filter, render_process_host(), kExtId,
false); base::nullopt, filter, false);
} }
{ {
base::DictionaryValue filter; base::DictionaryValue filter;
...@@ -384,15 +385,15 @@ TEST_F(MDnsAPITest, ExtensionRespectsWhitelist) { ...@@ -384,15 +385,15 @@ TEST_F(MDnsAPITest, ExtensionRespectsWhitelist) {
RegisterDnsSdListener("_testing._tcp.local")); RegisterDnsSdListener("_testing._tcp.local"));
EventRouter::Get(browser_context()) EventRouter::Get(browser_context())
->AddFilteredEventListener(api::mdns::OnServiceList::kEventName, ->AddFilteredEventListener(api::mdns::OnServiceList::kEventName,
render_process_host(), kExtId, filter, render_process_host(), kExtId, base::nullopt,
false); filter, false);
EXPECT_CALL(*dns_sd_registry(), EXPECT_CALL(*dns_sd_registry(),
UnregisterDnsSdListener("_testing._tcp.local")); UnregisterDnsSdListener("_testing._tcp.local"));
EventRouter::Get(browser_context()) EventRouter::Get(browser_context())
->RemoveFilteredEventListener(api::mdns::OnServiceList::kEventName, ->RemoveFilteredEventListener(api::mdns::OnServiceList::kEventName,
render_process_host(), kExtId, filter, render_process_host(), kExtId,
false); base::nullopt, filter, false);
} }
} }
...@@ -408,15 +409,17 @@ TEST_F(MDnsAPITest, PlatformAppsNotSubjectToWhitelist) { ...@@ -408,15 +409,17 @@ TEST_F(MDnsAPITest, PlatformAppsNotSubjectToWhitelist) {
ASSERT_TRUE(dns_sd_registry()); ASSERT_TRUE(dns_sd_registry());
// Test that the extension is able to listen to a non-whitelisted service // Test that the extension is able to listen to a non-whitelisted service
EXPECT_CALL(*dns_sd_registry(), RegisterDnsSdListener("_trex._tcp.local")); EXPECT_CALL(*dns_sd_registry(), RegisterDnsSdListener("_trex._tcp.local"));
EventRouter::Get(browser_context()) EventRouter::Get(browser_context())
->AddFilteredEventListener(api::mdns::OnServiceList::kEventName, ->AddFilteredEventListener(api::mdns::OnServiceList::kEventName,
render_process_host(), kExtId, filter, false); render_process_host(), kExtId, base::nullopt,
filter, false);
EXPECT_CALL(*dns_sd_registry(), UnregisterDnsSdListener("_trex._tcp.local")); EXPECT_CALL(*dns_sd_registry(), UnregisterDnsSdListener("_trex._tcp.local"));
EventRouter::Get(browser_context()) EventRouter::Get(browser_context())
->RemoveFilteredEventListener(api::mdns::OnServiceList::kEventName, ->RemoveFilteredEventListener(api::mdns::OnServiceList::kEventName,
render_process_host(), kExtId, filter, render_process_host(), kExtId,
false); base::nullopt, filter, false);
} }
} // namespace extensions } // namespace extensions
...@@ -950,4 +950,10 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerPushMessagingTest, OnPush) { ...@@ -950,4 +950,10 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerPushMessagingTest, OnPush) {
run_loop.Run(); // Wait until the message is handled by push service. run_loop.Run(); // Wait until the message is handled by push service.
} }
IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FilteredEvents) {
// Extensions APIs from SW are only enabled on trunk.
ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
ASSERT_TRUE(RunExtensionTest("service_worker/filtered_events"));
}
} // namespace extensions } // namespace extensions
...@@ -774,7 +774,7 @@ ...@@ -774,7 +774,7 @@
}, },
"webNavigation": { "webNavigation": {
"dependencies": ["permission:webNavigation"], "dependencies": ["permission:webNavigation"],
"contexts": ["blessed_extension"] "contexts": ["blessed_extension", "extension_service_worker"]
}, },
"webrtcAudioPrivate": { "webrtcAudioPrivate": {
"dependencies": ["permission:webrtcAudioPrivate"], "dependencies": ["permission:webrtcAudioPrivate"],
......
<!--
Copyright 2017 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<!DOCTYPE html>
<script src="a.js"></script>
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
onload = function() {
document.location = 'b.html';
}
<!--
Copyright 2017 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<!DOCTYPE html>
<html></html>
{
"name": "Extension service worker - filtered events",
"version": "1.0",
"manifest_version": 2,
"description": "Extension service worker - filtered events test with webNavigation",
"background": {
"scripts": ["test_filtered.js"]
},
"permissions": ["webNavigation", "tabs"]
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
self.onmessage = function(e) {
chrome.test.assertEq('testServiceWorkerFilteredEvents', e.data);
runTest();
};
function runTest() {
var getURL = chrome.extension.getURL;
chrome.tabs.create({url: 'about:blank'}, function(tab) {
var tabId = tab.id;
var aVisited = false;
chrome.webNavigation.onCommitted.addListener(function(details) {
chrome.test.fail();
}, {url: [{pathSuffix: 'never-navigated.html'}]});
chrome.webNavigation.onCommitted.addListener(function(details) {
chrome.test.log('chrome.webNavigation.onCommitted - a.html');
chrome.test.assertEq(getURL('a.html'), details.url);
aVisited = true;
}, {url: [{pathSuffix: 'a.html'}]});
chrome.webNavigation.onCommitted.addListener(function(details) {
chrome.test.log('chrome.webNavigation.onCommitted - b.html');
chrome.test.assertEq(getURL('b.html'), details.url);
chrome.test.assertTrue(aVisited);
chrome.test.succeed();
}, {url: [{pathSuffix: 'b.html'}]});
chrome.tabs.update(tabId, {url: getURL('a.html')});
});
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var workerPromise = new Promise(function(resolve, reject) {
navigator.serviceWorker.register('sw.js').then(function() {
return navigator.serviceWorker.ready;
}).then(function(registration) {
var sw = registration.active;
sw.postMessage('testServiceWorkerFilteredEvents');
}).catch(function(err) {
reject(err);
});
});
function testServiceWorkerFilteredEvents() {
// The worker calls chrome.test.succeed() if the test passes.
workerPromise.catch(function(err) {
chrome.test.fail();
});
};
chrome.test.runTests([testServiceWorkerFilteredEvents]);
...@@ -90,7 +90,11 @@ bool EventListener::IsLazy() const { ...@@ -90,7 +90,11 @@ bool EventListener::IsLazy() const {
} }
void EventListener::MakeLazy() { void EventListener::MakeLazy() {
DCHECK_EQ(worker_thread_id_, kMainThreadId); // A lazy listener neither has a process attached to it nor it has a worker
// thread id (if the listener was for a service worker), so reset these values
// below to reflect that.
if (is_for_service_worker_)
worker_thread_id_ = kMainThreadId;
process_ = nullptr; process_ = nullptr;
} }
......
...@@ -121,7 +121,7 @@ class EventListener { ...@@ -121,7 +121,7 @@ class EventListener {
// is_for_service_worker_ = true) and the worker is in running state, then // is_for_service_worker_ = true) and the worker is in running state, then
// this is the worker's thread id in the worker |process_|. For lazy service // this is the worker's thread id in the worker |process_|. For lazy service
// worker events, this will be kMainThreadId. // worker events, this will be kMainThreadId.
const int worker_thread_id_; int worker_thread_id_;
std::unique_ptr<base::DictionaryValue> filter_; std::unique_ptr<base::DictionaryValue> filter_;
EventFilter::MatcherID matcher_id_; // -1 if unset. EventFilter::MatcherID matcher_id_; // -1 if unset.
......
...@@ -324,36 +324,52 @@ void EventRouter::RemoveLazyServiceWorkerEventListener( ...@@ -324,36 +324,52 @@ void EventRouter::RemoveLazyServiceWorkerEventListener(
RegisteredEventType::kServiceWorker); RegisteredEventType::kServiceWorker);
} }
// TODO(lazyboy): Support filters for extension SW events. void EventRouter::AddFilteredEventListener(
void EventRouter::AddFilteredEventListener(const std::string& event_name, const std::string& event_name,
content::RenderProcessHost* process, content::RenderProcessHost* process,
const std::string& extension_id, const std::string& extension_id,
const base::DictionaryValue& filter, base::Optional<ServiceWorkerIdentifier> sw_identifier,
bool add_lazy_listener) { const base::DictionaryValue& filter,
listeners_.AddListener(EventListener::ForExtension( bool add_lazy_listener) {
event_name, extension_id, process, const bool is_for_service_worker = sw_identifier.has_value();
std::unique_ptr<DictionaryValue>(filter.DeepCopy()))); listeners_.AddListener(
is_for_service_worker
? EventListener::ForExtensionServiceWorker(
event_name, extension_id, process, sw_identifier->scope,
sw_identifier->thread_id, filter.CreateDeepCopy())
: EventListener::ForExtension(event_name, extension_id, process,
filter.CreateDeepCopy()));
if (!add_lazy_listener) if (!add_lazy_listener)
return; return;
bool added = listeners_.AddListener(EventListener::ForExtension( bool added = listeners_.AddListener(
event_name, extension_id, nullptr, is_for_service_worker
std::unique_ptr<DictionaryValue>(filter.DeepCopy()))); ? EventListener::ForExtensionServiceWorker(
event_name, extension_id, nullptr, sw_identifier->scope,
kMainThreadId, // Lazy, without worker thread id.
filter.CreateDeepCopy())
: EventListener::ForExtension(event_name, extension_id, nullptr,
filter.CreateDeepCopy()));
if (added) if (added)
AddFilterToEvent(event_name, extension_id, &filter); AddFilterToEvent(event_name, extension_id, &filter);
} }
// TODO(lazyboy): Support filters for extension SW events.
void EventRouter::RemoveFilteredEventListener( void EventRouter::RemoveFilteredEventListener(
const std::string& event_name, const std::string& event_name,
content::RenderProcessHost* process, content::RenderProcessHost* process,
const std::string& extension_id, const std::string& extension_id,
base::Optional<ServiceWorkerIdentifier> sw_identifier,
const base::DictionaryValue& filter, const base::DictionaryValue& filter,
bool remove_lazy_listener) { bool remove_lazy_listener) {
std::unique_ptr<EventListener> listener = EventListener::ForExtension( const bool is_for_service_worker = sw_identifier.has_value();
event_name, extension_id, process, std::unique_ptr<EventListener> listener =
std::unique_ptr<DictionaryValue>(filter.DeepCopy())); is_for_service_worker
? EventListener::ForExtensionServiceWorker(
event_name, extension_id, process, sw_identifier->scope,
sw_identifier->thread_id, filter.CreateDeepCopy())
: EventListener::ForExtension(event_name, extension_id, process,
filter.CreateDeepCopy());
listeners_.RemoveListener(listener.get()); listeners_.RemoveListener(listener.get());
...@@ -771,7 +787,6 @@ void EventRouter::OnExtensionLoaded(content::BrowserContext* browser_context, ...@@ -771,7 +787,6 @@ void EventRouter::OnExtensionLoaded(content::BrowserContext* browser_context,
std::set<std::string> registered_events = std::set<std::string> registered_events =
GetRegisteredEvents(extension->id(), RegisteredEventType::kLazy); GetRegisteredEvents(extension->id(), RegisteredEventType::kLazy);
listeners_.LoadUnfilteredLazyListeners(extension->id(), registered_events); listeners_.LoadUnfilteredLazyListeners(extension->id(), registered_events);
// TODO(lazyboy): Load extension SW filtered events when they are available.
const DictionaryValue* filtered_events = GetFilteredEvents(extension->id()); const DictionaryValue* filtered_events = GetFilteredEvents(extension->id());
if (filtered_events) if (filtered_events)
listeners_.LoadFilteredLazyListeners(extension->id(), *filtered_events); listeners_.LoadFilteredLazyListeners(extension->id(), *filtered_events);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "url/gurl.h" #include "url/gurl.h"
class GURL; class GURL;
struct ServiceWorkerIdentifier;
namespace content { namespace content {
class BrowserContext; class BrowserContext;
...@@ -172,19 +173,23 @@ class EventRouter : public KeyedService, ...@@ -172,19 +173,23 @@ class EventRouter : public KeyedService,
const GURL& service_worker_scope); const GURL& service_worker_scope);
// If |add_lazy_listener| is true also add the lazy version of this listener. // If |add_lazy_listener| is true also add the lazy version of this listener.
void AddFilteredEventListener(const std::string& event_name, void AddFilteredEventListener(
content::RenderProcessHost* process, const std::string& event_name,
const std::string& extension_id, content::RenderProcessHost* process,
const base::DictionaryValue& filter, const std::string& extension_id,
bool add_lazy_listener); base::Optional<ServiceWorkerIdentifier> sw_identifier,
const base::DictionaryValue& filter,
bool add_lazy_listener);
// If |remove_lazy_listener| is true also remove the lazy version of this // If |remove_lazy_listener| is true also remove the lazy version of this
// listener. // listener.
void RemoveFilteredEventListener(const std::string& event_name, void RemoveFilteredEventListener(
content::RenderProcessHost* process, const std::string& event_name,
const std::string& extension_id, content::RenderProcessHost* process,
const base::DictionaryValue& filter, const std::string& extension_id,
bool remove_lazy_listener); base::Optional<ServiceWorkerIdentifier> sw_identifier,
const base::DictionaryValue& filter,
bool remove_lazy_listener);
// Returns true if there is at least one listener for the given event. // Returns true if there is at least one listener for the given event.
bool HasEventListener(const std::string& event_name) const; bool HasEventListener(const std::string& event_name) const;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "extensions/browser/event_listener_map.h" #include "extensions/browser/event_listener_map.h"
#include "extensions/browser/extensions_test.h" #include "extensions/browser/extensions_test.h"
#include "extensions/common/extension_builder.h" #include "extensions/common/extension_builder.h"
#include "extensions/common/extension_messages.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
using base::DictionaryValue; using base::DictionaryValue;
...@@ -370,7 +371,8 @@ TEST_F(EventRouterFilterTest, Basic) { ...@@ -370,7 +371,8 @@ TEST_F(EventRouterFilterTest, Basic) {
std::unique_ptr<base::DictionaryValue> filter = std::unique_ptr<base::DictionaryValue> filter =
CreateHostSuffixFilter(kHostSuffixes[i]); CreateHostSuffixFilter(kHostSuffixes[i]);
event_router()->AddFilteredEventListener(kEventName, render_process_host(), event_router()->AddFilteredEventListener(kEventName, render_process_host(),
kExtensionId, *filter, true); kExtensionId, base::nullopt,
*filter, true);
filters.push_back(std::move(filter)); filters.push_back(std::move(filter));
} }
...@@ -392,21 +394,24 @@ TEST_F(EventRouterFilterTest, Basic) { ...@@ -392,21 +394,24 @@ TEST_F(EventRouterFilterTest, Basic) {
// Remove the second filter. // Remove the second filter.
event_router()->RemoveFilteredEventListener(kEventName, render_process_host(), event_router()->RemoveFilteredEventListener(kEventName, render_process_host(),
kExtensionId, *filters[1], true); kExtensionId, base::nullopt,
*filters[1], true);
ASSERT_TRUE(ContainsFilter(kExtensionId, kEventName, *filters[0])); ASSERT_TRUE(ContainsFilter(kExtensionId, kEventName, *filters[0]));
ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[1])); ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[1]));
ASSERT_TRUE(ContainsFilter(kExtensionId, kEventName, *filters[2])); ASSERT_TRUE(ContainsFilter(kExtensionId, kEventName, *filters[2]));
// Remove the first filter. // Remove the first filter.
event_router()->RemoveFilteredEventListener(kEventName, render_process_host(), event_router()->RemoveFilteredEventListener(kEventName, render_process_host(),
kExtensionId, *filters[0], true); kExtensionId, base::nullopt,
*filters[0], true);
ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[0])); ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[0]));
ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[1])); ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[1]));
ASSERT_TRUE(ContainsFilter(kExtensionId, kEventName, *filters[2])); ASSERT_TRUE(ContainsFilter(kExtensionId, kEventName, *filters[2]));
// Remove the third filter. // Remove the third filter.
event_router()->RemoveFilteredEventListener(kEventName, render_process_host(), event_router()->RemoveFilteredEventListener(kEventName, render_process_host(),
kExtensionId, *filters[2], true); kExtensionId, base::nullopt,
*filters[2], true);
ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[0])); ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[0]));
ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[1])); ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[1]));
ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[2])); ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[2]));
......
...@@ -273,6 +273,7 @@ void ExtensionMessageFilter::OnExtensionRemoveLazyServiceWorkerListener( ...@@ -273,6 +273,7 @@ void ExtensionMessageFilter::OnExtensionRemoveLazyServiceWorkerListener(
void ExtensionMessageFilter::OnExtensionAddFilteredListener( void ExtensionMessageFilter::OnExtensionAddFilteredListener(
const std::string& extension_id, const std::string& extension_id,
const std::string& event_name, const std::string& event_name,
base::Optional<ServiceWorkerIdentifier> sw_identifier,
const base::DictionaryValue& filter, const base::DictionaryValue& filter,
bool lazy) { bool lazy) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
...@@ -284,12 +285,13 @@ void ExtensionMessageFilter::OnExtensionAddFilteredListener( ...@@ -284,12 +285,13 @@ void ExtensionMessageFilter::OnExtensionAddFilteredListener(
return; return;
GetEventRouter()->AddFilteredEventListener(event_name, process, extension_id, GetEventRouter()->AddFilteredEventListener(event_name, process, extension_id,
filter, lazy); sw_identifier, filter, lazy);
} }
void ExtensionMessageFilter::OnExtensionRemoveFilteredListener( void ExtensionMessageFilter::OnExtensionRemoveFilteredListener(
const std::string& extension_id, const std::string& extension_id,
const std::string& event_name, const std::string& event_name,
base::Optional<ServiceWorkerIdentifier> sw_identifier,
const base::DictionaryValue& filter, const base::DictionaryValue& filter,
bool lazy) { bool lazy) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
...@@ -300,8 +302,8 @@ void ExtensionMessageFilter::OnExtensionRemoveFilteredListener( ...@@ -300,8 +302,8 @@ void ExtensionMessageFilter::OnExtensionRemoveFilteredListener(
if (!process) if (!process)
return; return;
GetEventRouter()->RemoveFilteredEventListener(event_name, process, GetEventRouter()->RemoveFilteredEventListener(
extension_id, filter, lazy); event_name, process, extension_id, sw_identifier, filter, lazy);
} }
void ExtensionMessageFilter::OnExtensionShouldSuspendAck( void ExtensionMessageFilter::OnExtensionShouldSuspendAck(
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
class GURL; class GURL;
struct ExtensionMsg_ExternalConnectionInfo; struct ExtensionMsg_ExternalConnectionInfo;
struct ExtensionMsg_TabTargetConnectionInfo; struct ExtensionMsg_TabTargetConnectionInfo;
struct ServiceWorkerIdentifier;
namespace content { namespace content {
class BrowserContext; class BrowserContext;
...@@ -76,14 +77,18 @@ class ExtensionMessageFilter : public content::BrowserMessageFilter { ...@@ -76,14 +77,18 @@ class ExtensionMessageFilter : public content::BrowserMessageFilter {
const std::string& extension_id, const std::string& extension_id,
const std::string& event_name, const std::string& event_name,
const GURL& worker_scope_url); const GURL& worker_scope_url);
void OnExtensionAddFilteredListener(const std::string& extension_id, void OnExtensionAddFilteredListener(
const std::string& event_name, const std::string& extension_id,
const base::DictionaryValue& filter, const std::string& event_name,
bool lazy); base::Optional<ServiceWorkerIdentifier> sw_identifier,
void OnExtensionRemoveFilteredListener(const std::string& extension_id, const base::DictionaryValue& filter,
const std::string& event_name, bool lazy);
const base::DictionaryValue& filter, void OnExtensionRemoveFilteredListener(
bool lazy); const std::string& extension_id,
const std::string& event_name,
base::Optional<ServiceWorkerIdentifier> sw_identifier,
const base::DictionaryValue& filter,
bool lazy);
void OnExtensionShouldSuspendAck(const std::string& extension_id, void OnExtensionShouldSuspendAck(const std::string& extension_id,
int sequence_id); int sequence_id);
void OnExtensionSuspendAck(const std::string& extension_id); void OnExtensionSuspendAck(const std::string& extension_id);
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "extensions/common/constants.h" #include "extensions/common/constants.h"
#include "ipc/ipc_message.h"
namespace extensions { namespace extensions {
const char kExtensionScheme[] = "chrome-extension"; const char kExtensionScheme[] = "chrome-extension";
...@@ -86,6 +88,7 @@ const size_t kWebstoreSignaturesPublicKeySize = ...@@ -86,6 +88,7 @@ const size_t kWebstoreSignaturesPublicKeySize =
arraysize(kWebstoreSignaturesPublicKey); arraysize(kWebstoreSignaturesPublicKey);
const int kMainThreadId = 0; const int kMainThreadId = 0;
const int kIgnoreRoutingId = MSG_ROUTING_NONE;
const char kMimeTypeJpeg[] = "image/jpeg"; const char kMimeTypeJpeg[] = "image/jpeg";
const char kMimeTypePng[] = "image/png"; const char kMimeTypePng[] = "image/png";
......
...@@ -122,6 +122,10 @@ extern const size_t kWebstoreSignaturesPublicKeySize; ...@@ -122,6 +122,10 @@ extern const size_t kWebstoreSignaturesPublicKeySize;
// from a non-service worker context // from a non-service worker context
extern const int kMainThreadId; extern const int kMainThreadId;
// A routing ID that is used in some contexts to specify that those contexts
// do not care about a specific routing id.
extern const int kIgnoreRoutingId;
// Enumeration of possible app launch sources. // Enumeration of possible app launch sources.
// This should be kept in sync with LaunchSource in // This should be kept in sync with LaunchSource in
// extensions/common/api/app_runtime.idl, and GetLaunchSourceEnum() in // extensions/common/api/app_runtime.idl, and GetLaunchSourceEnum() in
......
...@@ -276,6 +276,13 @@ IPC_STRUCT_TRAITS_BEGIN(extensions::EventFilteringInfo) ...@@ -276,6 +276,13 @@ IPC_STRUCT_TRAITS_BEGIN(extensions::EventFilteringInfo)
IPC_STRUCT_TRAITS_MEMBER(window_exposed_by_default) IPC_STRUCT_TRAITS_MEMBER(window_exposed_by_default)
IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_END()
// Identifier containing info about a service worker, used in event listener
// IPCs.
IPC_STRUCT_BEGIN(ServiceWorkerIdentifier)
IPC_STRUCT_MEMBER(GURL, scope)
IPC_STRUCT_MEMBER(int, thread_id)
IPC_STRUCT_END()
// Singly-included section for custom IPC traits. // Singly-included section for custom IPC traits.
#ifndef EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_ #ifndef EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
#define EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_ #define EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
...@@ -724,19 +731,27 @@ IPC_MESSAGE_CONTROL3(ExtensionHostMsg_RemoveLazyServiceWorkerListener, ...@@ -724,19 +731,27 @@ IPC_MESSAGE_CONTROL3(ExtensionHostMsg_RemoveLazyServiceWorkerListener,
// Notify the browser that the given extension added a listener to instances of // Notify the browser that the given extension added a listener to instances of
// the named event that satisfy the filter. // the named event that satisfy the filter.
IPC_MESSAGE_CONTROL4(ExtensionHostMsg_AddFilteredListener, // If |sw_identifier| is specified, it implies that the listener is for a
std::string /* extension_id */, // service worker, and the param is used to identify the worker.
std::string /* name */, IPC_MESSAGE_CONTROL5(
base::DictionaryValue /* filter */, ExtensionHostMsg_AddFilteredListener,
bool /* lazy */) std::string /* extension_id */,
std::string /* name */,
base::Optional<ServiceWorkerIdentifier> /* sw_identifier */,
base::DictionaryValue /* filter */,
bool /* lazy */)
// Notify the browser that the given extension is no longer interested in // Notify the browser that the given extension is no longer interested in
// instances of the named event that satisfy the filter. // instances of the named event that satisfy the filter.
IPC_MESSAGE_CONTROL4(ExtensionHostMsg_RemoveFilteredListener, // If |sw_identifier| is specified, it implies that the listener is for a
std::string /* extension_id */, // service worker, and the param is used to identify the worker.
std::string /* name */, IPC_MESSAGE_CONTROL5(
base::DictionaryValue /* filter */, ExtensionHostMsg_RemoveFilteredListener,
bool /* lazy */) std::string /* extension_id */,
std::string /* name */,
base::Optional<ServiceWorkerIdentifier> /* sw_identifier */,
base::DictionaryValue /* filter */,
bool /* lazy */)
// Notify the browser that an event has finished being dispatched. // Notify the browser that an event has finished being dispatched.
IPC_MESSAGE_ROUTED1(ExtensionHostMsg_EventAck, int /* message_id */) IPC_MESSAGE_ROUTED1(ExtensionHostMsg_EventAck, int /* message_id */)
......
...@@ -32,6 +32,17 @@ namespace extensions { ...@@ -32,6 +32,17 @@ namespace extensions {
namespace { namespace {
// Returns the routing id to use for matching filtered events.
// Used for routing events to the correct RenderFrame. This doesn't apply to
// Extension Service Worker events as there is no RenderFrame to target an event
// to. This function returns extensions::kIgnoreRoutingId in that case,
// essentially ignoring routing id for worker events.
int GetRoutingIDForFilteredEvents(ScriptContext* script_context) {
return script_context->context_type() == Feature::SERVICE_WORKER_CONTEXT
? kIgnoreRoutingId
: script_context->GetRenderFrame()->GetRoutingID();
}
// Returns a v8::Array containing the ids of the listeners that match the given // Returns a v8::Array containing the ids of the listeners that match the given
// |event_filter_dict| in the given |script_context|. // |event_filter_dict| in the given |script_context|.
v8::Local<v8::Array> GetMatchingListeners(ScriptContext* script_context, v8::Local<v8::Array> GetMatchingListeners(ScriptContext* script_context,
...@@ -45,7 +56,7 @@ v8::Local<v8::Array> GetMatchingListeners(ScriptContext* script_context, ...@@ -45,7 +56,7 @@ v8::Local<v8::Array> GetMatchingListeners(ScriptContext* script_context,
// have a routingId in their filter. // have a routingId in their filter.
std::set<EventFilter::MatcherID> matched_event_filters = std::set<EventFilter::MatcherID> matched_event_filters =
event_filter.MatchEvent(event_name, info, event_filter.MatchEvent(event_name, info,
script_context->GetRenderFrame()->GetRoutingID()); GetRoutingIDForFilteredEvents(script_context));
v8::Local<v8::Array> array( v8::Local<v8::Array> array(
v8::Array::New(isolate, matched_event_filters.size())); v8::Array::New(isolate, matched_event_filters.size()));
int i = 0; int i = 0;
...@@ -228,8 +239,8 @@ void EventBindings::AttachFilteredEvent( ...@@ -228,8 +239,8 @@ void EventBindings::AttachFilteredEvent(
EventFilter& event_filter = bookkeeper->event_filter(); EventFilter& event_filter = bookkeeper->event_filter();
int id = event_filter.AddEventMatcher( int id = event_filter.AddEventMatcher(
event_name, event_name,
std::make_unique<EventMatcher>( std::make_unique<EventMatcher>(std::move(filter),
std::move(filter), context()->GetRenderFrame()->GetRoutingID())); GetRoutingIDForFilteredEvents(context())));
if (id == -1) { if (id == -1) {
args.GetReturnValue().Set(static_cast<int32_t>(-1)); args.GetReturnValue().Set(static_cast<int32_t>(-1));
return; return;
......
...@@ -94,7 +94,7 @@ class MainThreadIPCMessageSender : public IPCMessageSender { ...@@ -94,7 +94,7 @@ class MainThreadIPCMessageSender : public IPCMessageSender {
DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId()); DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
render_thread_->Send(new ExtensionHostMsg_AddFilteredListener( render_thread_->Send(new ExtensionHostMsg_AddFilteredListener(
context->GetExtensionID(), event_name, filter, is_lazy)); context->GetExtensionID(), event_name, base::nullopt, filter, is_lazy));
} }
void SendRemoveFilteredEventListenerIPC(ScriptContext* context, void SendRemoveFilteredEventListenerIPC(ScriptContext* context,
...@@ -105,7 +105,8 @@ class MainThreadIPCMessageSender : public IPCMessageSender { ...@@ -105,7 +105,8 @@ class MainThreadIPCMessageSender : public IPCMessageSender {
DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId()); DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
render_thread_->Send(new ExtensionHostMsg_RemoveFilteredListener( render_thread_->Send(new ExtensionHostMsg_RemoveFilteredListener(
context->GetExtensionID(), event_name, filter, remove_lazy_listener)); context->GetExtensionID(), event_name, base::nullopt, filter,
remove_lazy_listener));
} }
private: private:
...@@ -204,7 +205,11 @@ class WorkerThreadIPCMessageSender : public IPCMessageSender { ...@@ -204,7 +205,11 @@ class WorkerThreadIPCMessageSender : public IPCMessageSender {
bool is_lazy) override { bool is_lazy) override {
DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type()); DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId()); DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
NOTIMPLEMENTED(); ServiceWorkerIdentifier sw_identifier;
sw_identifier.scope = context->service_worker_scope();
sw_identifier.thread_id = content::WorkerThread::GetCurrentId(),
dispatcher_->Send(new ExtensionHostMsg_AddFilteredListener(
context->GetExtensionID(), event_name, sw_identifier, filter, is_lazy));
} }
void SendRemoveFilteredEventListenerIPC(ScriptContext* context, void SendRemoveFilteredEventListenerIPC(ScriptContext* context,
...@@ -213,7 +218,12 @@ class WorkerThreadIPCMessageSender : public IPCMessageSender { ...@@ -213,7 +218,12 @@ class WorkerThreadIPCMessageSender : public IPCMessageSender {
bool remove_lazy_listener) override { bool remove_lazy_listener) override {
DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type()); DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId()); DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
NOTIMPLEMENTED(); ServiceWorkerIdentifier sw_identifier;
sw_identifier.scope = context->service_worker_scope();
sw_identifier.thread_id = content::WorkerThread::GetCurrentId(),
dispatcher_->Send(new ExtensionHostMsg_RemoveFilteredListener(
context->GetExtensionID(), event_name, sw_identifier, filter,
remove_lazy_listener));
} }
private: private:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment