diff options
author | koz@chromium.org <koz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-26 01:30:56 +0000 |
---|---|---|
committer | koz@chromium.org <koz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-26 01:30:56 +0000 |
commit | 365dd5b9e48f129f8ebd7e6bd76b1e0754885871 (patch) | |
tree | 52f249f608e10ed8d13f4c150f4d55d7a667e380 /chrome/browser/custom_handlers | |
parent | b12f63913575aa06b3820937bc0eca8af072304e (diff) | |
download | chromium_src-365dd5b9e48f129f8ebd7e6bd76b1e0754885871.zip chromium_src-365dd5b9e48f129f8ebd7e6bd76b1e0754885871.tar.gz chromium_src-365dd5b9e48f129f8ebd7e6bd76b1e0754885871.tar.bz2 |
Handler settings page.
This change implements a settings page that allows users to manage protocol
handlers registered via navigator.registerProtocolHandler.
tony: could you review the ProtocolHandlerRegistry stuff?
estade: could you review the webui stuff?
Thanks!
TEST=Unit tests provided.
Review URL: http://codereview.chromium.org/7033018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@86762 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/custom_handlers')
3 files changed, 202 insertions, 45 deletions
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.cc b/chrome/browser/custom_handlers/protocol_handler_registry.cc index b4991e2..b10ce61 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry.cc +++ b/chrome/browser/custom_handlers/protocol_handler_registry.cc @@ -13,11 +13,12 @@ #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile_io_data.h" #include "chrome/common/pref_names.h" +#include "content/browser/browser_thread.h" #include "content/browser/child_process_security_policy.h" +#include "content/common/notification_service.h" #include "net/base/network_delegate.h" #include "net/url_request/url_request_redirect_job.h" - // ProtocolHandlerRegistry ----------------------------------------------------- ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile, @@ -30,13 +31,14 @@ ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile, ProtocolHandlerRegistry::~ProtocolHandlerRegistry() { } -ProtocolHandlerRegistry::ProtocolHandlerList& -ProtocolHandlerRegistry::GetHandlerListFor(const std::string& scheme) { - ProtocolHandlerMultiMap::iterator p = protocol_handlers_.find(scheme); +const ProtocolHandlerRegistry::ProtocolHandlerList* +ProtocolHandlerRegistry::GetHandlersFor( + const std::string& scheme) const { + ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); if (p == protocol_handlers_.end()) { - protocol_handlers_[scheme] = ProtocolHandlerList(); + return NULL; } - return protocol_handlers_[scheme]; + return &p->second; } void ProtocolHandlerRegistry::RegisterProtocolHandler( @@ -49,7 +51,22 @@ void ProtocolHandlerRegistry::RegisterProtocolHandler( if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol())) { delegate_->RegisterExternalHandler(handler.protocol()); } - GetHandlerListFor(handler.protocol()).push_back(handler); + InsertHandler(handler); + NotifyChanged(); +} + +void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) { + ProtocolHandlerMultiMap::iterator p = + protocol_handlers_.find(handler.protocol()); + + if (p != protocol_handlers_.end()) { + p->second.push_back(handler); + return; + } + + ProtocolHandlerList new_list; + new_list.push_back(handler); + protocol_handlers_[handler.protocol()] = new_list; } void ProtocolHandlerRegistry::IgnoreProtocolHandler( @@ -66,6 +83,7 @@ void ProtocolHandlerRegistry::Enable() { p != protocol_handlers_.end(); ++p) { delegate_->RegisterExternalHandler(p->first); } + NotifyChanged(); } void ProtocolHandlerRegistry::Disable() { @@ -77,6 +95,7 @@ void ProtocolHandlerRegistry::Disable() { p != protocol_handlers_.end(); ++p) { delegate_->DeregisterExternalHandler(p->first); } + NotifyChanged(); } std::vector<const DictionaryValue*> @@ -161,24 +180,32 @@ void ProtocolHandlerRegistry::GetHandledProtocols( std::vector<std::string>* output) const { ProtocolHandlerMultiMap::const_iterator p; for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) { - output->push_back(p->first); + if (!p->second.empty()) { + output->push_back(p->first); + } } } void ProtocolHandlerRegistry::RemoveIgnoredHandler( const ProtocolHandler& handler) { - for (ProtocolHandlerList::iterator p = ignored_protocol_handlers_.begin(); - p != ignored_protocol_handlers_.end(); ++p) { - if (handler == *p) { - ignored_protocol_handlers_.erase(p); - break; - } + ProtocolHandlerList::iterator p = + std::find(ignored_protocol_handlers_.begin(), + ignored_protocol_handlers_.end(), handler); + if (p != ignored_protocol_handlers_.end()) { + ignored_protocol_handlers_.erase(p); + Save(); + NotifyChanged(); } } -bool ProtocolHandlerRegistry::IsRegistered(const ProtocolHandler& handler) { - ProtocolHandlerList& handlers(GetHandlerListFor(handler.protocol())); - return std::find(handlers.begin(), handlers.end(), handler) != handlers.end(); +bool ProtocolHandlerRegistry::IsRegistered( + const ProtocolHandler& handler) const { + const ProtocolHandlerList* handlers = GetHandlersFor(handler.protocol()); + if (!handlers) { + return false; + } + return std::find(handlers->begin(), handlers->end(), handler) != + handlers->end(); } bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const { @@ -194,21 +221,27 @@ bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const { bool ProtocolHandlerRegistry::IsHandledProtocol( const std::string& scheme) const { - return protocol_handlers_.find(scheme) != protocol_handlers_.end(); + return !GetHandlerFor(scheme).IsEmpty(); } void ProtocolHandlerRegistry::RemoveHandler(const ProtocolHandler& handler) { - ProtocolHandlerList& handlers(GetHandlerListFor(handler.protocol())); + ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()]; ProtocolHandlerList::iterator p = std::find(handlers.begin(), handlers.end(), handler); if (p != handlers.end()) { handlers.erase(p); } - ProtocolHandlerMap::iterator it = default_handlers_.find(handler.protocol()); - if (it != default_handlers_.end() && it->second == handler) { - default_handlers_.erase(it); + ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol()); + if (q != default_handlers_.end() && q->second == handler) { + default_handlers_.erase(q); + } + + if (!IsHandledProtocol(handler.protocol())) { + delegate_->DeregisterExternalHandler(handler.protocol()); } + Save(); + NotifyChanged(); } net::URLRequestJob* ProtocolHandlerRegistry::MaybeCreateJob( @@ -284,11 +317,13 @@ void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) { default_handlers_.erase(handler.protocol()); default_handlers_.insert(std::make_pair(handler.protocol(), handler)); Save(); + NotifyChanged(); } void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) { default_handlers_.erase(scheme); Save(); + NotifyChanged(); } bool ProtocolHandlerRegistry::IsDefault(const ProtocolHandler& handler) const { @@ -301,12 +336,28 @@ const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor( if (p != default_handlers_.end()) { return p->second; } - ProtocolHandlerMultiMap::const_iterator q = - protocol_handlers_.find(scheme); - if (q != protocol_handlers_.end() && q->second.size() == 1) { - return q->second[0]; + ProtocolHandlerMultiMap::const_iterator q = protocol_handlers_.find(scheme); + if (q == protocol_handlers_.end() || q->second.empty()) { + return ProtocolHandler::EmptyProtocolHandler(); + } + return q->second.back(); +} + +int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const { + const ProtocolHandler& handler = GetHandlerFor(scheme); + const ProtocolHandlerList* handlers = GetHandlersFor(scheme); + if (!handlers) { + return -1; + } + + ProtocolHandlerList::const_iterator p; + int i; + for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) { + if (*p == handler) { + return i; + } } - return ProtocolHandler::EmptyProtocolHandler(); + return -1; } bool ProtocolHandlerRegistry::HasDefault( @@ -314,8 +365,15 @@ bool ProtocolHandlerRegistry::HasDefault( return !GetHandlerFor(scheme).IsEmpty(); } -bool ProtocolHandlerRegistry::HasHandler(const std::string& scheme) { - return !GetHandlerListFor(scheme).empty(); +void ProtocolHandlerRegistry::NotifyChanged() { + if (is_loading_) + return; + + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + NotificationService::current()->Notify( + NotificationType::PROTOCOL_HANDLER_REGISTRY_CHANGED, + Source<Profile>(profile_), + NotificationService::NoDetails()); } // Delegate -------------------------------------------------------------------- diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.h b/chrome/browser/custom_handlers/protocol_handler_registry.h index eaeb0c6..500b551 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry.h +++ b/chrome/browser/custom_handlers/protocol_handler_registry.h @@ -15,6 +15,7 @@ #include "base/values.h" #include "chrome/browser/custom_handlers/protocol_handler.h" #include "chrome/browser/profiles/profile.h" +#include "content/common/notification_service.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_job.h" @@ -38,6 +39,10 @@ class ProtocolHandlerRegistry virtual bool IsExternalHandlerRegistered(const std::string& protocol); }; + typedef std::map<std::string, ProtocolHandler> ProtocolHandlerMap; + typedef std::vector<ProtocolHandler> ProtocolHandlerList; + typedef std::map<std::string, ProtocolHandlerList> ProtocolHandlerMultiMap; + ProtocolHandlerRegistry(Profile* profile, Delegate* delegate); ~ProtocolHandlerRegistry(); @@ -64,9 +69,6 @@ class ProtocolHandlerRegistry // it. bool HasDefault(const std::string& scheme) const; - // Returns true if there is a handler registered for the given protocol. - bool HasHandler(const std::string& scheme); - // Loads a user's registered protocol handlers. void Load(); @@ -77,6 +79,13 @@ class ProtocolHandlerRegistry // exists. const ProtocolHandler& GetHandlerFor(const std::string& scheme) const; + // Returns the offset in the list of handlers for a protocol of the default + // handler for that protocol. + int GetHandlerIndex(const std::string& scheme) const; + + // Get the list of protocol handlers for the given scheme. + const ProtocolHandlerList* GetHandlersFor(const std::string& scheme) const; + // Yields a list of the protocols handled by this registry. void GetHandledProtocols(std::vector<std::string>* output) const; @@ -85,7 +94,7 @@ class ProtocolHandlerRegistry bool CanSchemeBeOverridden(const std::string& scheme) const; // Returns true if an identical protocol handler has already been registered. - bool IsRegistered(const ProtocolHandler& handler); + bool IsRegistered(const ProtocolHandler& handler) const; // Returns true if the protocol handler is being ignored. bool IsIgnored(const ProtocolHandler& handler) const; @@ -119,9 +128,8 @@ class ProtocolHandlerRegistry private: friend class base::RefCountedThreadSafe<ProtocolHandlerRegistry>; - typedef std::map<std::string, ProtocolHandler> ProtocolHandlerMap; - typedef std::vector<ProtocolHandler> ProtocolHandlerList; - typedef std::map<std::string, ProtocolHandlerList> ProtocolHandlerMultiMap; + // Insert the given ProtocolHandler into the registry. + void InsertHandler(const ProtocolHandler& handler); // Returns a JSON list of protocol handlers. The caller is responsible for // deleting this Value. @@ -131,6 +139,9 @@ class ProtocolHandlerRegistry // responsible for deleting this Value. Value* EncodeIgnoredHandlers(); + // Sends a notification of the given type to the NotificationService. + void NotifyChanged(); + // Registers a new protocol handler. void RegisterProtocolHandler(const ProtocolHandler& handler); @@ -148,8 +159,6 @@ class ProtocolHandlerRegistry // Register void IgnoreHandlerFromValue(const DictionaryValue* value); - ProtocolHandlerList& GetHandlerListFor(const std::string& scheme); - // Map from protocols (strings) to protocol handlers. ProtocolHandlerMultiMap protocol_handlers_; diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc index 5613be7..60e3036 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc +++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc @@ -12,6 +12,8 @@ #include "chrome/test/testing_browser_process_test.h" #include "chrome/test/testing_pref_service.h" #include "chrome/test/testing_profile.h" +#include "content/browser/browser_thread.h" +#include "content/browser/renderer_host/test_render_view_host.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" #include "content/common/notification_service.h" @@ -40,11 +42,39 @@ class FakeDelegate : public ProtocolHandlerRegistry::Delegate { std::set<std::string> registered_protocols_; }; +class NotificationCounter : public NotificationObserver { + public: + NotificationCounter() + : events_(0), + notification_registrar_() { + notification_registrar_.Add(this, + NotificationType::PROTOCOL_HANDLER_REGISTRY_CHANGED, + NotificationService::AllSources()); + } + + ~NotificationCounter() { + notification_registrar_.Remove(this, + NotificationType::PROTOCOL_HANDLER_REGISTRY_CHANGED, + NotificationService::AllSources()); + } + + int events() { return events_; } + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + ++events_; + } -class ProtocolHandlerRegistryTest : public testing::Test { + int events_; + NotificationRegistrar notification_registrar_; +}; + + +class ProtocolHandlerRegistryTest : public RenderViewHostTestHarness { protected: ProtocolHandlerRegistryTest() - : test_protocol_handler_(CreateProtocolHandler("test", "test")) {} + : ui_thread_(BrowserThread::UI, MessageLoop::current()), + test_protocol_handler_(CreateProtocolHandler("test", "test")) {} FakeDelegate* delegate() const { return delegate_; } TestingProfile* profile() const { return profile_.get(); } @@ -84,6 +114,7 @@ class ProtocolHandlerRegistryTest : public testing::Test { ProtocolHandlerRegistry::RegisterPrefs(pref_service()); } + BrowserThread ui_thread_; FakeDelegate* delegate_; scoped_ptr<TestingProfile> profile_; scoped_refptr<ProtocolHandlerRegistry> registry_; @@ -141,6 +172,13 @@ TEST_F(ProtocolHandlerRegistryTest, ASSERT_FALSE(registry()->CanSchemeBeOverridden("test")); } +TEST_F(ProtocolHandlerRegistryTest, RemovingHandlerMeansItCanBeAddedAgain) { + registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler()); + ASSERT_TRUE(registry()->CanSchemeBeOverridden("test")); + registry()->RemoveHandler(test_protocol_handler()); + ASSERT_TRUE(registry()->CanSchemeBeOverridden("test")); +} + TEST_F(ProtocolHandlerRegistryTest, TestStartsAsDefault) { registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler()); ASSERT_TRUE(registry()->IsDefault(test_protocol_handler())); @@ -159,9 +197,10 @@ TEST_F(ProtocolHandlerRegistryTest, TestClearDefault) { registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->OnAcceptRegisterProtocolHandler(ph2); - registry()->SetDefault(ph2); + registry()->SetDefault(ph1); registry()->ClearDefault("test"); - ASSERT_FALSE(registry()->IsDefault(ph2)); + ASSERT_FALSE(registry()->IsDefault(ph1)); + ASSERT_TRUE(registry()->IsDefault(ph2)); } TEST_F(ProtocolHandlerRegistryTest, TestGetHandlerFor) { @@ -175,13 +214,13 @@ TEST_F(ProtocolHandlerRegistryTest, TestGetHandlerFor) { ASSERT_TRUE(registry()->HasDefault("test")); } -TEST_F(ProtocolHandlerRegistryTest, TestMultipleHandlersClearsDefault) { +TEST_F(ProtocolHandlerRegistryTest, TestMostRecentHandlerIsDefault) { ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); ProtocolHandler ph2 = CreateProtocolHandler("test", "test2"); registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->OnAcceptRegisterProtocolHandler(ph2); ASSERT_FALSE(registry()->IsDefault(ph1)); - ASSERT_FALSE(registry()->IsDefault(ph2)); + ASSERT_TRUE(registry()->IsDefault(ph2)); } TEST_F(ProtocolHandlerRegistryTest, TestSetDefault) { @@ -220,7 +259,7 @@ TEST_F(ProtocolHandlerRegistryTest, TestRemoveHandler) { registry()->RemoveHandler(ph1); ASSERT_FALSE(registry()->IsRegistered(ph1)); - ASSERT_FALSE(registry()->HasHandler("test")); + ASSERT_FALSE(registry()->IsHandledProtocol("test")); } TEST_F(ProtocolHandlerRegistryTest, TestIsRegistered) { @@ -236,6 +275,7 @@ TEST_F(ProtocolHandlerRegistryTest, TestRemoveHandlerRemovesDefault) { ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); ProtocolHandler ph2 = CreateProtocolHandler("test", "test2"); ProtocolHandler ph3 = CreateProtocolHandler("test", "test3"); + registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->OnAcceptRegisterProtocolHandler(ph2); registry()->OnAcceptRegisterProtocolHandler(ph3); @@ -244,3 +284,53 @@ TEST_F(ProtocolHandlerRegistryTest, TestRemoveHandlerRemovesDefault) { registry()->RemoveHandler(ph1); ASSERT_FALSE(registry()->IsDefault(ph1)); } + +TEST_F(ProtocolHandlerRegistryTest, TestGetHandlersFor) { + ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); + ProtocolHandler ph2 = CreateProtocolHandler("test", "test2"); + ProtocolHandler ph3 = CreateProtocolHandler("test", "test3"); + registry()->OnAcceptRegisterProtocolHandler(ph1); + registry()->OnAcceptRegisterProtocolHandler(ph2); + registry()->OnAcceptRegisterProtocolHandler(ph3); + + const ProtocolHandlerRegistry::ProtocolHandlerList* handlers = + registry()->GetHandlersFor("test"); + ASSERT_TRUE(handlers != NULL); + ASSERT_EQ(ph1, (*handlers)[0]); + ASSERT_EQ(ph2, (*handlers)[1]); + ASSERT_EQ(ph3, (*handlers)[2]); +} + +TEST_F(ProtocolHandlerRegistryTest, TestGetHandledProtocols) { + std::vector<std::string> protocols; + registry()->GetHandledProtocols(&protocols); + ASSERT_EQ((size_t) 0, protocols.size()); + + registry()->GetHandlersFor("test"); + + protocols.clear(); + registry()->GetHandledProtocols(&protocols); + ASSERT_EQ((size_t) 0, protocols.size()); +} + +TEST_F(ProtocolHandlerRegistryTest, TestIsHandledProtocol) { + registry()->GetHandlersFor("test"); + ASSERT_FALSE(registry()->IsHandledProtocol("test")); +} + +TEST_F(ProtocolHandlerRegistryTest, TestNotifications) { + ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); + NotificationCounter counter; + + registry()->OnAcceptRegisterProtocolHandler(ph1); + ASSERT_EQ(1, counter.events()); + + registry()->Disable(); + ASSERT_EQ(2, counter.events()); + + registry()->Enable(); + ASSERT_EQ(3, counter.events()); + + registry()->RemoveHandler(ph1); + ASSERT_EQ(4, counter.events()); +} |