summaryrefslogtreecommitdiffstats
path: root/chrome/browser/custom_handlers
diff options
context:
space:
mode:
authorkoz@chromium.org <koz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-26 01:30:56 +0000
committerkoz@chromium.org <koz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-26 01:30:56 +0000
commit365dd5b9e48f129f8ebd7e6bd76b1e0754885871 (patch)
tree52f249f608e10ed8d13f4c150f4d55d7a667e380 /chrome/browser/custom_handlers
parentb12f63913575aa06b3820937bc0eca8af072304e (diff)
downloadchromium_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')
-rw-r--r--chrome/browser/custom_handlers/protocol_handler_registry.cc116
-rw-r--r--chrome/browser/custom_handlers/protocol_handler_registry.h27
-rw-r--r--chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc104
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());
+}