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 d81af988fc58af5d2e7f30e6b30679ff451d30bf..ab8753a58b5fab79be1633c088a6bdec5088e091 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)); |
+ 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::ProtocolHandlerList |
+ProtocolHandlerRegistry::GetHandlersFor( |
+ const std::string& scheme) const { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (is_loading_) { |
- return; |
+ ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); |
+ if (p == protocol_handlers_.end()) { |
+ return ProtocolHandlerList(); |
} |
- 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 p->second; |
} |
-bool ProtocolHandlerRegistry::CanSchemeBeOverridden( |
- 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); |
+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,186 +468,89 @@ 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() { |
- 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; |
-} |
- |
-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::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(); |
-} |
- |
-void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler( |
- const ProtocolHandler& handler) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- RegisterProtocolHandler(handler); |
- Save(); |
- NotifyChanged(); |
-} |
- |
-void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler( |
- const ProtocolHandler& handler) { |
+const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor( |
+ const std::string& scheme) const { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- IgnoreProtocolHandler(handler); |
- Save(); |
- NotifyChanged(); |
+ return LookupHandler(default_handlers_, scheme); |
} |
-bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) { |
- 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(); |
+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 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); |
- } |
+ GURL translated_url(handler.TranslateUrl(request->url())); |
+ if (!translated_url.is_valid()) { |
+ return NULL; |
} |
- return replaced_handlers; |
-} |
- |
- |
-// static |
-void ProtocolHandlerRegistry::RegisterPrefs(PrefService* pref_service) { |
- pref_service->RegisterListPref(prefs::kRegisteredProtocolHandlers, |
- PrefService::UNSYNCABLE_PREF); |
- pref_service->RegisterListPref(prefs::kIgnoredProtocolHandlers, |
- PrefService::UNSYNCABLE_PREF); |
- pref_service->RegisterBooleanPref(prefs::kCustomHandlersEnabled, true, |
- PrefService::UNSYNCABLE_PREF); |
+ return new net::URLRequestRedirectJob(request, translated_url); |
} |
-void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) { |
+void ProtocolHandlerRegistry::Enable() { |
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); |
+ if (enabled_) { |
+ return; |
+ } |
+ enabled_ = true; |
BrowserThread::PostTask( |
BrowserThread::IO, |
FROM_HERE, |
- base::Bind(&ProtocolHandlerRegistry::SetDefaultIO, this, handler)); |
+ 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::ClearDefault(const std::string& scheme) { |
+void ProtocolHandlerRegistry::Disable() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- default_handlers_.erase(scheme); |
+ if (!enabled_) { |
+ return; |
+ } |
+ enabled_ = false; |
BrowserThread::PostTask( |
BrowserThread::IO, |
FROM_HERE, |
- base::Bind(&ProtocolHandlerRegistry::ClearDefaultIO, this, scheme)); |
+ 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::IsDefault( |
- const ProtocolHandler& handler) const { |
+void ProtocolHandlerRegistry::Finalize() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- return GetHandlerFor(handler.protocol()) == handler; |
+ 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(); |
+ } |
} |
-const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor( |
- const std::string& scheme) const { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- return LookupHandler(default_handlers_, scheme); |
+// static |
+void ProtocolHandlerRegistry::RegisterPrefs(PrefService* pref_service) { |
+ pref_service->RegisterListPref(prefs::kRegisteredProtocolHandlers, |
+ PrefService::UNSYNCABLE_PREF); |
+ pref_service->RegisterListPref(prefs::kIgnoredProtocolHandlers, |
+ PrefService::UNSYNCABLE_PREF); |
+ pref_service->RegisterBooleanPref(prefs::kCustomHandlersEnabled, true, |
+ PrefService::UNSYNCABLE_PREF); |
} |
-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); |
} |