diff options
author | rsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-27 02:56:21 +0000 |
---|---|---|
committer | rsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-27 02:56:21 +0000 |
commit | 649d1c0ea7c08dec1586220da91a2ac3f73206ea (patch) | |
tree | da3ba2bd2812f1440827aac59c2e657c0b06a243 /chrome/browser/custom_handlers/protocol_handler_registry.cc | |
parent | 3819c76919240d0470005263ae64761d7f7ed97f (diff) | |
download | chromium_src-649d1c0ea7c08dec1586220da91a2ac3f73206ea.zip chromium_src-649d1c0ea7c08dec1586220da91a2ac3f73206ea.tar.gz chromium_src-649d1c0ea7c08dec1586220da91a2ac3f73206ea.tar.bz2 |
RefCounted types should not have public destructors, chrome/browser/ part 6
BUG=123295
TEST=none
Review URL: http://codereview.chromium.org/10071036
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@134218 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 | 807 |
1 files changed, 402 insertions, 405 deletions
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.cc b/chrome/browser/custom_handlers/protocol_handler_registry.cc index d81af98..ab8753a 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry.cc +++ b/chrome/browser/custom_handlers/protocol_handler_registry.cc @@ -27,172 +27,224 @@ using content::BrowserThread; using content::ChildProcessSecurityPolicy; -// ProtocolHandlerRegistry ----------------------------------------------------- +namespace { -ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile, - Delegate* delegate) - : profile_(profile), - delegate_(delegate), - enabled_(true), - enabled_io_(enabled_), - is_loading_(false) { +// If true default protocol handlers will be removed if the OS level +// registration for a protocol is no longer Chrome. +bool ShouldRemoveHandlersNotInOS() { +#if defined(OS_LINUX) + // We don't do this on Linux as the OS registration there is not reliable, + // and Chrome OS doesn't have any notion of OS registration. + // TODO(benwells): When Linux support is more reliable remove this + // difference (http://crbug.com/88255). + return false; +#else + return ShellIntegration::CanSetAsDefaultProtocolClient(); +#endif } -ProtocolHandlerRegistry::~ProtocolHandlerRegistry() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - DCHECK(default_client_observers_.empty()); -} +} // namespace -void ProtocolHandlerRegistry::Finalize() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - delegate_.reset(NULL); - // We free these now in case there are any outstanding workers running. If - // we didn't free them they could respond to workers and try to update the - // protocol handler registry after it was deleted. - // Observers remove themselves from this list when they are deleted; so - // we delete the last item until none are left in the list. - while (!default_client_observers_.empty()) { - delete default_client_observers_.back(); +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; } + return ProtocolHandler::EmptyProtocolHandler(); } -const ProtocolHandlerRegistry::ProtocolHandlerList* -ProtocolHandlerRegistry::GetHandlerList( - const std::string& scheme) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); - if (p == protocol_handlers_.end()) { - return NULL; - } - return &p->second; +// DefaultClientObserver ------------------------------------------------------ + +ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver( + ProtocolHandlerRegistry* registry) + : worker_(NULL), + registry_(registry) { + DCHECK(registry_); } -ProtocolHandlerRegistry::ProtocolHandlerList -ProtocolHandlerRegistry::GetHandlersFor( - const std::string& scheme) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); - if (p == protocol_handlers_.end()) { - return ProtocolHandlerList(); +ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() { + if (worker_) + worker_->ObserverDestroyed(); + + DefaultClientObserverList::iterator iter = std::find( + registry_->default_client_observers_.begin(), + registry_->default_client_observers_.end(), this); + registry_->default_client_observers_.erase(iter); +} + +void +ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState( + ShellIntegration::DefaultWebClientUIState state) { + if (worker_) { + if (ShouldRemoveHandlersNotInOS() && + (state == ShellIntegration::STATE_NOT_DEFAULT)) { + registry_->ClearDefault(worker_->protocol()); + } + } else { + NOTREACHED(); } - return p->second; } -ProtocolHandlerRegistry::ProtocolHandlerList -ProtocolHandlerRegistry::GetIgnoredHandlers() { - return ignored_protocol_handlers_; +void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker( + ShellIntegration::DefaultProtocolClientWorker* worker) { + worker_ = worker; } -void ProtocolHandlerRegistry::RegisterProtocolHandler( - const ProtocolHandler& handler) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(CanSchemeBeOverridden(handler.protocol())); - DCHECK(!handler.IsEmpty()); - if (IsRegistered(handler)) { - return; +// Delegate -------------------------------------------------------------------- + +ProtocolHandlerRegistry::Delegate::~Delegate() {} + +void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler( + const std::string& protocol) { + ChildProcessSecurityPolicy* policy = + ChildProcessSecurityPolicy::GetInstance(); + if (!policy->IsWebSafeScheme(protocol)) { + policy->RegisterWebSafeScheme(protocol); } - if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol())) - delegate_->RegisterExternalHandler(handler.protocol()); - InsertHandler(handler); } -void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ProtocolHandlerMultiMap::iterator p = - protocol_handlers_.find(handler.protocol()); +void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler( + const std::string& protocol) { +} - if (p != protocol_handlers_.end()) { - p->second.push_back(handler); - return; - } +bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered( + const std::string& protocol) { + // NOTE(koz): This function is safe to call from any thread, despite living + // in ProfileIOData. + return ProfileIOData::IsHandledProtocol(protocol); +} - ProtocolHandlerList new_list; - new_list.push_back(handler); - protocol_handlers_[handler.protocol()] = new_list; +ShellIntegration::DefaultProtocolClientWorker* +ProtocolHandlerRegistry::Delegate::CreateShellWorker( + ShellIntegration::DefaultWebClientObserver* observer, + const std::string& protocol) { + return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol); } -void ProtocolHandlerRegistry::IgnoreProtocolHandler( +ProtocolHandlerRegistry::DefaultClientObserver* +ProtocolHandlerRegistry::Delegate::CreateShellObserver( + ProtocolHandlerRegistry* registry) { + return new DefaultClientObserver(registry); +} + +void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient( + const std::string& protocol, ProtocolHandlerRegistry* registry) { + DefaultClientObserver* observer = CreateShellObserver(registry); + // The worker pointer is reference counted. While it is running the + // message loops of the FILE and UI thread will hold references to it + // and it will be automatically freed once all its tasks have finished. + scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; + worker = CreateShellWorker(observer, protocol); + observer->SetWorker(worker); + registry->default_client_observers_.push_back(observer); + worker->StartSetAsDefault(); +} + +// ProtocolHandlerRegistry ----------------------------------------------------- + +ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile, + Delegate* delegate) + : profile_(profile), + delegate_(delegate), + enabled_(true), + enabled_io_(enabled_), + is_loading_(false) { +} + +bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest( + const ProtocolHandler& handler) { + if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol())) + return true; + + if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler)) + return true; + + if (AttemptReplace(handler)) + return true; + + return false; +} + +void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler( const ProtocolHandler& handler) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ignored_protocol_handlers_.push_back(handler); + RegisterProtocolHandler(handler); + SetDefault(handler); + Save(); + NotifyChanged(); } -void ProtocolHandlerRegistry::Enable() { +void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler( + const ProtocolHandler& handler) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (enabled_) { - return; - } - enabled_ = true; - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&ProtocolHandlerRegistry::EnableIO, this)); - ProtocolHandlerMap::const_iterator p; - for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { - delegate_->RegisterExternalHandler(p->first); - } + RegisterProtocolHandler(handler); Save(); NotifyChanged(); } -void ProtocolHandlerRegistry::Disable() { +void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler( + const ProtocolHandler& handler) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (!enabled_) { - return; - } - enabled_ = false; - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&ProtocolHandlerRegistry::DisableIO, this)); - ProtocolHandlerMap::const_iterator p; - for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { - delegate_->DeregisterExternalHandler(p->first); - } + IgnoreProtocolHandler(handler); Save(); NotifyChanged(); } -std::vector<const DictionaryValue*> -ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const { +bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - std::vector<const DictionaryValue*> result; - PrefService* prefs = profile_->GetPrefs(); - if (!prefs->HasPrefPath(pref_name)) { - return result; + ProtocolHandler old_default = GetHandlerFor(handler.protocol()); + bool make_new_handler_default = handler.IsSameOrigin(old_default); + ProtocolHandlerList to_replace(GetReplacedHandlers(handler)); + if (to_replace.empty()) + return false; + for (ProtocolHandlerList::iterator p = to_replace.begin(); + p != to_replace.end(); ++p) { + RemoveHandler(*p); } + if (make_new_handler_default) { + OnAcceptRegisterProtocolHandler(handler); + } else { + InsertHandler(handler); + NotifyChanged(); + } + return true; +} - const ListValue* handlers = prefs->GetList(pref_name); - if (handlers) { - for (size_t i = 0; i < handlers->GetSize(); ++i) { - DictionaryValue* dict; - if (!handlers->GetDictionary(i, &dict)) - continue; - if (ProtocolHandler::IsValidDict(dict)) { - result.push_back(dict); - } +ProtocolHandlerRegistry::ProtocolHandlerList +ProtocolHandlerRegistry::GetReplacedHandlers( + const ProtocolHandler& handler) const { + ProtocolHandlerList replaced_handlers; + const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); + if (!handlers) + return replaced_handlers; + for (ProtocolHandlerList::const_iterator p = handlers->begin(); + p != handlers->end(); p++) { + if (handler.IsSameOrigin(*p)) { + replaced_handlers.push_back(*p); } } - return result; + return replaced_handlers; } -namespace { - -// If true default protocol handlers will be removed if the OS level -// registration for a protocol is no longer Chrome. -bool ShouldRemoveHandlersNotInOS() { -#if defined(OS_LINUX) - // We don't do this on Linux as the OS registration there is not reliable, - // and Chrome OS doesn't have any notion of OS registration. - // TODO(benwells): When Linux support is more reliable remove this - // difference (http://crbug.com/88255). - return false; -#else - return ShellIntegration::CanSetAsDefaultProtocolClient(); -#endif +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)); + Save(); + NotifyChanged(); } -} // namespace +bool ProtocolHandlerRegistry::IsDefault( + const ProtocolHandler& handler) const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return GetHandlerFor(handler.protocol()) == handler; +} void ProtocolHandlerRegistry::Load() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -243,30 +295,38 @@ void ProtocolHandlerRegistry::Load() { } } -void ProtocolHandlerRegistry::Save() { +int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (is_loading_) { - return; + const ProtocolHandler& handler = GetHandlerFor(scheme); + if (handler.IsEmpty()) + return -1; + const ProtocolHandlerList* handlers = GetHandlerList(scheme); + if (!handlers) + return -1; + + ProtocolHandlerList::const_iterator p; + int i; + for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) { + if (*p == handler) + return i; } - scoped_ptr<Value> registered_protocol_handlers(EncodeRegisteredHandlers()); - scoped_ptr<Value> ignored_protocol_handlers(EncodeIgnoredHandlers()); - scoped_ptr<Value> enabled(Value::CreateBooleanValue(enabled_)); - profile_->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers, - *registered_protocol_handlers); - profile_->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers, - *ignored_protocol_handlers); - profile_->GetPrefs()->Set(prefs::kCustomHandlersEnabled, *enabled); + return -1; } -bool ProtocolHandlerRegistry::CanSchemeBeOverridden( +ProtocolHandlerRegistry::ProtocolHandlerList +ProtocolHandlerRegistry::GetHandlersFor( const std::string& scheme) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - const ProtocolHandlerList* handlers = GetHandlerList(scheme); - // If we already have a handler for this scheme, we can add more. - if (handlers != NULL && !handlers->empty()) - return true; - // Don't override a scheme if it already has an external handler. - return !delegate_->IsExternalHandlerRegistered(scheme); + ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); + if (p == protocol_handlers_.end()) { + return ProtocolHandlerList(); + } + return p->second; +} + +ProtocolHandlerRegistry::ProtocolHandlerList +ProtocolHandlerRegistry::GetIgnoredHandlers() { + return ignored_protocol_handlers_; } void ProtocolHandlerRegistry::GetRegisteredProtocols( @@ -279,20 +339,15 @@ void ProtocolHandlerRegistry::GetRegisteredProtocols( } } -void ProtocolHandlerRegistry::RemoveIgnoredHandler( - const ProtocolHandler& handler) { +bool ProtocolHandlerRegistry::CanSchemeBeOverridden( + const std::string& scheme) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - bool should_notify = false; - ProtocolHandlerList::iterator p = std::find( - ignored_protocol_handlers_.begin(), ignored_protocol_handlers_.end(), - handler); - if (p != ignored_protocol_handlers_.end()) { - ignored_protocol_handlers_.erase(p); - Save(); - should_notify = true; - } - if (should_notify) - NotifyChanged(); + const ProtocolHandlerList* handlers = GetHandlerList(scheme); + // If we already have a handler for this scheme, we can add more. + if (handlers != NULL && !handlers->empty()) + return true; + // Don't override a scheme if it already has an external handler. + return !delegate_->IsExternalHandlerRegistered(scheme); } bool ProtocolHandlerRegistry::IsRegistered( @@ -306,6 +361,18 @@ bool ProtocolHandlerRegistry::IsRegistered( handlers->end(); } +bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + ProtocolHandlerList::const_iterator i; + for (i = ignored_protocol_handlers_.begin(); + i != ignored_protocol_handlers_.end(); ++i) { + if (*i == handler) { + return true; + } + } + return false; +} + bool ProtocolHandlerRegistry::HasRegisteredEquivalent( const ProtocolHandler& handler) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -322,29 +389,33 @@ bool ProtocolHandlerRegistry::HasRegisteredEquivalent( return false; } -bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const { +bool ProtocolHandlerRegistry::HasIgnoredEquivalent( + const ProtocolHandler& handler) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); ProtocolHandlerList::const_iterator i; for (i = ignored_protocol_handlers_.begin(); i != ignored_protocol_handlers_.end(); ++i) { - if (*i == handler) { + if (handler.IsEquivalent(*i)) { return true; } } return false; } -bool ProtocolHandlerRegistry::HasIgnoredEquivalent( - const ProtocolHandler& handler) const { +void ProtocolHandlerRegistry::RemoveIgnoredHandler( + const ProtocolHandler& handler) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ProtocolHandlerList::const_iterator i; - for (i = ignored_protocol_handlers_.begin(); - i != ignored_protocol_handlers_.end(); ++i) { - if (handler.IsEquivalent(*i)) { - return true; - } + bool should_notify = false; + ProtocolHandlerList::iterator p = std::find( + ignored_protocol_handlers_.begin(), ignored_protocol_handlers_.end(), + handler); + if (p != ignored_protocol_handlers_.end()) { + ignored_protocol_handlers_.erase(p); + Save(); + should_notify = true; } - return false; + if (should_notify) + NotifyChanged(); } bool ProtocolHandlerRegistry::IsHandledProtocol( @@ -353,6 +424,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)); @@ -391,120 +468,76 @@ void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) { RemoveHandler(current_default); } -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; - } - return ProtocolHandler::EmptyProtocolHandler(); -} - -Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() { +const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor( + const std::string& scheme) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ListValue* protocol_handlers = new ListValue(); - for (ProtocolHandlerMultiMap::iterator i = protocol_handlers_.begin(); - i != protocol_handlers_.end(); ++i) { - for (ProtocolHandlerList::iterator j = i->second.begin(); - j != i->second.end(); ++j) { - DictionaryValue* encoded = j->Encode(); - if (IsDefault(*j)) { - encoded->Set("default", Value::CreateBooleanValue(true)); - } - protocol_handlers->Append(encoded); - } - } - return protocol_handlers; + return LookupHandler(default_handlers_, scheme); } -Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ListValue* handlers = new ListValue(); - for (ProtocolHandlerList::iterator i = ignored_protocol_handlers_.begin(); - i != ignored_protocol_handlers_.end(); ++i) { - handlers->Append(i->Encode()); +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; } - return handlers; -} - -bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest( - const ProtocolHandler& handler) { - if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol())) - return true; - - if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler)) - return true; - - if (AttemptReplace(handler)) - return true; - - return false; -} - -void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler( - const ProtocolHandler& handler) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - RegisterProtocolHandler(handler); - SetDefault(handler); - Save(); - NotifyChanged(); + GURL translated_url(handler.TranslateUrl(request->url())); + if (!translated_url.is_valid()) { + return NULL; + } + return new net::URLRequestRedirectJob(request, translated_url); } -void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler( - const ProtocolHandler& handler) { +void ProtocolHandlerRegistry::Enable() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - RegisterProtocolHandler(handler); + if (enabled_) { + return; + } + enabled_ = true; + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&ProtocolHandlerRegistry::EnableIO, this)); + ProtocolHandlerMap::const_iterator p; + for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { + delegate_->RegisterExternalHandler(p->first); + } Save(); NotifyChanged(); } -void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler( - const ProtocolHandler& handler) { +void ProtocolHandlerRegistry::Disable() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - IgnoreProtocolHandler(handler); + if (!enabled_) { + return; + } + enabled_ = false; + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&ProtocolHandlerRegistry::DisableIO, this)); + ProtocolHandlerMap::const_iterator p; + for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { + delegate_->DeregisterExternalHandler(p->first); + } Save(); NotifyChanged(); } -bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) { +void ProtocolHandlerRegistry::Finalize() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ProtocolHandler old_default = GetHandlerFor(handler.protocol()); - bool make_new_handler_default = handler.IsSameOrigin(old_default); - ProtocolHandlerList to_replace(GetReplacedHandlers(handler)); - if (to_replace.empty()) - return false; - for (ProtocolHandlerList::iterator p = to_replace.begin(); - p != to_replace.end(); ++p) { - RemoveHandler(*p); - } - if (make_new_handler_default) { - OnAcceptRegisterProtocolHandler(handler); - } else { - InsertHandler(handler); - NotifyChanged(); - } - return true; -} - -ProtocolHandlerRegistry::ProtocolHandlerList -ProtocolHandlerRegistry::GetReplacedHandlers( - const ProtocolHandler& handler) const { - ProtocolHandlerList replaced_handlers; - const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); - if (!handlers) - return replaced_handlers; - for (ProtocolHandlerList::const_iterator p = handlers->begin(); - p != handlers->end(); p++) { - if (handler.IsSameOrigin(*p)) { - replaced_handlers.push_back(*p); - } + delegate_.reset(NULL); + // We free these now in case there are any outstanding workers running. If + // we didn't free them they could respond to workers and try to update the + // protocol handler registry after it was deleted. + // Observers remove themselves from this list when they are deleted; so + // we delete the last item until none are left in the list. + while (!default_client_observers_.empty()) { + delete default_client_observers_.back(); } - return replaced_handlers; } - // static void ProtocolHandlerRegistry::RegisterPrefs(PrefService* pref_service) { pref_service->RegisterListPref(prefs::kRegisteredProtocolHandlers, @@ -515,62 +548,9 @@ void ProtocolHandlerRegistry::RegisterPrefs(PrefService* pref_service) { PrefService::UNSYNCABLE_PREF); } -void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ProtocolHandlerMap::const_iterator p = default_handlers_.find( - handler.protocol()); - // If we're not loading, and we are setting a default for a new protocol, - // register with the OS. - if (!is_loading_ && p == default_handlers_.end()) - delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this); - default_handlers_.erase(handler.protocol()); - default_handlers_.insert(std::make_pair(handler.protocol(), handler)); - PromoteHandler(handler); - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&ProtocolHandlerRegistry::SetDefaultIO, this, handler)); -} - -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)); - Save(); - NotifyChanged(); -} - -bool ProtocolHandlerRegistry::IsDefault( - const ProtocolHandler& handler) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - return GetHandlerFor(handler.protocol()) == handler; -} - -const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor( - const std::string& scheme) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - return LookupHandler(default_handlers_, scheme); -} - -int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - const ProtocolHandler& handler = GetHandlerFor(scheme); - if (handler.IsEmpty()) - return -1; - const ProtocolHandlerList* handlers = GetHandlerList(scheme); - if (!handlers) - return -1; - - ProtocolHandlerList::const_iterator p; - int i; - for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) { - if (*p == handler) - return i; - } - return -1; +ProtocolHandlerRegistry::~ProtocolHandlerRegistry() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(default_client_observers_.empty()); } void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) { @@ -583,16 +563,6 @@ void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) { list.insert(list.begin(), handler); } -void ProtocolHandlerRegistry::NotifyChanged() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, - content::Source<Profile>(profile_), - content::NotificationService::NoDetails()); -} - -// IO thread methods ----------------------------------------------------------- - void ProtocolHandlerRegistry::ClearDefaultIO(const std::string& scheme) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); default_handlers_io_.erase(scheme); @@ -604,110 +574,137 @@ void ProtocolHandlerRegistry::SetDefaultIO(const ProtocolHandler& handler) { default_handlers_io_.insert(std::make_pair(handler.protocol(), handler)); } -bool ProtocolHandlerRegistry::IsHandledProtocolIO( - const std::string& scheme) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - return enabled_io_ && !LookupHandler(default_handlers_io_, scheme).IsEmpty(); +void ProtocolHandlerRegistry::Save() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (is_loading_) { + return; + } + scoped_ptr<Value> registered_protocol_handlers(EncodeRegisteredHandlers()); + scoped_ptr<Value> ignored_protocol_handlers(EncodeIgnoredHandlers()); + scoped_ptr<Value> enabled(Value::CreateBooleanValue(enabled_)); + profile_->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers, + *registered_protocol_handlers); + profile_->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers, + *ignored_protocol_handlers); + profile_->GetPrefs()->Set(prefs::kCustomHandlersEnabled, *enabled); } -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()) { +const ProtocolHandlerRegistry::ProtocolHandlerList* +ProtocolHandlerRegistry::GetHandlerList( + const std::string& scheme) const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); + if (p == protocol_handlers_.end()) { return NULL; } - return new net::URLRequestRedirectJob(request, translated_url); + return &p->second; } -// Delegate -------------------------------------------------------------------- - -ProtocolHandlerRegistry::Delegate::~Delegate() { +void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + ProtocolHandlerMap::const_iterator p = default_handlers_.find( + handler.protocol()); + // If we're not loading, and we are setting a default for a new protocol, + // register with the OS. + if (!is_loading_ && p == default_handlers_.end()) + delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this); + default_handlers_.erase(handler.protocol()); + default_handlers_.insert(std::make_pair(handler.protocol(), handler)); + PromoteHandler(handler); + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&ProtocolHandlerRegistry::SetDefaultIO, this, handler)); } -void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler( - const std::string& protocol) { - ChildProcessSecurityPolicy* policy = - ChildProcessSecurityPolicy::GetInstance(); - if (!policy->IsWebSafeScheme(protocol)) { - policy->RegisterWebSafeScheme(protocol); - } -} +void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + ProtocolHandlerMultiMap::iterator p = + protocol_handlers_.find(handler.protocol()); -void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler( - const std::string& protocol) { -} + if (p != protocol_handlers_.end()) { + p->second.push_back(handler); + return; + } -ShellIntegration::DefaultProtocolClientWorker* -ProtocolHandlerRegistry::Delegate::CreateShellWorker( - ShellIntegration::DefaultWebClientObserver* observer, - const std::string& protocol) { - return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol); + ProtocolHandlerList new_list; + new_list.push_back(handler); + protocol_handlers_[handler.protocol()] = new_list; } -ProtocolHandlerRegistry::DefaultClientObserver* -ProtocolHandlerRegistry::Delegate::CreateShellObserver( - ProtocolHandlerRegistry* registry) { - return new DefaultClientObserver(registry); +Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + ListValue* protocol_handlers = new ListValue(); + for (ProtocolHandlerMultiMap::iterator i = protocol_handlers_.begin(); + i != protocol_handlers_.end(); ++i) { + for (ProtocolHandlerList::iterator j = i->second.begin(); + j != i->second.end(); ++j) { + DictionaryValue* encoded = j->Encode(); + if (IsDefault(*j)) { + encoded->Set("default", Value::CreateBooleanValue(true)); + } + protocol_handlers->Append(encoded); + } + } + return protocol_handlers; } -void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient( - const std::string& protocol, ProtocolHandlerRegistry* registry) { - DefaultClientObserver* observer = CreateShellObserver(registry); - // The worker pointer is reference counted. While it is running the - // message loops of the FILE and UI thread will hold references to it - // and it will be automatically freed once all its tasks have finished. - scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; - worker = CreateShellWorker(observer, protocol); - observer->SetWorker(worker); - registry->default_client_observers_.push_back(observer); - worker->StartSetAsDefault(); +Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + ListValue* handlers = new ListValue(); + for (ProtocolHandlerList::iterator i = ignored_protocol_handlers_.begin(); + i != ignored_protocol_handlers_.end(); ++i) { + handlers->Append(i->Encode()); + } + return handlers; } -bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered( - const std::string& protocol) { - // NOTE(koz): This function is safe to call from any thread, despite living - // in ProfileIOData. - return ProfileIOData::IsHandledProtocol(protocol); +void ProtocolHandlerRegistry::NotifyChanged() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, + content::Source<Profile>(profile_), + content::NotificationService::NoDetails()); } -// DefaultClientObserver ------------------------------------------------------ - -ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver( - ProtocolHandlerRegistry* registry) - : worker_(NULL), registry_(registry) { - DCHECK(registry_); +void ProtocolHandlerRegistry::RegisterProtocolHandler( + const ProtocolHandler& handler) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(CanSchemeBeOverridden(handler.protocol())); + DCHECK(!handler.IsEmpty()); + if (IsRegistered(handler)) { + return; + } + if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol())) + delegate_->RegisterExternalHandler(handler.protocol()); + InsertHandler(handler); } -ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() { - if (worker_) { - worker_->ObserverDestroyed(); - }; - DefaultClientObserverList::iterator iter = std::find( - registry_->default_client_observers_.begin(), - registry_->default_client_observers_.end(), this); - registry_->default_client_observers_.erase(iter); -} +std::vector<const DictionaryValue*> +ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + std::vector<const DictionaryValue*> result; + PrefService* prefs = profile_->GetPrefs(); + if (!prefs->HasPrefPath(pref_name)) { + return result; + } -void -ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState( - ShellIntegration::DefaultWebClientUIState state) { - if (worker_) { - if (ShouldRemoveHandlersNotInOS() && - (state == ShellIntegration::STATE_NOT_DEFAULT)) { - registry_->ClearDefault(worker_->protocol()); + const ListValue* handlers = prefs->GetList(pref_name); + if (handlers) { + for (size_t i = 0; i < handlers->GetSize(); ++i) { + DictionaryValue* dict; + if (!handlers->GetDictionary(i, &dict)) + continue; + if (ProtocolHandler::IsValidDict(dict)) { + result.push_back(dict); + } } - } else { - NOTREACHED(); } + return result; } -void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker( - ShellIntegration::DefaultProtocolClientWorker* worker) { - worker_ = worker; +void ProtocolHandlerRegistry::IgnoreProtocolHandler( + const ProtocolHandler& handler) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + ignored_protocol_handlers_.push_back(handler); } |