diff options
Diffstat (limited to 'chrome/browser/custom_handlers')
5 files changed, 198 insertions, 478 deletions
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.cc b/chrome/browser/custom_handlers/protocol_handler_registry.cc index 712f791..5a6dfae 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry.cc +++ b/chrome/browser/custom_handlers/protocol_handler_registry.cc @@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/logging.h" -#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h" #include "chrome/browser/net/chrome_url_request_context.h" @@ -22,30 +21,14 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/notification_service.h" -#include "grit/generated_resources.h" #include "net/base/network_delegate.h" -#include "net/url_request/url_request.h" -#include "net/url_request/url_request_job.h" #include "net/url_request/url_request_redirect_job.h" -#include "ui/base/l10n/l10n_util.h" using content::BrowserThread; using content::ChildProcessSecurityPolicy; namespace { -const ProtocolHandler& LookupHandler( - const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map, - const std::string& scheme) { - ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p = - handler_map.find(scheme); - - if (p != handler_map.end()) - return p->second; - - return ProtocolHandler::EmptyProtocolHandler(); -} - // If true default protocol handlers will be removed if the OS level // registration for a protocol is no longer Chrome. bool ShouldRemoveHandlersNotInOS() { @@ -61,165 +44,17 @@ bool ShouldRemoveHandlersNotInOS() { #endif } -void InstallDefaultProtocolHandlers(ProtocolHandlerRegistry* registry) { - // Only chromeos has default protocol handlers at this point. - #if defined(OS_CHROMEOS) - registry->AddPredefinedHandler( - ProtocolHandler::CreateProtocolHandler( - "mailto", - GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_MAILTO_HANDLER_URL)), - l10n_util::GetStringUTF16(IDS_GOOGLE_MAILTO_HANDLER_NAME))); - registry->AddPredefinedHandler( - ProtocolHandler::CreateProtocolHandler( - "webcal", - GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL)), - l10n_util::GetStringUTF16(IDS_GOOGLE_WEBCAL_HANDLER_NAME))); - #endif -} - -} // namespace - -// Core ------------------------------------------------------------------------ - -// Core is an IO thread specific object. Access to the class should all -// be done via the IO thread. The registry living on the UI thread makes -// a best effort to update the IO object after local updates are completed. -class ProtocolHandlerRegistry::Core - : public base::RefCountedThreadSafe<ProtocolHandlerRegistry::Core> { - public: - - // Creates a new instance. If |enabled| is true the registry is considered - // enabled on the IO thread. - explicit Core(bool enabled); - - // Returns true if the protocol has a default protocol handler. - // Should be called only from the IO thread. - bool IsHandledProtocol(const std::string& scheme) const; - - // Clears the default for the provided protocol. - // Should be called only from the IO thread. - void ClearDefault(const std::string& scheme); - - // Makes this ProtocolHandler the default handler for its protocol. - // Should be called only from the IO thread. - void SetDefault(const ProtocolHandler& handler); - - // Creates a URL request job for the given request if there is a matching - // protocol handler, returns NULL otherwise. - net::URLRequestJob* MaybeCreateJob(net::URLRequest* request) const; - - // Indicate that the registry has been enabled in the IO thread's - // copy of the data. - void Enable() { enabled_ = true; } - - // Indicate that the registry has been disabled in the IO thread's copy of - // the data. - void Disable() { enabled_ = false; } - - private: - friend class base::RefCountedThreadSafe<Core>; - virtual ~Core(); - - // Copy of protocol handlers use only on the IO thread. - ProtocolHandlerRegistry::ProtocolHandlerMap default_handlers_; - - // Is the registry enabled on the IO thread. - bool enabled_; - - DISALLOW_COPY_AND_ASSIGN(Core); -}; - -ProtocolHandlerRegistry::Core::Core(bool) : enabled_(true) {} -ProtocolHandlerRegistry::Core::~Core() {} - -bool ProtocolHandlerRegistry::Core::IsHandledProtocol( - const std::string& scheme) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - return enabled_ && !LookupHandler(default_handlers_, scheme).IsEmpty(); -} - -void ProtocolHandlerRegistry::Core::ClearDefault(const std::string& scheme) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - default_handlers_.erase(scheme); -} - -void ProtocolHandlerRegistry::Core::SetDefault(const ProtocolHandler& handler) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - ClearDefault(handler.protocol()); - default_handlers_.insert(std::make_pair(handler.protocol(), handler)); -} - -// Create a new job for the supplied |URLRequest| if a default handler -// is registered and the associated handler is able to interpret -// the url from |request|. -net::URLRequestJob* ProtocolHandlerRegistry::Core::MaybeCreateJob( - net::URLRequest* request) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - ProtocolHandler handler = LookupHandler(default_handlers_, - request->url().scheme()); - if (handler.IsEmpty()) - return NULL; - - GURL translated_url(handler.TranslateUrl(request->url())); - if (!translated_url.is_valid()) - return NULL; - - return new net::URLRequestRedirectJob(request, translated_url); -} - -// URLInterceptor ------------------------------------------------------------ - -// Instances of this class are produced for ownership by the IO -// thread where it handler URL requests. We should never hold -// any pointers on this class, only produce them in response to -// requests via |ProtocolHandlerRegistry::CreateURLInterceptor|. -class ProtocolHandlerRegistry::URLInterceptor - : public net::URLRequestJobFactory::Interceptor { - public: - explicit URLInterceptor(Core* core); - virtual ~URLInterceptor(); - - virtual net::URLRequestJob* MaybeIntercept( - net::URLRequest* request) const OVERRIDE; - - virtual bool WillHandleProtocol(const std::string& protocol) const OVERRIDE; - - virtual net::URLRequestJob* MaybeInterceptRedirect( - const GURL& url, net::URLRequest* request) const OVERRIDE { - return NULL; - } +} // namespace - virtual net::URLRequestJob* MaybeInterceptResponse( - net::URLRequest* request) const OVERRIDE { - return NULL; +static const ProtocolHandler& LookupHandler( + const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map, + const std::string& scheme) { + ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p = + handler_map.find(scheme); + if (p != handler_map.end()) { + return p->second; } - - private: - scoped_refptr<Core> core_; - DISALLOW_COPY_AND_ASSIGN(URLInterceptor); -}; - -ProtocolHandlerRegistry::URLInterceptor::URLInterceptor(Core* core) - : core_(core) { - DCHECK(core_); -} - -ProtocolHandlerRegistry::URLInterceptor::~URLInterceptor() { -} - -net::URLRequestJob* ProtocolHandlerRegistry::URLInterceptor::MaybeIntercept( - net::URLRequest* request) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - return core_->MaybeCreateJob(request); -} - -bool ProtocolHandlerRegistry::URLInterceptor::WillHandleProtocol( - const std::string& protocol) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - return core_->IsHandledProtocol(protocol); + return ProtocolHandler::EmptyProtocolHandler(); } // DefaultClientObserver ------------------------------------------------------ @@ -241,7 +76,8 @@ ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() { registry_->default_client_observers_.erase(iter); } -void ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState( +void +ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState( ShellIntegration::DefaultWebClientUIState state) { if (worker_) { if (ShouldRemoveHandlersNotInOS() && @@ -315,9 +151,9 @@ ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile, : profile_(profile), delegate_(delegate), enabled_(true), + enabled_io_(enabled_), is_loading_(false), - is_loaded_(false), - core_(new Core(enabled_)){ + is_loaded_(false) { } bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest( @@ -397,12 +233,11 @@ ProtocolHandlerRegistry::GetReplacedHandlers( void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - default_handlers_.erase(scheme); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&Core::ClearDefault, core_, scheme)); + base::Bind(&ProtocolHandlerRegistry::ClearDefaultIO, this, scheme)); Save(); NotifyChanged(); } @@ -413,23 +248,19 @@ bool ProtocolHandlerRegistry::IsDefault( return GetHandlerFor(handler.protocol()) == handler; } -void ProtocolHandlerRegistry::InitProtocolSettings() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // Default protocol handlers must be installed first. - InstallDefaultProtocolHandlers(this); - +void ProtocolHandlerRegistry::Load() { // Any further default additions to the table will get rejected from now on. is_loaded_ = true; + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); is_loading_ = true; - PrefService* prefs = profile_->GetPrefs(); if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) { - if (prefs->GetBoolean(prefs::kCustomHandlersEnabled)) { - Enable(); - } else { - Disable(); - } + enabled_ = prefs->GetBoolean(prefs::kCustomHandlersEnabled); + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(enabled_ ? &ProtocolHandlerRegistry::EnableIO : + &ProtocolHandlerRegistry::DisableIO, this)); } std::vector<const DictionaryValue*> registered_handlers = GetHandlersFromPref(prefs::kRegisteredProtocolHandlers); @@ -597,6 +428,12 @@ bool ProtocolHandlerRegistry::IsHandledProtocol( return enabled_ && !GetHandlerFor(scheme).IsEmpty(); } +bool ProtocolHandlerRegistry::IsHandledProtocolIO( + const std::string& scheme) const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + return enabled_io_ && !LookupHandler(default_handlers_io_, scheme).IsEmpty(); +} + void ProtocolHandlerRegistry::RemoveHandler( const ProtocolHandler& handler) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -615,8 +452,8 @@ void ProtocolHandlerRegistry::RemoveHandler( } else { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&Core::ClearDefault, core_, q->second.protocol())); - + base::Bind(&ProtocolHandlerRegistry::ClearDefaultIO, this, + q->second.protocol())); default_handlers_.erase(q); } } @@ -641,6 +478,21 @@ const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor( return LookupHandler(default_handlers_, scheme); } +net::URLRequestJob* ProtocolHandlerRegistry::MaybeCreateJob( + net::URLRequest* request) const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + ProtocolHandler handler = LookupHandler(default_handlers_io_, + request->url().scheme()); + if (handler.IsEmpty()) { + return NULL; + } + GURL translated_url(handler.TranslateUrl(request->url())); + if (!translated_url.is_valid()) { + return NULL; + } + return new net::URLRequestRedirectJob(request, translated_url); +} + void ProtocolHandlerRegistry::Enable() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (enabled_) { @@ -650,8 +502,7 @@ void ProtocolHandlerRegistry::Enable() { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&Core::Enable, core_)); - + base::Bind(&ProtocolHandlerRegistry::EnableIO, this)); ProtocolHandlerMap::const_iterator p; for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { delegate_->RegisterExternalHandler(p->first); @@ -669,8 +520,7 @@ void ProtocolHandlerRegistry::Disable() { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&Core::Disable, core_)); - + base::Bind(&ProtocolHandlerRegistry::DisableIO, this)); ProtocolHandlerMap::const_iterator p; for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { delegate_->DeregisterExternalHandler(p->first); @@ -679,7 +529,7 @@ void ProtocolHandlerRegistry::Disable() { NotifyChanged(); } -void ProtocolHandlerRegistry::Shutdown() { +void ProtocolHandlerRegistry::Finalize() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); delegate_.reset(NULL); // We free these now in case there are any outstanding workers running. If @@ -703,7 +553,7 @@ void ProtocolHandlerRegistry::RegisterPrefs(PrefService* pref_service) { } ProtocolHandlerRegistry::~ProtocolHandlerRegistry() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(default_client_observers_.empty()); } @@ -717,6 +567,17 @@ void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) { list.insert(list.begin(), handler); } +void ProtocolHandlerRegistry::ClearDefaultIO(const std::string& scheme) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + default_handlers_io_.erase(scheme); +} + +void ProtocolHandlerRegistry::SetDefaultIO(const ProtocolHandler& handler) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + ClearDefaultIO(handler.protocol()); + default_handlers_io_.insert(std::make_pair(handler.protocol(), handler)); +} + void ProtocolHandlerRegistry::Save() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (is_loading_) { @@ -757,7 +618,7 @@ void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&Core::SetDefault, core_, handler)); + base::Bind(&ProtocolHandlerRegistry::SetDefaultIO, this, handler)); } void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) { @@ -854,16 +715,10 @@ void ProtocolHandlerRegistry::IgnoreProtocolHandler( void ProtocolHandlerRegistry::AddPredefinedHandler( const ProtocolHandler& handler) { - DCHECK(!is_loaded_); // Must be called prior InitProtocolSettings. + // If called after the load command was issued this function will fail. + DCHECK(!is_loaded_); RegisterProtocolHandler(handler); SetDefault(handler); } -net::URLRequestJobFactory::Interceptor* - ProtocolHandlerRegistry::CreateURLInterceptor() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // this is always created on the UI thread (in profile_io's - // InitializeOnUIThread. Any method calls must be done - // on the IO thread (this is checked). - return new URLInterceptor(core_); -} + diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.h b/chrome/browser/custom_handlers/protocol_handler_registry.h index 82f608db..a74a765 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry.h +++ b/chrome/browser/custom_handlers/protocol_handler_registry.h @@ -20,18 +20,17 @@ #include "content/public/browser/notification_service.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_job.h" -#include "net/url_request/url_request_job_factory.h" // This is where handlers for protocols registered with // navigator.registerProtocolHandler() are registered. Each Profile owns an // instance of this class, which is initialized on browser start through // Profile::InitRegisteredProtocolHandlers(), and they should be the only // instances of this class. -class ProtocolHandlerRegistry : public ProfileKeyedService { +class ProtocolHandlerRegistry + : public base::RefCountedThreadSafe< + ProtocolHandlerRegistry, content::BrowserThread::DeleteOnIOThread> { public: - // Provides notification of when the OS level user agent settings - // are changed. class DefaultClientObserver : public ShellIntegration::DefaultWebClientObserver { public: @@ -60,9 +59,9 @@ class ProtocolHandlerRegistry : public ProfileKeyedService { DISALLOW_COPY_AND_ASSIGN(DefaultClientObserver); }; - // |Delegate| provides an interface for interacting asynchronously - // with the underlying OS for the purposes of registering Chrome - // as the default handler for specific protocols. + // TODO(koz): Refactor this to eliminate the unnecessary virtuals. All that + // should be needed is a way to ensure that the list of websafe protocols is + // updated. class Delegate { public: virtual ~Delegate(); @@ -84,14 +83,7 @@ class ProtocolHandlerRegistry : public ProfileKeyedService { typedef std::map<std::string, ProtocolHandlerList> ProtocolHandlerMultiMap; typedef std::vector<DefaultClientObserver*> DefaultClientObserverList; - // Creates a new instance. Assumes ownership of |delegate|. ProtocolHandlerRegistry(Profile* profile, Delegate* delegate); - virtual ~ProtocolHandlerRegistry(); - - // Returns a net::URLRequestJobFactory::Interceptor suitable - // for use on the IO thread, but is initialized on the UI thread. - // Callers assume responsibility for deleting this object. - net::URLRequestJobFactory::Interceptor* CreateURLInterceptor(); // Called when a site tries to register as a protocol handler. If the request // can be handled silently by the registry - either to ignore the request @@ -124,10 +116,8 @@ class ProtocolHandlerRegistry : public ProfileKeyedService { // Returns true if this handler is the default handler for its protocol. bool IsDefault(const ProtocolHandler& handler) const; - // Initializes default protocol settings and loads them from prefs. - // This method must be called to complete initialization of the - // registry after creation, and prior to use. - void InitProtocolSettings(); + // Loads a user's registered protocol handlers. + void Load(); // Returns the offset in the list of handlers for a protocol of the default // handler for that protocol. @@ -165,6 +155,10 @@ class ProtocolHandlerRegistry : public ProfileKeyedService { // Returns true if the protocol has a default protocol handler. bool IsHandledProtocol(const std::string& scheme) const; + // Returns true if the protocol has a default protocol handler. + // Should be called only from the IO thread. + bool IsHandledProtocolIO(const std::string& scheme) const; + // Removes the given protocol handler from the registry. void RemoveHandler(const ProtocolHandler& handler); @@ -175,6 +169,10 @@ class ProtocolHandlerRegistry : public ProfileKeyedService { // exists. const ProtocolHandler& GetHandlerFor(const std::string& scheme) const; + // Creates a URL request job for the given request if there is a matching + // protocol handler, returns NULL otherwise. + net::URLRequestJob* MaybeCreateJob(net::URLRequest* request) const; + // Puts this registry in the enabled state - registered protocol handlers // will handle requests. void Enable(); @@ -185,7 +183,7 @@ class ProtocolHandlerRegistry : public ProfileKeyedService { // This is called by the UI thread when the system is shutting down. This // does finalization which must be done on the UI thread. - virtual void Shutdown() OVERRIDE; + void Finalize(); // Registers the preferences that we store registered protocol handlers in. static void RegisterPrefs(PrefService* prefService); @@ -203,14 +201,28 @@ class ProtocolHandlerRegistry : public ProfileKeyedService { friend class ProtocolHandlerRegistryTest; friend class RegisterProtocolHandlerBrowserTest; - // Forward declaration of the internal implementation classes. - class Core; - class URLInterceptor; + ~ProtocolHandlerRegistry(); // Puts the given handler at the top of the list of handlers for its // protocol. void PromoteHandler(const ProtocolHandler& handler); + // Clears the default for the provided protocol. + // Should be called only from the IO thread. + void ClearDefaultIO(const std::string& scheme); + + // Makes this ProtocolHandler the default handler for its protocol. + // Should be called only from the IO thread. + void SetDefaultIO(const ProtocolHandler& handler); + + // Indicate that the registry has been enabled in the IO thread's copy of the + // data. + void EnableIO() { enabled_io_ = true; } + + // Indicate that the registry has been disabled in the IO thread's copy of + // the data. + void DisableIO() { enabled_io_ = false; } + // Saves a user's registered protocol handlers. void Save(); @@ -265,6 +277,9 @@ class ProtocolHandlerRegistry : public ProfileKeyedService { // requests. bool enabled_; + // Copy of enabled_ that is only accessed on the IO thread. + bool enabled_io_; + // Whether or not we are loading. bool is_loading_; @@ -272,12 +287,11 @@ class ProtocolHandlerRegistry : public ProfileKeyedService { // AddPredefinedHandler will be rejected. bool is_loaded_; - // Copy of registry data for use on the IO thread. Changes to the registry - // are posted to the IO thread where updates are applied to this object. - scoped_refptr<Core> core_; - DefaultClientObserverList default_client_observers_; + // Copy of default_handlers_ that is only accessed on the IO thread. + ProtocolHandlerMap default_handlers_io_; + DISALLOW_COPY_AND_ASSIGN(ProtocolHandlerRegistry); }; #endif // CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_H_ diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc b/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc deleted file mode 100644 index 63a3548..0000000 --- a/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2012 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/custom_handlers/protocol_handler_registry_factory.h" - -#include "base/memory/singleton.h" -#include "chrome/browser/custom_handlers/protocol_handler_registry.h" -#include "chrome/browser/extensions/extension_system_factory.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_dependency_manager.h" - -// static -ProtocolHandlerRegistryFactory* ProtocolHandlerRegistryFactory::GetInstance() { - return Singleton<ProtocolHandlerRegistryFactory>::get(); -} - -// static -ProtocolHandlerRegistry* ProtocolHandlerRegistryFactory::GetForProfile( - Profile* profile) { - return static_cast<ProtocolHandlerRegistry*>( - GetInstance()->GetServiceForProfile(profile, true)); -} - -ProtocolHandlerRegistryFactory::ProtocolHandlerRegistryFactory() - : ProfileKeyedServiceFactory("ProtocolHandlerRegistry", - ProfileDependencyManager::GetInstance()) { -} - -ProtocolHandlerRegistryFactory::~ProtocolHandlerRegistryFactory() { -} - -// Will be created when initializing profile_io_data, so we might -// as well have the framework create this along with other -// PKSs to preserve orderly civic conduct :) -bool ProtocolHandlerRegistryFactory::ServiceIsCreatedWithProfile() { - return true; -} - -// Allows the produced registry to be used in incognito mode. -bool ProtocolHandlerRegistryFactory::ServiceRedirectedInIncognito() { - return true; -} - -// Do not create this service for tests. MANY tests will fail -// due to the threading requirements of this service. ALSO, -// not creating this increases test isolation (which is GOOD!) -bool ProtocolHandlerRegistryFactory::ServiceIsNULLWhileTesting() { - return true; -} - -ProfileKeyedService* ProtocolHandlerRegistryFactory::BuildServiceInstanceFor( - Profile* profile) const { - ProtocolHandlerRegistry* registry = new ProtocolHandlerRegistry( - profile, new ProtocolHandlerRegistry::Delegate()); - - // Must be called as a part of the creation process. - registry->InitProtocolSettings(); - - return registry; -} diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_factory.h b/chrome/browser/custom_handlers/protocol_handler_registry_factory.h deleted file mode 100644 index 343303f..0000000 --- a/chrome/browser/custom_handlers/protocol_handler_registry_factory.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2012 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_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_FACTORY_H_ -#define CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_FACTORY_H_ - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "chrome/browser/profiles/profile_keyed_service_factory.h" - -class Profile; -class ProtocolHandlerRegistry; -template <typename T> struct DefaultSingletonTraits; - -// Singleton that owns all ProtocolHandlerRegistrys and associates them with -// Profiles. Listens for the Profile's destruction notification and cleans up -// the associated ProtocolHandlerRegistry. -class ProtocolHandlerRegistryFactory : public ProfileKeyedServiceFactory { - public: - // Returns the singleton instance of the ProtocolHandlerRegistryFactory. - static ProtocolHandlerRegistryFactory* GetInstance(); - - // Returns the ProtocolHandlerRegistry that provides intent registration for - // |profile|. Ownership stays with this factory object. - static ProtocolHandlerRegistry* GetForProfile(Profile* profile); - - protected: - // ProfileKeyedServiceFactory implementation. - virtual bool ServiceIsCreatedWithProfile() OVERRIDE; - virtual bool ServiceRedirectedInIncognito() OVERRIDE; - virtual bool ServiceIsNULLWhileTesting() OVERRIDE; - - private: - friend struct DefaultSingletonTraits<ProtocolHandlerRegistryFactory>; - - ProtocolHandlerRegistryFactory(); - virtual ~ProtocolHandlerRegistryFactory(); - - // ProfileKeyedServiceFactory implementation. - virtual ProfileKeyedService* BuildServiceInstanceFor( - Profile* profile) const OVERRIDE; - - DISALLOW_COPY_AND_ASSIGN(ProtocolHandlerRegistryFactory); -}; - -#endif // CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_FACTORY_H_ diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc index 029e99d1..1330661 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc +++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc @@ -8,7 +8,6 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" -#include "base/synchronization/waitable_event.h" #include "base/utf_string_conversions.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/custom_handlers/protocol_handler.h" @@ -22,56 +21,11 @@ #include "content/public/test/test_renderer_host.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_context.h" -#include "testing/gtest/include/gtest/gtest.h" using content::BrowserThread; namespace { -void AssertInterceptedIO( - const GURL& url, - net::URLRequestJobFactory::Interceptor* interceptor) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - net::URLRequestContext context; - net::URLRequest request(url, NULL, &context); - scoped_refptr<net::URLRequestJob> job = interceptor->MaybeIntercept(&request); - ASSERT_TRUE(job.get() != NULL); -} - -void AssertIntercepted( - const GURL& url, - net::URLRequestJobFactory::Interceptor* interceptor) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - BrowserThread::PostTask(BrowserThread::IO, - FROM_HERE, - base::Bind(AssertInterceptedIO, - url, - base::Unretained(interceptor))); - MessageLoop::current()->RunAllPending(); -} - -void AssertWillHandleIO( - const std::string& scheme, - bool expected, - net::URLRequestJobFactory::Interceptor* interceptor) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - ASSERT_EQ(expected, interceptor->WillHandleProtocol(scheme)); -} - -void AssertWillHandle( - const std::string& scheme, - bool expected, - net::URLRequestJobFactory::Interceptor* interceptor) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - BrowserThread::PostTask(BrowserThread::IO, - FROM_HERE, - base::Bind(AssertWillHandleIO, - scheme, - expected, - base::Unretained(interceptor))); - MessageLoop::current()->RunAllPending(); -} - class FakeDelegate : public ProtocolHandlerRegistry::Delegate { public: FakeDelegate() : force_os_failure_(false) {} @@ -220,7 +174,7 @@ class QueryProtocolHandlerOnChange public: QueryProtocolHandlerOnChange(Profile* profile, ProtocolHandlerRegistry* registry) - : local_registry_(registry), + : registry_(registry), called_(false), notification_registrar_() { notification_registrar_.Add(this, @@ -232,53 +186,26 @@ class QueryProtocolHandlerOnChange const content::NotificationSource& source, const content::NotificationDetails& details) { std::vector<std::string> output; - local_registry_->GetRegisteredProtocols(&output); + registry_->GetRegisteredProtocols(&output); called_ = true; } - ProtocolHandlerRegistry* local_registry_; + ProtocolHandlerRegistry* registry_; bool called_; content::NotificationRegistrar notification_registrar_; }; -// URLRequest DCHECKS that the current MessageLoop is IO. It does this because -// it can't check the thread id (since net can't depend on content.) We want -// to harness our tests so all threads use the same loop allowing us to -// guarantee all messages are processed.) By overriding the IsType method -// we basically ignore the supplied message loop type, and instead infer -// our type based on the current thread. GO DEPENDENCY INJECTION! -class TestMessageLoop : public MessageLoop { - public: - TestMessageLoop() : MessageLoop(MessageLoop::TYPE_DEFAULT) {} - ~TestMessageLoop() {} - virtual bool IsType(MessageLoop::Type type) const OVERRIDE { - switch (type) { - case MessageLoop::TYPE_UI: - return BrowserThread::CurrentlyOn(BrowserThread::UI); - case MessageLoop::TYPE_IO: - return BrowserThread::CurrentlyOn(BrowserThread::IO); - case MessageLoop::TYPE_DEFAULT: - return !BrowserThread::CurrentlyOn(BrowserThread::UI) && - !BrowserThread::CurrentlyOn(BrowserThread::IO); - } - return false; - } -}; - } // namespace class ProtocolHandlerRegistryTest : public testing::Test { protected: ProtocolHandlerRegistryTest() - : ui_thread_(BrowserThread::UI, &loop_), - file_thread_(BrowserThread::FILE, &loop_), - io_thread_(BrowserThread::IO, &loop_), - test_protocol_handler_(CreateProtocolHandler("test", "test")) {} + : test_protocol_handler_(CreateProtocolHandler("test", "test")) {} FakeDelegate* delegate() const { return delegate_; } - ProtocolHandlerRegistry* registry() { return registry_.get(); } TestingProfile* profile() const { return profile_.get(); } PrefService* pref_service() const { return profile_->GetPrefs(); } + ProtocolHandlerRegistry* registry() const { return registry_.get(); } const ProtocolHandler& test_protocol_handler() const { return test_protocol_handler_; } @@ -296,48 +223,68 @@ class ProtocolHandlerRegistryTest : public testing::Test { name); } - void RecreateRegistry(bool initialize) { - TeadDownRegistry(); - SetUpRegistry(initialize); - } - - // Returns a new registry, initializing it if |initialize| is true. - // Caller assumes ownership for the object - void SetUpRegistry(bool initialize) { + void ReloadProtocolHandlerRegistry() { delegate_ = new FakeDelegate(); - registry_.reset(new ProtocolHandlerRegistry(profile(), delegate())); - if (initialize) registry_->InitProtocolSettings(); + registry_->Finalize(); + registry_ = NULL; + registry_ = new ProtocolHandlerRegistry(profile(), delegate()); + registry_->Load(); } - void TeadDownRegistry() { - registry_->Shutdown(); - registry_.reset(); - // Registry owns the delegate_ it handles deletion of that object. + void ReloadProtocolHandlerRegistryAndInstallDefaultHandler() { + delegate_ = new FakeDelegate(); + registry_->Finalize(); + registry_ = NULL; + registry_ = new ProtocolHandlerRegistry(profile(), delegate()); + registry_->AddPredefinedHandler(CreateProtocolHandler( + "test", GURL("http://test.com/%s"), "Test")); + registry_->Load(); } virtual void SetUp() { + ui_message_loop_.reset(new MessageLoopForUI()); + ui_thread_.reset(new content::TestBrowserThread(BrowserThread::UI, + MessageLoop::current())); + io_thread_.reset(new content::TestBrowserThread(BrowserThread::IO)); + io_thread_->StartIOThread(); + + file_thread_.reset(new content::TestBrowserThread(BrowserThread::FILE)); + file_thread_->Start(); + profile_.reset(new TestingProfile()); profile_->SetPrefService(new TestingPrefService()); - SetUpRegistry(true); + delegate_ = new FakeDelegate(); + registry_ = new ProtocolHandlerRegistry(profile(), delegate()); + registry_->Load(); test_protocol_handler_ = CreateProtocolHandler("test", GURL("http://test.com/%s"), "Test"); + ProtocolHandlerRegistry::RegisterPrefs(pref_service()); } virtual void TearDown() { - TeadDownRegistry(); + registry_->Finalize(); + registry_ = NULL; + io_thread_->Stop(); + io_thread_.reset(NULL); + file_thread_->Stop(); + file_thread_.reset(NULL); + ui_thread_.reset(NULL); + ui_message_loop_.reset(NULL); } - TestMessageLoop loop_; + bool enabled_io() { + return registry()->enabled_io_; + } - private: - content::TestBrowserThread ui_thread_; - content::TestBrowserThread file_thread_; - content::TestBrowserThread io_thread_; + scoped_ptr<MessageLoopForUI> ui_message_loop_; + scoped_ptr<content::TestBrowserThread> ui_thread_; + scoped_ptr<content::TestBrowserThread> io_thread_; + scoped_ptr<content::TestBrowserThread> file_thread_; + FakeDelegate* delegate_; scoped_ptr<TestingProfile> profile_; - FakeDelegate* delegate_; // Registry assumes ownership of delegate_. - scoped_ptr<ProtocolHandlerRegistry> registry_; + scoped_refptr<ProtocolHandlerRegistry> registry_; ProtocolHandler test_protocol_handler_; }; @@ -436,7 +383,7 @@ TEST_F(ProtocolHandlerRegistryTest, SaveAndLoad) { ASSERT_TRUE(registry()->IsHandledProtocol("test")); ASSERT_TRUE(registry()->IsIgnored(stuff_protocol_handler)); delegate()->Reset(); - RecreateRegistry(true); + ReloadProtocolHandlerRegistry(); ASSERT_TRUE(registry()->IsHandledProtocol("test")); ASSERT_TRUE(registry()->IsIgnored(stuff_protocol_handler)); } @@ -522,14 +469,14 @@ TEST_F(ProtocolHandlerRegistryTest, TestDefaultSaveLoad) { registry()->OnAcceptRegisterProtocolHandler(ph2); registry()->Disable(); - RecreateRegistry(true); + ReloadProtocolHandlerRegistry(); ASSERT_FALSE(registry()->enabled()); registry()->Enable(); ASSERT_FALSE(registry()->IsDefault(ph1)); ASSERT_TRUE(registry()->IsDefault(ph2)); - RecreateRegistry(true); + ReloadProtocolHandlerRegistry(); ASSERT_TRUE(registry()->enabled()); } @@ -689,10 +636,6 @@ TEST_F(ProtocolHandlerRegistryTest, TestDisablePreventsHandling) { ASSERT_FALSE(registry()->IsHandledProtocol("test")); } -// TODO(smckay): This is much more appropriately an integration -// test. Make that so, then update the -// ShellIntegretion{Delegate,Observer,Worker} test classes we use to fully -// isolate this test from the FILE thread. TEST_F(ProtocolHandlerRegistryTest, TestOSRegistration) { ProtocolHandler ph_do1 = CreateProtocolHandler("do", "test1"); ProtocolHandler ph_do2 = CreateProtocolHandler("do", "test2"); @@ -703,7 +646,7 @@ TEST_F(ProtocolHandlerRegistryTest, TestOSRegistration) { registry()->OnAcceptRegisterProtocolHandler(ph_do1); registry()->OnDenyRegisterProtocolHandler(ph_dont); - MessageLoop::current()->Run(); // FILE thread needs to run. + MessageLoop::current()->Run(); ASSERT_TRUE(delegate()->IsFakeRegisteredWithOS("do")); ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("dont")); @@ -721,10 +664,6 @@ TEST_F(ProtocolHandlerRegistryTest, TestOSRegistration) { #define MAYBE_TestOSRegistrationFailure TestOSRegistrationFailure #endif -// TODO(smckay): This is much more appropriately an integration -// test. Make that so, then update the -// ShellIntegretion{Delegate,Observer,Worker} test classes we use to fully -// isolate this test from the FILE thread. TEST_F(ProtocolHandlerRegistryTest, MAYBE_TestOSRegistrationFailure) { ProtocolHandler ph_do = CreateProtocolHandler("do", "test1"); ProtocolHandler ph_dont = CreateProtocolHandler("dont", "test"); @@ -733,24 +672,40 @@ TEST_F(ProtocolHandlerRegistryTest, MAYBE_TestOSRegistrationFailure) { ASSERT_FALSE(registry()->IsHandledProtocol("dont")); registry()->OnAcceptRegisterProtocolHandler(ph_do); - MessageLoop::current()->Run(); // FILE thread needs to run. + MessageLoop::current()->Run(); delegate()->set_force_os_failure(true); registry()->OnAcceptRegisterProtocolHandler(ph_dont); - MessageLoop::current()->Run(); // FILE thread needs to run. + MessageLoop::current()->Run(); ASSERT_TRUE(registry()->IsHandledProtocol("do")); ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("do").size()); ASSERT_FALSE(registry()->IsHandledProtocol("dont")); ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("dont").size()); } +static void MakeRequest(const GURL& url, ProtocolHandlerRegistry* registry) { + net::URLRequestContext context; + net::URLRequest request(url, NULL, &context); + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + MessageLoop::QuitClosure()); + scoped_refptr<net::URLRequestJob> job(registry->MaybeCreateJob(&request)); + ASSERT_TRUE(job.get() != NULL); +} + TEST_F(ProtocolHandlerRegistryTest, TestMaybeCreateTaskWorksFromIOThread) { ProtocolHandler ph1 = CreateProtocolHandler("mailto", "test1"); registry()->OnAcceptRegisterProtocolHandler(ph1); GURL url("mailto:someone@something.com"); - net::URLRequestJobFactory::Interceptor* interceptor = - registry()->CreateURLInterceptor(); + scoped_refptr<ProtocolHandlerRegistry> r(registry()); + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(MakeRequest, url, r)); + MessageLoop::current()->Run(); +} - AssertIntercepted(url, interceptor); +static void CheckIsHandled(const std::string& scheme, bool expected, + ProtocolHandlerRegistry* registry) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + MessageLoop::QuitClosure()); + ASSERT_EQ(expected, registry->IsHandledProtocolIO(scheme)); } TEST_F(ProtocolHandlerRegistryTest, @@ -758,10 +713,11 @@ TEST_F(ProtocolHandlerRegistryTest, std::string scheme("mailto"); ProtocolHandler ph1 = CreateProtocolHandler(scheme, "test1"); registry()->OnAcceptRegisterProtocolHandler(ph1); - net::URLRequestJobFactory::Interceptor* interceptor = - registry()->CreateURLInterceptor(); - - AssertWillHandle(scheme, true, interceptor); + scoped_refptr<ProtocolHandlerRegistry> r(registry()); + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(CheckIsHandled, scheme, true, r)); } TEST_F(ProtocolHandlerRegistryTest, TestRemovingDefaultFallsBackToOldDefault) { @@ -805,20 +761,26 @@ TEST_F(ProtocolHandlerRegistryTest, MAYBE_TestClearDefaultGetsPropagatedToIO) { ProtocolHandler ph1 = CreateProtocolHandler(scheme, "test1"); registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->ClearDefault(scheme); - net::URLRequestJobFactory::Interceptor* interceptor = - registry()->CreateURLInterceptor(); + scoped_refptr<ProtocolHandlerRegistry> r(registry()); - AssertWillHandle(scheme, false, interceptor); + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(CheckIsHandled, scheme, false, r)); } -TEST_F(ProtocolHandlerRegistryTest, TestLoadEnabledGetsPropogatedToIO) { - std::string mailto("mailto"); - ProtocolHandler ph1 = CreateProtocolHandler(mailto, "MailtoHandler"); - registry()->OnAcceptRegisterProtocolHandler(ph1); +static void QuitUILoop() { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + MessageLoop::QuitClosure()); +} - AssertWillHandle(mailto, true, registry()->CreateURLInterceptor()); +TEST_F(ProtocolHandlerRegistryTest, TestLoadEnabledGetsPropogatedToIO) { registry()->Disable(); - AssertWillHandle(mailto, false, registry()->CreateURLInterceptor()); + ReloadProtocolHandlerRegistry(); + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(QuitUILoop)); + MessageLoop::current()->Run(); + ASSERT_FALSE(enabled_io()); } TEST_F(ProtocolHandlerRegistryTest, TestReplaceHandler) { @@ -882,10 +844,7 @@ TEST_F(ProtocolHandlerRegistryTest, TestIsSameOrigin) { } TEST_F(ProtocolHandlerRegistryTest, MAYBE_TestInstallDefaultHandler) { - RecreateRegistry(false); - registry()->AddPredefinedHandler(CreateProtocolHandler( - "test", GURL("http://test.com/%s"), "Test")); - registry()->InitProtocolSettings(); + ReloadProtocolHandlerRegistryAndInstallDefaultHandler(); std::vector<std::string> protocols; registry()->GetRegisteredProtocols(&protocols); ASSERT_EQ(static_cast<size_t>(1), protocols.size()); |