Initial chrome.mdns API.

BUG=280900
TBR=erg

Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=221619

Review URL: https://chromiumcodereview.appspot.com/23437015

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221738 0039d316-1c4b-4281-b951-d872f2087c98
parent 779a78fb
justinlin@chromium.org
mfoltz@chromium.org
// Copyright 2013 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.
#include "chrome/browser/extensions/api/mdns/dns_sd_registry.h"
namespace extensions {
DnsSdRegistry::DnsSdRegistry() {}
DnsSdRegistry::~DnsSdRegistry() {}
void DnsSdRegistry::AddObserver(DnsSdObserver* observer) {
observers_.AddObserver(observer);
}
void DnsSdRegistry::RemoveObserver(DnsSdObserver* observer) {
observers_.RemoveObserver(observer);
}
void DnsSdRegistry::RegisterDnsSdListener(std::string service_type) {
// TODO(mfoltz): Start DNS-SD service.
}
void DnsSdRegistry::UnregisterDnsSdListener(std::string service_type) {
// TODO(mfoltz): Stop DNS-SD service.
}
} // namespace extensions
// Copyright 2013 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.
#ifndef CHROME_BROWSER_EXTENSIONS_API_MDNS_DNS_SD_REGISTRY_H_
#define CHROME_BROWSER_EXTENSIONS_API_MDNS_DNS_SD_REGISTRY_H_
#include <string>
#include <vector>
#include "base/observer_list.h"
namespace extensions {
// Network Service Discovery registry class for keeping track of discovered
// network services.
class DnsSdRegistry {
public:
typedef std::vector<std::string> DnsSdServiceList;
class DnsSdObserver {
public:
virtual void OnDnsSdEvent(const std::string& service_type,
const DnsSdServiceList& services) = 0;
protected:
virtual ~DnsSdObserver() {}
};
explicit DnsSdRegistry();
virtual ~DnsSdRegistry();
// Observer registration for parties interested in discovery events.
virtual void AddObserver(DnsSdObserver* observer);
virtual void RemoveObserver(DnsSdObserver* observer);
// DNS-SD-related discovery functionality.
virtual void RegisterDnsSdListener(std::string service_type);
virtual void UnregisterDnsSdListener(std::string service_type);
protected:
ObserverList<DnsSdObserver> observers_;
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_MDNS_DNS_SD_REGISTRY_H_
// Copyright 2013 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.
#include "chrome/browser/extensions/api/mdns/mdns_api.h"
#include <vector>
#include "base/lazy_instance.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/common/extensions/api/mdns.h"
namespace extensions {
namespace mdns = api::mdns;
namespace {
// Whitelisted mDNS service types.
const char kCastServiceType[] = "_googlecast._tcp.local";
const char kTestServiceType[] = "_testing._tcp.local";
bool IsServiceTypeWhitelisted(const std::string& service_type) {
return service_type == kCastServiceType ||
service_type == kTestServiceType;
}
} // namespace
MDnsAPI::MDnsAPI(Profile* profile) : profile_(profile) {
DCHECK(profile_);
ExtensionSystem::Get(profile)->event_router()->RegisterObserver(
this, mdns::OnServiceList::kEventName);
}
MDnsAPI::~MDnsAPI() {
if (dns_sd_registry_.get()) {
dns_sd_registry_->RemoveObserver(this);
}
}
// static
MDnsAPI* MDnsAPI::Get(Profile* profile) {
return ProfileKeyedAPIFactory<MDnsAPI>::GetForProfile(profile);
}
static base::LazyInstance<ProfileKeyedAPIFactory<MDnsAPI> > g_factory =
LAZY_INSTANCE_INITIALIZER;
// static
ProfileKeyedAPIFactory<MDnsAPI>* MDnsAPI::GetFactoryInstance() {
return &g_factory.Get();
}
void MDnsAPI::SetDnsSdRegistryForTesting(
scoped_ptr<DnsSdRegistry> dns_sd_registry) {
dns_sd_registry_ = dns_sd_registry.Pass();
}
DnsSdRegistry* MDnsAPI::dns_sd_registry() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!dns_sd_registry_.get()) {
dns_sd_registry_.reset(new extensions::DnsSdRegistry());
dns_sd_registry_->AddObserver(this);
}
return dns_sd_registry_.get();
}
void MDnsAPI::OnListenerAdded(const EventListenerInfo& details) {
DCHECK(thread_checker_.CalledOnValidThread());
UpdateMDnsListeners(details);
}
void MDnsAPI::OnListenerRemoved(const EventListenerInfo& details) {
DCHECK(thread_checker_.CalledOnValidThread());
UpdateMDnsListeners(details);
}
void MDnsAPI::UpdateMDnsListeners(const EventListenerInfo& details) {
std::set<std::string> new_service_types;
// Check all listeners for service type filers.
const EventListenerMap::ListenerList& listeners =
extensions::ExtensionSystem::Get(profile_)->event_router()->
listeners().GetEventListenersByName(details.event_name);
for (EventListenerMap::ListenerList::const_iterator it = listeners.begin();
it != listeners.end(); ++it) {
base::DictionaryValue* filter = ((*it)->filter.get());
for (base::DictionaryValue::Iterator iter(*filter);
!iter.IsAtEnd(); iter.Advance()) {
}
std::string filter_value;
filter->GetStringASCII(kEventFilterServiceTypeKey, &filter_value);
if (filter_value.empty())
continue;
new_service_types.insert(filter_value);
}
// Find all the added and removed service types since last update.
std::set<std::string> added_service_types =
base::STLSetDifference<std::set<std::string> >(
service_types_, new_service_types);
std::set<std::string> removed_service_types =
base::STLSetDifference<std::set<std::string> >(
new_service_types, service_types_);
// Update the registry.
DnsSdRegistry* registry = dns_sd_registry();
for (std::set<std::string>::iterator it = added_service_types.begin();
it != added_service_types.end(); ++it) {
if (IsServiceTypeWhitelisted(*it))
registry->RegisterDnsSdListener(*it);
}
for (std::set<std::string>::iterator it = removed_service_types.begin();
it != removed_service_types.end(); ++it) {
if (IsServiceTypeWhitelisted(*it))
registry->UnregisterDnsSdListener(*it);
}
service_types_ = new_service_types;
}
void MDnsAPI::OnDnsSdEvent(const std::string& service_type,
const DnsSdRegistry::DnsSdServiceList& services) {
DCHECK(thread_checker_.CalledOnValidThread());
if (services.size() == 0)
return;
std::vector<linked_ptr<mdns::MDnsService> > args;
for (DnsSdRegistry::DnsSdServiceList::const_iterator it = services.begin();
it != services.end(); ++it) {
linked_ptr<mdns::MDnsService> mdns_service =
make_linked_ptr(new mdns::MDnsService);
// TODO(justinlin, mfoltz): Copy data from service list.
mdns_service->service_name = service_type;
args.push_back(mdns_service);
}
scoped_ptr<base::ListValue> results = mdns::OnServiceList::Create(args);
scoped_ptr<Event> event(
new Event(mdns::OnServiceList::kEventName, results.Pass()));
event->restrict_to_profile = profile_;
event->filter_info.SetServiceType(service_type);
// TODO(justinlin): To avoid having listeners without filters getting all
// events, modify API to have this event require filters.
extensions::ExtensionSystem::Get(profile_)->event_router()->
BroadcastEvent(event.Pass());
}
} // namespace extensions
// Copyright 2013 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.
#ifndef CHROME_BROWSER_EXTENSIONS_API_MDNS_MDNS_API_H_
#define CHROME_BROWSER_EXTENSIONS_API_MDNS_MDNS_API_H_
#include <set>
#include <string>
#include "base/memory/scoped_ptr.h"
#include "base/threading/thread_checker.h"
#include "chrome/browser/extensions/api/mdns/dns_sd_registry.h"
#include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
#include "chrome/browser/extensions/event_router.h"
namespace extensions {
class DnsSdRegistry;
// MDnsAPI is instantiated with the profile and will listen for extensions that
// register listeners for the chrome.mdns extension API. It will use a registry
// class to start the mDNS listener process (if necessary) and observe new
// service events to dispatch them to registered extensions.
class MDnsAPI : public ProfileKeyedAPI,
public EventRouter::Observer,
public DnsSdRegistry::DnsSdObserver {
public:
explicit MDnsAPI(Profile* profile);
virtual ~MDnsAPI();
static MDnsAPI* Get(Profile* profile);
// ProfileKeyedAPI implementation.
static ProfileKeyedAPIFactory<MDnsAPI>* GetFactoryInstance();
// Used to mock out the DnsSdRegistry for testing.
void SetDnsSdRegistryForTesting(scoped_ptr<DnsSdRegistry> registry);
protected:
// Retrieve an instance of the registry. Lazily created when needed.
virtual DnsSdRegistry* dns_sd_registry();
private:
friend class ProfileKeyedAPIFactory<MDnsAPI>;
// EventRouter::Observer:
virtual void OnListenerAdded(const EventListenerInfo& details) OVERRIDE;
virtual void OnListenerRemoved(const EventListenerInfo& details) OVERRIDE;
// DnsSdRegistry::Observer
virtual void OnDnsSdEvent(
const std::string& service_type,
const DnsSdRegistry::DnsSdServiceList& services) OVERRIDE;
// ProfileKeyedAPI implementation.
static const char* service_name() {
return "MDnsAPI";
}
static const bool kServiceIsCreatedWithBrowserContext = true;
static const bool kServiceIsNULLWhileTesting = true;
// Update the current list of service types and update the registry.
void UpdateMDnsListeners(const EventListenerInfo& details);
// Ensure methods are only called on UI thread.
base::ThreadChecker thread_checker_;
Profile* const profile_;
// Lazily created on first access and destroyed with this API class.
scoped_ptr<DnsSdRegistry> dns_sd_registry_;
// Current set of service types registered with the registry.
std::set<std::string> service_types_;
DISALLOW_COPY_AND_ASSIGN(MDnsAPI);
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_MDNS_MDNS_API_H_
// Copyright 2013 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.
#include "base/command_line.h"
#include "chrome/browser/extensions/api/mdns/mdns_api.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/api/mdns.h"
#include "testing/gmock/include/gmock/gmock.h"
using extensions::DnsSdRegistry;
using ::testing::A;
using ::testing::_;
namespace api = extensions::api;
namespace {
class MockDnsSdRegistry : public DnsSdRegistry {
public:
explicit MockDnsSdRegistry(extensions::MDnsAPI* api) : api_(api) {}
virtual ~MockDnsSdRegistry() {}
MOCK_METHOD1(AddObserver, void(DnsSdObserver* observer));
MOCK_METHOD1(RemoveObserver, void(DnsSdObserver* observer));
MOCK_METHOD1(RegisterDnsSdListener, void(std::string service_type));
MOCK_METHOD1(UnregisterDnsSdListener, void(std::string service_type));
void DispatchMDnsEvent(const std::string& service_type,
const DnsSdServiceList& services) {
api_->OnDnsSdEvent(service_type, services);
}
private:
extensions::DnsSdRegistry::DnsSdObserver* api_;
};
class MDnsAPITest : public ExtensionApiTest {
public:
MDnsAPITest() {}
virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
ExtensionApiTest::SetUpCommandLine(command_line);
command_line->AppendSwitchASCII(
switches::kWhitelistedExtensionID, "ddchlicdkolnonkihahngkmmmjnjlkkf");
}
void SetUpTestDnsSdRegistry() {
extensions::MDnsAPI* api = extensions::MDnsAPI::Get(profile());
dns_sd_registry_ = new MockDnsSdRegistry(api);
// Transfers ownership of the registry instance.
api->SetDnsSdRegistryForTesting(
make_scoped_ptr<DnsSdRegistry>(dns_sd_registry_).Pass());
}
protected:
MockDnsSdRegistry* dns_sd_registry_;
};
} // namespace
// TODO(justinlin): Win Dbg has a workaround that makes RunExtensionSubtest
// always return true without actually running the test. Remove when fixed.
#if defined(OS_WIN) && !defined(NDEBUG)
#define MAYBE_RegisterListener DISABLED_RegisterListener
#else
#define MAYBE_RegisterListener RegisterListener
#endif
// Test loading extension, registering an MDNS listener and dispatching events.
IN_PROC_BROWSER_TEST_F(MDnsAPITest, MAYBE_RegisterListener) {
const std::string& service_type = "_googlecast._tcp.local";
SetUpTestDnsSdRegistry();
EXPECT_CALL(*dns_sd_registry_, RegisterDnsSdListener(service_type))
.Times(1);
EXPECT_CALL(*dns_sd_registry_, UnregisterDnsSdListener(service_type))
.Times(1);
EXPECT_CALL(*dns_sd_registry_,
RemoveObserver(A<extensions::DnsSdRegistry::DnsSdObserver*>()))
.Times(1);
EXPECT_TRUE(RunExtensionSubtest("mdns/api", "register_listener.html"))
<< message_;
ResultCatcher catcher;
// Dispatch 3 events, one of which should not be sent to the test extension.
std::vector<std::string> services;
services.push_back("test");
dns_sd_registry_->DispatchMDnsEvent(service_type, services);
dns_sd_registry_->DispatchMDnsEvent("_uninteresting._tcp.local", services);
dns_sd_registry_->DispatchMDnsEvent(service_type, services);
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
// TODO(justinlin): Win Dbg has a workaround that makes RunExtensionSubtest
// always return true without actually running the test. Remove when fixed.
#if defined(OS_WIN) && !defined(NDEBUG)
#define MAYBE_RegisterMultipleListeners DISABLED_RegisterMultipleListeners
#else
#define MAYBE_RegisterMultipleListeners RegisterMultipleListeners
#endif
// Test loading extension and registering multiple listeners.
IN_PROC_BROWSER_TEST_F(MDnsAPITest, MAYBE_RegisterMultipleListeners) {
const std::string& service_type = "_googlecast._tcp.local";
const std::string& test_service_type = "_testing._tcp.local";
SetUpTestDnsSdRegistry();
EXPECT_CALL(*dns_sd_registry_, RegisterDnsSdListener(service_type))
.Times(1);
EXPECT_CALL(*dns_sd_registry_, UnregisterDnsSdListener(service_type))
.Times(1);
EXPECT_CALL(*dns_sd_registry_, RegisterDnsSdListener(test_service_type))
.Times(1);
EXPECT_CALL(*dns_sd_registry_, UnregisterDnsSdListener(test_service_type))
.Times(1);
EXPECT_CALL(*dns_sd_registry_,
RemoveObserver(A<extensions::DnsSdRegistry::DnsSdObserver*>()))
.Times(1);
EXPECT_TRUE(RunExtensionSubtest("mdns/api",
"register_multiple_listeners.html"))
<< message_;
ResultCatcher catcher;
std::vector<std::string> services;
services.push_back("test");
dns_sd_registry_->DispatchMDnsEvent(service_type, services);
dns_sd_registry_->DispatchMDnsEvent(test_service_type, services);
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "chrome/browser/extensions/api/input/input.h" #include "chrome/browser/extensions/api/input/input.h"
#include "chrome/browser/extensions/api/location/location_manager.h" #include "chrome/browser/extensions/api/location/location_manager.h"
#include "chrome/browser/extensions/api/management/management_api.h" #include "chrome/browser/extensions/api/management/management_api.h"
#include "chrome/browser/extensions/api/mdns/mdns_api.h"
#include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.h" #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.h"
#include "chrome/browser/extensions/api/omnibox/omnibox_api.h" #include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
#include "chrome/browser/extensions/api/preference/chrome_direct_setting_api.h" #include "chrome/browser/extensions/api/preference/chrome_direct_setting_api.h"
...@@ -239,6 +240,7 @@ EnsureBrowserContextKeyedServiceFactoriesBuilt() { ...@@ -239,6 +240,7 @@ EnsureBrowserContextKeyedServiceFactoriesBuilt() {
#endif #endif
extensions::LocationManager::GetFactoryInstance(); extensions::LocationManager::GetFactoryInstance();
extensions::ManagementAPI::GetFactoryInstance(); extensions::ManagementAPI::GetFactoryInstance();
extensions::MDnsAPI::GetFactoryInstance();
extensions::MediaGalleriesPrivateAPI::GetFactoryInstance(); extensions::MediaGalleriesPrivateAPI::GetFactoryInstance();
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
extensions::MediaPlayerAPI::GetFactoryInstance(); extensions::MediaPlayerAPI::GetFactoryInstance();
......
...@@ -329,6 +329,10 @@ ...@@ -329,6 +329,10 @@
'browser/extensions/api/messaging/native_message_port.h', 'browser/extensions/api/messaging/native_message_port.h',
'browser/extensions/api/metrics_private/metrics_private_api.cc', 'browser/extensions/api/metrics_private/metrics_private_api.cc',
'browser/extensions/api/metrics_private/metrics_private_api.h', 'browser/extensions/api/metrics_private/metrics_private_api.h',
'browser/extensions/api/mdns/dns_sd_registry.h',
'browser/extensions/api/mdns/dns_sd_registry.cc',
'browser/extensions/api/mdns/mdns_api.h',
'browser/extensions/api/mdns/mdns_api.cc',
'browser/extensions/api/module/module.cc', 'browser/extensions/api/module/module.cc',
'browser/extensions/api/module/module.h', 'browser/extensions/api/module/module.h',
'browser/extensions/api/music_manager_private/device_id.cc', 'browser/extensions/api/music_manager_private/device_id.cc',
......
...@@ -1343,6 +1343,7 @@ ...@@ -1343,6 +1343,7 @@
'browser/extensions/api/management/management_api_browsertest.cc', 'browser/extensions/api/management/management_api_browsertest.cc',
'browser/extensions/api/management/management_apitest.cc', 'browser/extensions/api/management/management_apitest.cc',
'browser/extensions/api/management/management_browsertest.cc', 'browser/extensions/api/management/management_browsertest.cc',
'browser/extensions/api/mdns/mdns_apitest.cc',
'browser/extensions/api/media_galleries/media_galleries_apitest.cc', 'browser/extensions/api/media_galleries/media_galleries_apitest.cc',
'browser/extensions/api/media_galleries_private/media_galleries_private_apitest.cc', 'browser/extensions/api/media_galleries_private/media_galleries_private_apitest.cc',
'browser/extensions/api/media_galleries_private/media_galleries_watch_apitest.cc', 'browser/extensions/api/media_galleries_private/media_galleries_watch_apitest.cc',
......
...@@ -351,6 +351,10 @@ ...@@ -351,6 +351,10 @@
"dependencies": ["permission:metricsPrivate"], "dependencies": ["permission:metricsPrivate"],
"contexts": ["blessed_extension"] "contexts": ["blessed_extension"]
}, },
"mdns": {
"dependencies": ["permission:mdns"],
"contexts": ["blessed_extension"]
},
"musicManagerPrivate": { "musicManagerPrivate": {
"dependencies": ["permission:musicManagerPrivate"], "dependencies": ["permission:musicManagerPrivate"],
"contexts": ["blessed_extension"] "contexts": ["blessed_extension"]
......
...@@ -432,6 +432,18 @@ ...@@ -432,6 +432,18 @@
"eemlkeanncmjljgehlbplemhmdmalhdc" // CCD Release "eemlkeanncmjljgehlbplemhmdmalhdc" // CCD Release
] ]
}, },
"mdns": {
"channel": "stable",
"extension_types": ["extension"],
"whitelist": [
"enhhojjnijigcajfphajepfemndkmdlo", // Dev
"pkedcjkdefgpdelpbcmbmeomcjbeemfm", // Trusted Tester
"fmfcbgogabcbclcofgocippekhfcmgfj", // Staging
"hfaagokkkhdbgiakmmlclaapfelnkoah", // Canary
"F155646B5D1CA545F7E1E4E20D573DFDD44C2540", // Trusted Tester (public)
"16CA7A47AAE4BE49B1E75A6B960C3875E945B264" // Release
]
},
"musicManagerPrivate": { "musicManagerPrivate": {
"channel": "stable", "channel": "stable",
"extension_types": ["platform_app"], "extension_types": ["platform_app"],
......
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
'log_private.idl', 'log_private.idl',
'management.json', 'management.json',
'manifest_types.json', 'manifest_types.json',
'mdns.idl',
'media_galleries.idl', 'media_galleries.idl',
'media_galleries_private.idl', 'media_galleries_private.idl',
'media_player_private.json', 'media_player_private.json',
......
// Copyright 2013 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.
// Use the <code>chrome.mdns</code> API to discover services over mDNS.
// This comprises a subset of the features of the NSD spec:
// http://www.w3.org/TR/discovery-api/
namespace mdns {
// Represents a mDNS/DNS-SD service.
dictionary MDnsService {
// The service name of an mDNS advertised service,
// <instance_name>.<service_type>.
DOMString serviceName;
// The host:port pair of an mDNS advertised service.
DOMString serviceHostPort;
// The IP address of an mDNS advertised service.
DOMString ipAddress;
// Metadata for an mDNS advertised service.
DOMString[] serviceData;
};
interface Events {
// Event fired to inform clients of the current complete set of known
// available services. Clients should only need to store the list from the
// most recent event. The service types that the extension is interested in
// discovering should be declared as an array in the extensions manifest
// file with the 'mdns_service_types' key.
[supportsFilters=true] static void onServiceList(MDnsService[] services);
};
};
...@@ -102,6 +102,7 @@ class APIPermission { ...@@ -102,6 +102,7 @@ class APIPermission {
kMediaGalleriesPrivate, kMediaGalleriesPrivate,
kMediaPlayerPrivate, kMediaPlayerPrivate,
kMetricsPrivate, kMetricsPrivate,
kMDns,
kMusicManagerPrivate, kMusicManagerPrivate,
kNativeMessaging, kNativeMessaging,
kNetworkingPrivate, kNetworkingPrivate,
......
...@@ -188,6 +188,7 @@ std::vector<APIPermissionInfo*> ChromeAPIPermissions::GetAllPermissions() ...@@ -188,6 +188,7 @@ std::vector<APIPermissionInfo*> ChromeAPIPermissions::GetAllPermissions()
APIPermissionInfo::kFlagCannotBeOptional }, APIPermissionInfo::kFlagCannotBeOptional },
{ APIPermission::kMetricsPrivate, "metricsPrivate", { APIPermission::kMetricsPrivate, "metricsPrivate",
APIPermissionInfo::kFlagCannotBeOptional }, APIPermissionInfo::kFlagCannotBeOptional },
{ APIPermission::kMDns, "mdns", APIPermissionInfo::kFlagCannotBeOptional },
{ APIPermission::kMusicManagerPrivate, "musicManagerPrivate", { APIPermission::kMusicManagerPrivate, "musicManagerPrivate",
APIPermissionInfo::kFlagCannotBeOptional, APIPermissionInfo::kFlagCannotBeOptional,
IDS_EXTENSION_PROMPT_WARNING_MUSIC_MANAGER_PRIVATE, IDS_EXTENSION_PROMPT_WARNING_MUSIC_MANAGER_PRIVATE,
......
...@@ -717,6 +717,7 @@ TEST(PermissionsTest, PermissionMessages) { ...@@ -717,6 +717,7 @@ TEST(PermissionsTest, PermissionMessages) {
skip.insert(APIPermission::kMediaGalleriesPrivate); skip.insert(APIPermission::kMediaGalleriesPrivate);
skip.insert(APIPermission::kMediaPlayerPrivate); skip.insert(APIPermission::kMediaPlayerPrivate);
skip.insert(APIPermission::kMetricsPrivate); skip.insert(APIPermission::kMetricsPrivate);
skip.insert(APIPermission::kMDns);
skip.insert(APIPermission::kPreferencesPrivate); skip.insert(APIPermission::kPreferencesPrivate);
skip.insert(APIPermission::kRecoveryPrivate); skip.insert(APIPermission::kRecoveryPrivate);
skip.insert(APIPermission::kRtcPrivate); skip.insert(APIPermission::kRtcPrivate);
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#include "chrome/renderer/extensions/event_bindings.h" #include "chrome/renderer/extensions/event_bindings.h"
#include <map>
#include <set>
#include <string>
#include <vector> #include <vector>
#include "base/basictypes.h" #include "base/basictypes.h"
...@@ -21,7 +24,6 @@ ...@@ -21,7 +24,6 @@
#include "chrome/renderer/extensions/chrome_v8_context_set.h" #include "chrome/renderer/extensions/chrome_v8_context_set.h"
#include "chrome/renderer/extensions/chrome_v8_extension.h" #include "chrome/renderer/extensions/chrome_v8_extension.h"
#include "chrome/renderer/extensions/dispatcher.h" #include "chrome/renderer/extensions/dispatcher.h"
#include "chrome/renderer/extensions/event_bindings.h"
#include "chrome/renderer/extensions/extension_helper.h" #include "chrome/renderer/extensions/extension_helper.h"
#include "chrome/renderer/extensions/user_script_slave.h" #include "chrome/renderer/extensions/user_script_slave.h"
#include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_thread.h"
...@@ -293,6 +295,11 @@ class ExtensionImpl : public ChromeV8Extension { ...@@ -293,6 +295,11 @@ class ExtensionImpl : public ChromeV8Extension {
v8::Handle<v8::Value> instance_id_value(object->Get(instance_id)); v8::Handle<v8::Value> instance_id_value(object->Get(instance_id));
info.SetInstanceID(instance_id_value->IntegerValue()); info.SetInstanceID(instance_id_value->IntegerValue());
} }
v8::Handle<v8::String> service_type(v8::String::New("serviceType"));
if (object->Has(service_type)) {
v8::Handle<v8::Value> service_type_value(object->Get(service_type));
info.SetServiceType(*v8::String::AsciiValue(service_type_value));
}
return info; return info;
} }
......
...@@ -228,7 +228,7 @@ ...@@ -228,7 +228,7 @@
// Dispatches a named event with the given argument array. The args array is // Dispatches a named event with the given argument array. The args array is
// the list of arguments that will be sent to the event callback. // the list of arguments that will be sent to the event callback.
function dispatchEvent(name, args, filteringInfo) { function dispatchEvent(name, args, filteringInfo) {
var listenerIDs = null; var listenerIDs = [];
if (filteringInfo) if (filteringInfo)
listenerIDs = eventNatives.MatchAgainstEventFilter(name, filteringInfo); listenerIDs = eventNatives.MatchAgainstEventFilter(name, filteringInfo);
...@@ -262,7 +262,11 @@ ...@@ -262,7 +262,11 @@
if (!this.eventOptions_.supportsFilters) if (!this.eventOptions_.supportsFilters)
throw new Error("This event does not support filters."); throw new Error("This event does not support filters.");
if (filters.url && !(filters.url instanceof Array)) if (filters.url && !(filters.url instanceof Array))
throw new Error("filters.url should be an array"); throw new Error("filters.url should be an array.");
if (filters.serviceType &&
!(typeof filters.serviceType === 'string')) {
throw new Error("filters.serviceType should be a string.")
}
} }
var listener = {callback: cb, filters: filters}; var listener = {callback: cb, filters: filters};
this.attach_(listener); this.attach_(listener);
......
{
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8xv6iO+j4kzj1HiBL93+XVJH/CRyAQMUHS/Z0l8nCAzaAFkW/JsNwxJqQhrZspnxLqbQxNncXs6g6bsXAwKHiEs+LSs+bIv0Gc/2ycZdhXJ8GhEsSMakog5dpQd1681c2gLK/8CrAoewE/0GIKhaFcp7a2iZlGh4Am6fgMKy0iQIDAQAB",
"manifest_version": 2,
"name": "MDNS Extension",
"version": "1.0",
"description": "Test MDNS Extension",
"permissions": ["mdns"]
}
// Copyright 2013 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() {
chrome.test.runTests([
function registerListener() {
var numEvents = 0;
chrome.mdns.onServiceList.addListener(function(services) {
if (services[0].serviceName != '_googlecast._tcp.local') {
chrome.test.fail();
return;
} else if (numEvents == 1) {
chrome.test.succeed();
} else {
numEvents++;
}
}, {'serviceType': '_googlecast._tcp.local'});
chrome.test.notifyPass();
}
]);
};
<script src="register_multiple_listeners.js"></script>
// Copyright 2013 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() {
chrome.test.runTests([
function registerListeners() {
var numEvents = 0;
chrome.mdns.onServiceList.addListener(function(services) {
if (numEvents++ == 1) {
chrome.test.succeed();
}
}, {'serviceType': '_googlecast._tcp.local'});
chrome.mdns.onServiceList.addListener(function(services) {
if (numEvents++ == 1) {
chrome.test.succeed();
}
}, {'serviceType': '_testing._tcp.local'});
chrome.test.notifyPass();
}
]);
};
...@@ -38,11 +38,15 @@ scoped_ptr<base::Value> EventFilteringInfo::AsValue() const { ...@@ -38,11 +38,15 @@ scoped_ptr<base::Value> EventFilteringInfo::AsValue() const {
if (has_instance_id_) if (has_instance_id_)
result->SetInteger("instanceId", instance_id_); result->SetInteger("instanceId", instance_id_);
if (!service_type_.empty())
result->SetString("serviceType", service_type_);
return result.PassAs<base::Value>(); return result.PassAs<base::Value>();
} }
bool EventFilteringInfo::IsEmpty() const { bool EventFilteringInfo::IsEmpty() const {
return !has_url_; return !has_url_ && service_type_.empty();
} }
} // namespace extensions } // namespace extensions
...@@ -28,6 +28,9 @@ class EventFilteringInfo { ...@@ -28,6 +28,9 @@ class EventFilteringInfo {
~EventFilteringInfo(); ~EventFilteringInfo();
void SetURL(const GURL& url); void SetURL(const GURL& url);
void SetInstanceID(int instance_id); void SetInstanceID(int instance_id);
void SetServiceType(const std::string& service_type) {
service_type_ = service_type;
}
bool has_url() const { return has_url_; } bool has_url() const { return has_url_; }
const GURL& url() const { return url_; } const GURL& url() const { return url_; }
...@@ -35,12 +38,16 @@ class EventFilteringInfo { ...@@ -35,12 +38,16 @@ class EventFilteringInfo {
bool has_instance_id() const { return has_instance_id_; } bool has_instance_id() const { return has_instance_id_; }
int instance_id() const { return instance_id_; } int instance_id() const { return instance_id_; }
bool has_service_type() const { return !service_type_.empty(); }
const std::string& service_type() const { return service_type_; }
scoped_ptr<base::Value> AsValue() const; scoped_ptr<base::Value> AsValue() const;
bool IsEmpty() const; bool IsEmpty() const;
private: private:
bool has_url_; bool has_url_;
GURL url_; GURL url_;
std::string service_type_;
bool has_instance_id_; bool has_instance_id_;
int instance_id_; int instance_id_;
......
...@@ -12,6 +12,8 @@ const char kUrlFiltersKey[] = "url"; ...@@ -12,6 +12,8 @@ const char kUrlFiltersKey[] = "url";
namespace extensions { namespace extensions {
const char kEventFilterServiceTypeKey[] = "serviceType";
EventMatcher::EventMatcher(scoped_ptr<base::DictionaryValue> filter, EventMatcher::EventMatcher(scoped_ptr<base::DictionaryValue> filter,
int routing_id) int routing_id)
: filter_(filter.Pass()), : filter_(filter.Pass()),
...@@ -23,10 +25,13 @@ EventMatcher::~EventMatcher() { ...@@ -23,10 +25,13 @@ EventMatcher::~EventMatcher() {
bool EventMatcher::MatchNonURLCriteria( bool EventMatcher::MatchNonURLCriteria(
const EventFilteringInfo& event_info) const { const EventFilteringInfo& event_info) const {
if (!event_info.has_instance_id()) if (event_info.has_instance_id()) {
return true; return event_info.instance_id() == GetInstanceID();
}
return event_info.instance_id() == GetInstanceID(); const std::string& service_type_filter = GetServiceTypeFilter();
return service_type_filter.empty() ||
service_type_filter == event_info.service_type();
} }
int EventMatcher::GetURLFilterCount() const { int EventMatcher::GetURLFilterCount() const {
...@@ -48,6 +53,12 @@ int EventMatcher::HasURLFilters() const { ...@@ -48,6 +53,12 @@ int EventMatcher::HasURLFilters() const {
return GetURLFilterCount() != 0; return GetURLFilterCount() != 0;
} }
std::string EventMatcher::GetServiceTypeFilter() const {
std::string service_type_filter;
filter_->GetStringASCII(kEventFilterServiceTypeKey, &service_type_filter);
return service_type_filter;
}
int EventMatcher::GetInstanceID() const { int EventMatcher::GetInstanceID() const {
int instance_id = 0; int instance_id = 0;
filter_->GetInteger("instanceId", &instance_id); filter_->GetInteger("instanceId", &instance_id);
......
...@@ -12,6 +12,8 @@ namespace extensions { ...@@ -12,6 +12,8 @@ namespace extensions {
class EventFilteringInfo; class EventFilteringInfo;
extern const char kEventFilterServiceTypeKey[];
// Matches EventFilteringInfos against a set of criteria. This is intended to // Matches EventFilteringInfos against a set of criteria. This is intended to
// be used by EventFilter which performs efficient URL matching across // be used by EventFilter which performs efficient URL matching across
// potentially many EventMatchers itself. This is why this class only exposes // potentially many EventMatchers itself. This is why this class only exposes
...@@ -29,6 +31,8 @@ class EventMatcher { ...@@ -29,6 +31,8 @@ class EventMatcher {
int GetURLFilterCount() const; int GetURLFilterCount() const;
bool GetURLFilter(int i, base::DictionaryValue** url_filter_out); bool GetURLFilter(int i, base::DictionaryValue** url_filter_out);
std::string GetServiceTypeFilter() const;
int HasURLFilters() const; int HasURLFilters() const;
int GetInstanceID() const; int GetInstanceID() const;
......
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