diff options
author | smckay@chromium.org <smckay@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-20 01:52:02 +0000 |
---|---|---|
committer | smckay@chromium.org <smckay@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-20 01:52:02 +0000 |
commit | 26effd10fe11d820b3040e72d85e00dd3bd524d5 (patch) | |
tree | 604505f94bf6cd372a8fc63a7337c9435bcd3b58 /chrome/browser/custom_handlers/protocol_handler_registry.cc | |
parent | 0397dea43ea8a08e496971c80795970db5ad0644 (diff) | |
download | chromium_src-26effd10fe11d820b3040e72d85e00dd3bd524d5.zip chromium_src-26effd10fe11d820b3040e72d85e00dd3bd524d5.tar.gz chromium_src-26effd10fe11d820b3040e72d85e00dd3bd524d5.tar.bz2 |
Convert ProtocolHandlerRegistry to be a ProfileKeyedService.
BUG=129200
TEST=protocol_handler_registry_browsertest.cc,protocol_handler_registry_unittest.cc
willchan@ -> profile_io changes
+bauerb -> content_settings changes
Review URL: https://chromiumcodereview.appspot.com/10546083
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@147597 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/custom_handlers/protocol_handler_registry.cc')
-rw-r--r-- | chrome/browser/custom_handlers/protocol_handler_registry.cc | 273 |
1 files changed, 209 insertions, 64 deletions
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.cc b/chrome/browser/custom_handlers/protocol_handler_registry.cc index 5a6dfae..712f791 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry.cc +++ b/chrome/browser/custom_handlers/protocol_handler_registry.cc @@ -9,6 +9,7 @@ #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" @@ -21,14 +22,30 @@ #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() { @@ -44,17 +61,165 @@ bool ShouldRemoveHandlersNotInOS() { #endif } -} // namespace +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 +} -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; +} // 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; } - return ProtocolHandler::EmptyProtocolHandler(); + + virtual net::URLRequestJob* MaybeInterceptResponse( + net::URLRequest* request) const OVERRIDE { + return NULL; + } + + 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); } // DefaultClientObserver ------------------------------------------------------ @@ -76,8 +241,7 @@ ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() { registry_->default_client_observers_.erase(iter); } -void -ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState( +void ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState( ShellIntegration::DefaultWebClientUIState state) { if (worker_) { if (ShouldRemoveHandlersNotInOS() && @@ -151,9 +315,9 @@ ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile, : profile_(profile), delegate_(delegate), enabled_(true), - enabled_io_(enabled_), is_loading_(false), - is_loaded_(false) { + is_loaded_(false), + core_(new Core(enabled_)){ } bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest( @@ -233,11 +397,12 @@ 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(&ProtocolHandlerRegistry::ClearDefaultIO, this, scheme)); + base::Bind(&Core::ClearDefault, core_, scheme)); Save(); NotifyChanged(); } @@ -248,19 +413,23 @@ bool ProtocolHandlerRegistry::IsDefault( return GetHandlerFor(handler.protocol()) == handler; } -void ProtocolHandlerRegistry::Load() { +void ProtocolHandlerRegistry::InitProtocolSettings() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // Default protocol handlers must be installed first. + InstallDefaultProtocolHandlers(this); + // 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)) { - enabled_ = prefs->GetBoolean(prefs::kCustomHandlersEnabled); - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(enabled_ ? &ProtocolHandlerRegistry::EnableIO : - &ProtocolHandlerRegistry::DisableIO, this)); + if (prefs->GetBoolean(prefs::kCustomHandlersEnabled)) { + Enable(); + } else { + Disable(); + } } std::vector<const DictionaryValue*> registered_handlers = GetHandlersFromPref(prefs::kRegisteredProtocolHandlers); @@ -428,12 +597,6 @@ 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)); @@ -452,8 +615,8 @@ void ProtocolHandlerRegistry::RemoveHandler( } else { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&ProtocolHandlerRegistry::ClearDefaultIO, this, - q->second.protocol())); + base::Bind(&Core::ClearDefault, core_, q->second.protocol())); + default_handlers_.erase(q); } } @@ -478,21 +641,6 @@ 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_) { @@ -502,7 +650,8 @@ void ProtocolHandlerRegistry::Enable() { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&ProtocolHandlerRegistry::EnableIO, this)); + base::Bind(&Core::Enable, core_)); + ProtocolHandlerMap::const_iterator p; for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { delegate_->RegisterExternalHandler(p->first); @@ -520,7 +669,8 @@ void ProtocolHandlerRegistry::Disable() { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&ProtocolHandlerRegistry::DisableIO, this)); + base::Bind(&Core::Disable, core_)); + ProtocolHandlerMap::const_iterator p; for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { delegate_->DeregisterExternalHandler(p->first); @@ -529,7 +679,7 @@ void ProtocolHandlerRegistry::Disable() { NotifyChanged(); } -void ProtocolHandlerRegistry::Finalize() { +void ProtocolHandlerRegistry::Shutdown() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); delegate_.reset(NULL); // We free these now in case there are any outstanding workers running. If @@ -553,7 +703,7 @@ void ProtocolHandlerRegistry::RegisterPrefs(PrefService* pref_service) { } ProtocolHandlerRegistry::~ProtocolHandlerRegistry() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(default_client_observers_.empty()); } @@ -567,17 +717,6 @@ 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_) { @@ -618,7 +757,7 @@ void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&ProtocolHandlerRegistry::SetDefaultIO, this, handler)); + base::Bind(&Core::SetDefault, core_, handler)); } void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) { @@ -715,10 +854,16 @@ void ProtocolHandlerRegistry::IgnoreProtocolHandler( void ProtocolHandlerRegistry::AddPredefinedHandler( const ProtocolHandler& handler) { - // If called after the load command was issued this function will fail. - DCHECK(!is_loaded_); + DCHECK(!is_loaded_); // Must be called prior InitProtocolSettings. 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_); +} |