Chromium Code Reviews| Index: chrome/browser/custom_handlers/protocol_handler_registry.cc |
| diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.cc b/chrome/browser/custom_handlers/protocol_handler_registry.cc |
| index 5a6dfae91134364984447dfffb2269b13714e820..d0e6e9818239474d1b24c69ef06eeec9e12016a8 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" |
| @@ -22,6 +23,8 @@ |
| #include "content/public/browser/child_process_security_policy.h" |
| #include "content/public/browser/notification_service.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" |
| using content::BrowserThread; |
| @@ -29,6 +32,17 @@ 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 +58,162 @@ 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> { |
| + |
|
willchan no longer on Chromium
2012/06/22 19:01:56
-whitespace
Steve McKay
2012/06/27 21:49:28
Done.
|
| + public: |
| + |
|
willchan no longer on Chromium
2012/06/22 19:01:56
-whitespace
Steve McKay
2012/06/27 21:49:28
Done.
|
| + explicit Core(bool); |
| + |
| + // 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 default_handlers_ that is only accessed on the IO thread. |
| + ProtocolHandlerRegistry::ProtocolHandlerMap default_handlers_; |
| + // Copy of enabled_ that is only accessed 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)); |
| +} |
| + |
| +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; |
| } |
| - return ProtocolHandler::EmptyProtocolHandler(); |
| + GURL translated_url(handler.TranslateUrl(request->url())); |
| + if (!translated_url.is_valid()) { |
| + return NULL; |
| + } |
| + return new net::URLRequestRedirectJob(request, translated_url); |
| +} |
| + |
| +// IOURLInterceptor ------------------------------------------------------------ |
| + |
| +// 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::CreateIOURLInterceptor|. |
| +class ProtocolHandlerRegistry::IOURLInterceptor |
| + : public net::URLRequestJobFactory::Interceptor { |
| + public: |
| + explicit IOURLInterceptor(Core* core); |
| + virtual ~IOURLInterceptor(); |
| + |
| + 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; |
| + } |
| + |
| + virtual net::URLRequestJob* MaybeInterceptResponse( |
| + net::URLRequest* request) const OVERRIDE { |
| + return NULL; |
| + } |
| + |
| + private: |
| + scoped_refptr<Core> core_; |
| + DISALLOW_COPY_AND_ASSIGN(IOURLInterceptor); |
| +}; |
| + |
| +ProtocolHandlerRegistry::IOURLInterceptor::IOURLInterceptor(Core* core) |
| + : core_(core) { |
| + DCHECK(core_); |
| +} |
| + |
| +ProtocolHandlerRegistry::IOURLInterceptor::~IOURLInterceptor() { |
| + // TODO(smckay): release what ever type of pointer we have |
| + // on the C instance. |
| +} |
| + |
| +net::URLRequestJob* ProtocolHandlerRegistry::IOURLInterceptor::MaybeIntercept( |
| + net::URLRequest* request) const { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + return core_->MaybeCreateJob(request); |
| +} |
| + |
| +bool ProtocolHandlerRegistry::IOURLInterceptor::WillHandleProtocol( |
| + const std::string& protocol) const { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + return core_->IsHandledProtocol(protocol); |
| } |
| // DefaultClientObserver ------------------------------------------------------ |
| @@ -76,8 +235,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 +309,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 +391,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 +407,23 @@ bool ProtocolHandlerRegistry::IsDefault( |
| return GetHandlerFor(handler.protocol()) == handler; |
| } |
| -void ProtocolHandlerRegistry::Load() { |
| +void ProtocolHandlerRegistry::InitProtocolSettings() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + // Install predefined protocol handlers. |
| + 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 +591,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 +609,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 +635,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 +644,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 +663,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 +673,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 +697,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 +711,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 +751,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) { |
| @@ -721,4 +854,11 @@ void ProtocolHandlerRegistry::AddPredefinedHandler( |
| SetDefault(handler); |
| } |
| - |
| +net::URLRequestJobFactory::Interceptor* |
| + ProtocolHandlerRegistry::CreateIOURLInterceptor() { |
| + 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 IOURLInterceptor(core_); |
| +} |