| 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> {
|
| +
|
| + public:
|
| +
|
| + 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_);
|
| +}
|
|
|