| // 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_H_ |
| #define CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_H_ |
| |
| #include <map> |
| #include <string> |
| #include <vector> |
| |
| #include "base/basictypes.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/sequenced_task_runner_helpers.h" |
| #include "base/values.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/shell_integration.h" |
| #include "chrome/common/custom_handlers/protocol_handler.h" |
| #include "components/keyed_service/core/keyed_service.h" |
| #include "content/public/browser/browser_thread.h" |
| #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" |
| |
| namespace user_prefs { |
| class PrefRegistrySyncable; |
| } |
| |
| // 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 KeyedService { |
| |
| public: |
| enum HandlerSource { |
| USER, // The handler was installed by user |
| POLICY, // The handler was installed by policy |
| }; |
| // Provides notification of when the OS level user agent settings |
| // are changed. |
| class DefaultClientObserver |
| : public ShellIntegration::DefaultWebClientObserver { |
| public: |
| explicit DefaultClientObserver(ProtocolHandlerRegistry* registry); |
| virtual ~DefaultClientObserver(); |
| |
| // Get response from the worker regarding whether Chrome is the default |
| // handler for the protocol. |
| virtual void SetDefaultWebClientUIState( |
| ShellIntegration::DefaultWebClientUIState state) OVERRIDE; |
| |
| virtual bool IsInteractiveSetDefaultPermitted() OVERRIDE; |
| |
| // Give the observer a handle to the worker, so we can find out the protocol |
| // when we're called and also tell the worker if we get deleted. |
| void SetWorker(ShellIntegration::DefaultProtocolClientWorker* worker); |
| |
| protected: |
| ShellIntegration::DefaultProtocolClientWorker* worker_; |
| |
| private: |
| virtual bool IsOwnedByWorker() OVERRIDE; |
| |
| // This is a raw pointer, not reference counted, intentionally. In general |
| // subclasses of DefaultWebClientObserver are not able to be refcounted |
| // e.g. the browser options page |
| ProtocolHandlerRegistry* registry_; |
| |
| 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. |
| class Delegate { |
| public: |
| virtual ~Delegate(); |
| virtual void RegisterExternalHandler(const std::string& protocol); |
| virtual void DeregisterExternalHandler(const std::string& protocol); |
| virtual bool IsExternalHandlerRegistered(const std::string& protocol); |
| virtual ShellIntegration::DefaultProtocolClientWorker* CreateShellWorker( |
| ShellIntegration::DefaultWebClientObserver* observer, |
| const std::string& protocol); |
| virtual DefaultClientObserver* CreateShellObserver( |
| ProtocolHandlerRegistry* registry); |
| virtual void RegisterWithOSAsDefaultClient( |
| const std::string& protocol, |
| ProtocolHandlerRegistry* registry); |
| }; |
| |
| // Forward declaration of the internal implementation class. |
| class IOThreadDelegate; |
| |
| // JobInterceptorFactory intercepts URLRequestJob creation for URLRequests the |
| // ProtocolHandlerRegistry is registered to handle. When no handler is |
| // registered, the URLRequest is passed along to the chained |
| // URLRequestJobFactory (set with |JobInterceptorFactory::Chain|). |
| // JobInterceptorFactory's are created via |
| // |ProtocolHandlerRegistry::CreateJobInterceptorFactory|. |
| class JobInterceptorFactory : public net::URLRequestJobFactory { |
| public: |
| // |io_thread_delegate| is used to perform actual job creation work. |
| explicit JobInterceptorFactory(IOThreadDelegate* io_thread_delegate); |
| virtual ~JobInterceptorFactory(); |
| |
| // |job_factory| is set as the URLRequestJobFactory where requests are |
| // forwarded if JobInterceptorFactory decides to pass on them. |
| void Chain(scoped_ptr<net::URLRequestJobFactory> job_factory); |
| |
| // URLRequestJobFactory implementation. |
| virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler( |
| const std::string& scheme, |
| net::URLRequest* request, |
| net::NetworkDelegate* network_delegate) const OVERRIDE; |
| virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE; |
| virtual bool IsHandledURL(const GURL& url) const OVERRIDE; |
| virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE; |
| |
| private: |
| // When JobInterceptorFactory decides to pass on particular requests, |
| // they're forwarded to the chained URLRequestJobFactory, |job_factory_|. |
| scoped_ptr<URLRequestJobFactory> job_factory_; |
| // |io_thread_delegate_| performs the actual job creation decisions by |
| // mirroring the ProtocolHandlerRegistry on the IO thread. |
| scoped_refptr<IOThreadDelegate> io_thread_delegate_; |
| |
| DISALLOW_COPY_AND_ASSIGN(JobInterceptorFactory); |
| }; |
| |
| typedef std::map<std::string, ProtocolHandler> ProtocolHandlerMap; |
| typedef std::vector<ProtocolHandler> ProtocolHandlerList; |
| typedef std::map<std::string, ProtocolHandlerList> ProtocolHandlerMultiMap; |
| typedef std::vector<DefaultClientObserver*> DefaultClientObserverList; |
| |
| // Creates a new instance. Assumes ownership of |delegate|. |
| ProtocolHandlerRegistry(content::BrowserContext* context, Delegate* delegate); |
| virtual ~ProtocolHandlerRegistry(); |
| |
| // Returns a net::URLRequestJobFactory suitable for use on the IO thread, but |
| // is initialized on the UI thread. |
| scoped_ptr<JobInterceptorFactory> CreateJobInterceptorFactory(); |
| |
| // 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 |
| // or to update an existing handler - the request will succeed. If this |
| // function returns false the user needs to be prompted for confirmation. |
| bool SilentlyHandleRegisterHandlerRequest(const ProtocolHandler& handler); |
| |
| // Called when the user accepts the registration of a given protocol handler. |
| void OnAcceptRegisterProtocolHandler(const ProtocolHandler& handler); |
| |
| // Called when the user denies the registration of a given protocol handler. |
| void OnDenyRegisterProtocolHandler(const ProtocolHandler& handler); |
| |
| // Called when the user indicates that they don't want to be asked about the |
| // given protocol handler again. |
| void OnIgnoreRegisterProtocolHandler(const ProtocolHandler& handler); |
| |
| // Removes all handlers that have the same origin and protocol as the given |
| // one and installs the given handler. Returns true if any protocol handlers |
| // were replaced. |
| bool AttemptReplace(const ProtocolHandler& handler); |
| |
| // Returns a list of protocol handlers that can be replaced by the given |
| // handler. |
| ProtocolHandlerList GetReplacedHandlers(const ProtocolHandler& handler) const; |
| |
| // Clears the default for the provided protocol. |
| void ClearDefault(const std::string& scheme); |
| |
| // 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(); |
| |
| // 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. |
| ProtocolHandlerList GetHandlersFor(const std::string& scheme) const; |
| |
| // Get the list of ignored protocol handlers. |
| ProtocolHandlerList GetIgnoredHandlers(); |
| |
| // Yields a list of the protocols that have handlers registered in this |
| // registry. |
| void GetRegisteredProtocols(std::vector<std::string>* output) const; |
| |
| // Returns true if we allow websites to register handlers for the given |
| // scheme. |
| bool CanSchemeBeOverridden(const std::string& scheme) const; |
| |
| // Returns true if an identical protocol handler has already been registered. |
| bool IsRegistered(const ProtocolHandler& handler) const; |
| |
| // Returns true if an identical protocol handler is being ignored. |
| bool IsIgnored(const ProtocolHandler& handler) const; |
| |
| // Returns true if an equivalent protocol handler has already been registered. |
| bool HasRegisteredEquivalent(const ProtocolHandler& handler) const; |
| |
| // Returns true if an equivalent protocol handler is being ignored. |
| bool HasIgnoredEquivalent(const ProtocolHandler& handler) const; |
| |
| // Causes the given protocol handler to not be ignored anymore. |
| void RemoveIgnoredHandler(const ProtocolHandler& handler); |
| |
| // Returns true if the protocol has a default protocol handler. |
| bool IsHandledProtocol(const std::string& scheme) const; |
| |
| // Removes the given protocol handler from the registry. |
| void RemoveHandler(const ProtocolHandler& handler); |
| |
| // Remove the default handler for the given protocol. |
| void RemoveDefaultHandler(const std::string& scheme); |
| |
| // Returns the default handler for this protocol, or an empty handler if none |
| // exists. |
| const ProtocolHandler& GetHandlerFor(const std::string& scheme) const; |
| |
| // Puts this registry in the enabled state - registered protocol handlers |
| // will handle requests. |
| void Enable(); |
| |
| // Puts this registry in the disabled state - registered protocol handlers |
| // will not handle requests. |
| void Disable(); |
| |
| // 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; |
| |
| // Registers the preferences that we store registered protocol handlers in. |
| static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); |
| |
| bool enabled() const { return enabled_; } |
| |
| // Add a predefined protocol handler. This has to be called before the first |
| // load command was issued, otherwise the command will be ignored. |
| void AddPredefinedHandler(const ProtocolHandler& handler); |
| |
| private: |
| friend class base::DeleteHelper<ProtocolHandlerRegistry>; |
| friend struct content::BrowserThread::DeleteOnThread< |
| content::BrowserThread::IO>; |
| |
| // for access to InstallDefaultsForChromeOS |
| friend class ProtocolHandlerRegistryFactory; |
| |
| friend class ProtocolHandlerRegistryTest; |
| friend class RegisterProtocolHandlerBrowserTest; |
| |
| // Puts the given handler at the top of the list of handlers for its |
| // protocol. |
| void PromoteHandler(const ProtocolHandler& handler); |
| |
| // Saves a user's registered protocol handlers. |
| void Save(); |
| |
| // Returns a pointer to the list of handlers registered for the given scheme, |
| // or NULL if there are none. |
| const ProtocolHandlerList* GetHandlerList(const std::string& scheme) const; |
| |
| // Install default protocol handlers for chromeos which must be done |
| // prior to calling InitProtocolSettings. |
| void InstallDefaultsForChromeOS(); |
| |
| // Makes this ProtocolHandler the default handler for its protocol. |
| void SetDefault(const ProtocolHandler& handler); |
| |
| // 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. |
| base::Value* EncodeRegisteredHandlers(); |
| |
| // Returns a JSON list of ignored protocol handlers. The caller is |
| // responsible for deleting this Value. |
| base::Value* EncodeIgnoredHandlers(); |
| |
| // Sends a notification of the given type to the NotificationService. |
| void NotifyChanged(); |
| |
| // Registers a new protocol handler. |
| void RegisterProtocolHandler(const ProtocolHandler& handler, |
| const HandlerSource source); |
| |
| // Registers protocol handlers from the preference. |
| void RegisterProtocolHandlersFromPref(const char* pref_name, |
| const HandlerSource source); |
| |
| // Get the DictionaryValues stored under the given pref name that are valid |
| // ProtocolHandler values. |
| std::vector<const base::DictionaryValue*> GetHandlersFromPref( |
| const char* pref_name) const; |
| |
| // Ignores future requests to register the given protocol handler. |
| void IgnoreProtocolHandler(const ProtocolHandler& handler, |
| const HandlerSource source); |
| |
| // Ignores protocol handlers from the preference. |
| void IgnoreProtocolHandlersFromPref(const char* pref_name, |
| const HandlerSource source); |
| |
| // Verifies if the handler exists in the map. |
| bool HandlerExists(const ProtocolHandler& handler, |
| ProtocolHandlerMultiMap* map); |
| |
| // Verifies if the handler exists in the list. |
| bool HandlerExists(const ProtocolHandler& handler, |
| const ProtocolHandlerList& list); |
| |
| // Erases the handler that is guaranteed to exist from the map. |
| void EraseHandler(const ProtocolHandler& handler, |
| ProtocolHandlerMultiMap* map); |
| |
| // Erases the handler that is guaranteed to exist from the list. |
| void EraseHandler(const ProtocolHandler& handler, ProtocolHandlerList* list); |
| |
| // Map from protocols (strings) to protocol handlers. |
| ProtocolHandlerMultiMap protocol_handlers_; |
| |
| // Protocol handlers that the user has told us to ignore. |
| ProtocolHandlerList ignored_protocol_handlers_; |
| |
| // These maps track the source of protocol handler registrations for the |
| // purposes of disallowing the removal of handlers that are registered by |
| // policy. Every entry in protocol_handlers_ should exist in at least one of |
| // the user or policy maps. |
| ProtocolHandlerMultiMap user_protocol_handlers_; |
| ProtocolHandlerMultiMap policy_protocol_handlers_; |
| |
| // These lists track the source of protocol handlers that were ignored, for |
| // the purposes of disallowing the removal of handlers that are ignored by |
| // policy. Every entry in ignored_protocol_handlers_ should exist in at least |
| // one of the user or policy lists. |
| ProtocolHandlerList user_ignored_protocol_handlers_; |
| ProtocolHandlerList policy_ignored_protocol_handlers_; |
| |
| // Protocol handlers that are the defaults for a given protocol. |
| ProtocolHandlerMap default_handlers_; |
| |
| // The browser context that owns this ProtocolHandlerRegistry. |
| content::BrowserContext* context_; |
| |
| // The Delegate that registers / deregisters external handlers on our behalf. |
| scoped_ptr<Delegate> delegate_; |
| |
| // If false then registered protocol handlers will not be used to handle |
| // requests. |
| bool enabled_; |
| |
| // Whether or not we are loading. |
| bool is_loading_; |
| |
| // When the table gets loaded this flag will be set and any further calls to |
| // 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<IOThreadDelegate> io_thread_delegate_; |
| |
| DefaultClientObserverList default_client_observers_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ProtocolHandlerRegistry); |
| }; |
| #endif // CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_H_ |