| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/custom_handlers/protocol_handler_registry.h" | 5 #include "chrome/browser/custom_handlers/protocol_handler_registry.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "chrome/browser/custom_handlers/register_protocol_handler_infobar_deleg
ate.h" | 13 #include "chrome/browser/custom_handlers/register_protocol_handler_infobar_deleg
ate.h" |
| 14 #include "chrome/browser/net/chrome_url_request_context.h" | 14 #include "chrome/browser/net/chrome_url_request_context.h" |
| 15 #include "chrome/browser/prefs/pref_service.h" | 15 #include "chrome/browser/prefs/pref_service.h" |
| 16 #include "chrome/browser/profiles/profile_io_data.h" | 16 #include "chrome/browser/profiles/profile_io_data.h" |
| 17 #include "chrome/common/chrome_notification_types.h" | 17 #include "chrome/common/chrome_notification_types.h" |
| 18 #include "chrome/common/chrome_switches.h" | 18 #include "chrome/common/chrome_switches.h" |
| 19 #include "chrome/common/custom_handlers/protocol_handler.h" | 19 #include "chrome/common/custom_handlers/protocol_handler.h" |
| 20 #include "chrome/common/pref_names.h" | 20 #include "chrome/common/pref_names.h" |
| 21 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
| 22 #include "content/public/browser/child_process_security_policy.h" | 22 #include "content/public/browser/child_process_security_policy.h" |
| 23 #include "content/public/browser/notification_service.h" | 23 #include "content/public/browser/notification_service.h" |
| 24 #include "net/base/network_delegate.h" | 24 #include "net/base/network_delegate.h" |
| 25 #include "net/url_request/url_request_redirect_job.h" | 25 #include "net/url_request/url_request_redirect_job.h" |
| 26 | 26 |
| 27 using content::BrowserThread; | 27 using content::BrowserThread; |
| 28 using content::ChildProcessSecurityPolicy; | 28 using content::ChildProcessSecurityPolicy; |
| 29 | 29 |
| 30 // ProtocolHandlerRegistry ----------------------------------------------------- | |
| 31 | |
| 32 ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile, | |
| 33 Delegate* delegate) | |
| 34 : profile_(profile), | |
| 35 delegate_(delegate), | |
| 36 enabled_(true), | |
| 37 enabled_io_(enabled_), | |
| 38 is_loading_(false) { | |
| 39 } | |
| 40 | |
| 41 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() { | |
| 42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 43 DCHECK(default_client_observers_.empty()); | |
| 44 } | |
| 45 | |
| 46 void ProtocolHandlerRegistry::Finalize() { | |
| 47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 48 delegate_.reset(NULL); | |
| 49 // We free these now in case there are any outstanding workers running. If | |
| 50 // we didn't free them they could respond to workers and try to update the | |
| 51 // protocol handler registry after it was deleted. | |
| 52 // Observers remove themselves from this list when they are deleted; so | |
| 53 // we delete the last item until none are left in the list. | |
| 54 while (!default_client_observers_.empty()) { | |
| 55 delete default_client_observers_.back(); | |
| 56 } | |
| 57 } | |
| 58 | |
| 59 const ProtocolHandlerRegistry::ProtocolHandlerList* | |
| 60 ProtocolHandlerRegistry::GetHandlerList( | |
| 61 const std::string& scheme) const { | |
| 62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 63 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); | |
| 64 if (p == protocol_handlers_.end()) { | |
| 65 return NULL; | |
| 66 } | |
| 67 return &p->second; | |
| 68 } | |
| 69 | |
| 70 ProtocolHandlerRegistry::ProtocolHandlerList | |
| 71 ProtocolHandlerRegistry::GetHandlersFor( | |
| 72 const std::string& scheme) const { | |
| 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 74 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); | |
| 75 if (p == protocol_handlers_.end()) { | |
| 76 return ProtocolHandlerList(); | |
| 77 } | |
| 78 return p->second; | |
| 79 } | |
| 80 | |
| 81 ProtocolHandlerRegistry::ProtocolHandlerList | |
| 82 ProtocolHandlerRegistry::GetIgnoredHandlers() { | |
| 83 return ignored_protocol_handlers_; | |
| 84 } | |
| 85 | |
| 86 void ProtocolHandlerRegistry::RegisterProtocolHandler( | |
| 87 const ProtocolHandler& handler) { | |
| 88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 89 DCHECK(CanSchemeBeOverridden(handler.protocol())); | |
| 90 DCHECK(!handler.IsEmpty()); | |
| 91 if (IsRegistered(handler)) { | |
| 92 return; | |
| 93 } | |
| 94 if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol())) | |
| 95 delegate_->RegisterExternalHandler(handler.protocol()); | |
| 96 InsertHandler(handler); | |
| 97 } | |
| 98 | |
| 99 void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) { | |
| 100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 101 ProtocolHandlerMultiMap::iterator p = | |
| 102 protocol_handlers_.find(handler.protocol()); | |
| 103 | |
| 104 if (p != protocol_handlers_.end()) { | |
| 105 p->second.push_back(handler); | |
| 106 return; | |
| 107 } | |
| 108 | |
| 109 ProtocolHandlerList new_list; | |
| 110 new_list.push_back(handler); | |
| 111 protocol_handlers_[handler.protocol()] = new_list; | |
| 112 } | |
| 113 | |
| 114 void ProtocolHandlerRegistry::IgnoreProtocolHandler( | |
| 115 const ProtocolHandler& handler) { | |
| 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 117 ignored_protocol_handlers_.push_back(handler); | |
| 118 } | |
| 119 | |
| 120 void ProtocolHandlerRegistry::Enable() { | |
| 121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 122 if (enabled_) { | |
| 123 return; | |
| 124 } | |
| 125 enabled_ = true; | |
| 126 BrowserThread::PostTask( | |
| 127 BrowserThread::IO, | |
| 128 FROM_HERE, | |
| 129 base::Bind(&ProtocolHandlerRegistry::EnableIO, this)); | |
| 130 ProtocolHandlerMap::const_iterator p; | |
| 131 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { | |
| 132 delegate_->RegisterExternalHandler(p->first); | |
| 133 } | |
| 134 Save(); | |
| 135 NotifyChanged(); | |
| 136 } | |
| 137 | |
| 138 void ProtocolHandlerRegistry::Disable() { | |
| 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 140 if (!enabled_) { | |
| 141 return; | |
| 142 } | |
| 143 enabled_ = false; | |
| 144 BrowserThread::PostTask( | |
| 145 BrowserThread::IO, | |
| 146 FROM_HERE, | |
| 147 base::Bind(&ProtocolHandlerRegistry::DisableIO, this)); | |
| 148 ProtocolHandlerMap::const_iterator p; | |
| 149 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { | |
| 150 delegate_->DeregisterExternalHandler(p->first); | |
| 151 } | |
| 152 Save(); | |
| 153 NotifyChanged(); | |
| 154 } | |
| 155 | |
| 156 std::vector<const DictionaryValue*> | |
| 157 ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const { | |
| 158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 159 std::vector<const DictionaryValue*> result; | |
| 160 PrefService* prefs = profile_->GetPrefs(); | |
| 161 if (!prefs->HasPrefPath(pref_name)) { | |
| 162 return result; | |
| 163 } | |
| 164 | |
| 165 const ListValue* handlers = prefs->GetList(pref_name); | |
| 166 if (handlers) { | |
| 167 for (size_t i = 0; i < handlers->GetSize(); ++i) { | |
| 168 DictionaryValue* dict; | |
| 169 if (!handlers->GetDictionary(i, &dict)) | |
| 170 continue; | |
| 171 if (ProtocolHandler::IsValidDict(dict)) { | |
| 172 result.push_back(dict); | |
| 173 } | |
| 174 } | |
| 175 } | |
| 176 return result; | |
| 177 } | |
| 178 | |
| 179 namespace { | 30 namespace { |
| 180 | 31 |
| 181 // If true default protocol handlers will be removed if the OS level | 32 // If true default protocol handlers will be removed if the OS level |
| 182 // registration for a protocol is no longer Chrome. | 33 // registration for a protocol is no longer Chrome. |
| 183 bool ShouldRemoveHandlersNotInOS() { | 34 bool ShouldRemoveHandlersNotInOS() { |
| 184 #if defined(OS_LINUX) | 35 #if defined(OS_LINUX) |
| 185 // We don't do this on Linux as the OS registration there is not reliable, | 36 // We don't do this on Linux as the OS registration there is not reliable, |
| 186 // and Chrome OS doesn't have any notion of OS registration. | 37 // and Chrome OS doesn't have any notion of OS registration. |
| 187 // TODO(benwells): When Linux support is more reliable remove this | 38 // TODO(benwells): When Linux support is more reliable remove this |
| 188 // difference (http://crbug.com/88255). | 39 // difference (http://crbug.com/88255). |
| 189 return false; | 40 return false; |
| 190 #else | 41 #else |
| 191 return ShellIntegration::CanSetAsDefaultProtocolClient(); | 42 return ShellIntegration::CanSetAsDefaultProtocolClient(); |
| 192 #endif | 43 #endif |
| 193 } | 44 } |
| 194 | 45 |
| 195 } // namespace | 46 } // namespace |
| 196 | 47 |
| 48 static const ProtocolHandler& LookupHandler( |
| 49 const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map, |
| 50 const std::string& scheme) { |
| 51 ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p = |
| 52 handler_map.find(scheme); |
| 53 if (p != handler_map.end()) { |
| 54 return p->second; |
| 55 } |
| 56 return ProtocolHandler::EmptyProtocolHandler(); |
| 57 } |
| 58 |
| 59 // DefaultClientObserver ------------------------------------------------------ |
| 60 |
| 61 ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver( |
| 62 ProtocolHandlerRegistry* registry) |
| 63 : worker_(NULL), |
| 64 registry_(registry) { |
| 65 DCHECK(registry_); |
| 66 } |
| 67 |
| 68 ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() { |
| 69 if (worker_) |
| 70 worker_->ObserverDestroyed(); |
| 71 |
| 72 DefaultClientObserverList::iterator iter = std::find( |
| 73 registry_->default_client_observers_.begin(), |
| 74 registry_->default_client_observers_.end(), this); |
| 75 registry_->default_client_observers_.erase(iter); |
| 76 } |
| 77 |
| 78 void |
| 79 ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState( |
| 80 ShellIntegration::DefaultWebClientUIState state) { |
| 81 if (worker_) { |
| 82 if (ShouldRemoveHandlersNotInOS() && |
| 83 (state == ShellIntegration::STATE_NOT_DEFAULT)) { |
| 84 registry_->ClearDefault(worker_->protocol()); |
| 85 } |
| 86 } else { |
| 87 NOTREACHED(); |
| 88 } |
| 89 } |
| 90 |
| 91 void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker( |
| 92 ShellIntegration::DefaultProtocolClientWorker* worker) { |
| 93 worker_ = worker; |
| 94 } |
| 95 |
| 96 // Delegate -------------------------------------------------------------------- |
| 97 |
| 98 ProtocolHandlerRegistry::Delegate::~Delegate() {} |
| 99 |
| 100 void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler( |
| 101 const std::string& protocol) { |
| 102 ChildProcessSecurityPolicy* policy = |
| 103 ChildProcessSecurityPolicy::GetInstance(); |
| 104 if (!policy->IsWebSafeScheme(protocol)) { |
| 105 policy->RegisterWebSafeScheme(protocol); |
| 106 } |
| 107 } |
| 108 |
| 109 void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler( |
| 110 const std::string& protocol) { |
| 111 } |
| 112 |
| 113 bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered( |
| 114 const std::string& protocol) { |
| 115 // NOTE(koz): This function is safe to call from any thread, despite living |
| 116 // in ProfileIOData. |
| 117 return ProfileIOData::IsHandledProtocol(protocol); |
| 118 } |
| 119 |
| 120 ShellIntegration::DefaultProtocolClientWorker* |
| 121 ProtocolHandlerRegistry::Delegate::CreateShellWorker( |
| 122 ShellIntegration::DefaultWebClientObserver* observer, |
| 123 const std::string& protocol) { |
| 124 return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol); |
| 125 } |
| 126 |
| 127 ProtocolHandlerRegistry::DefaultClientObserver* |
| 128 ProtocolHandlerRegistry::Delegate::CreateShellObserver( |
| 129 ProtocolHandlerRegistry* registry) { |
| 130 return new DefaultClientObserver(registry); |
| 131 } |
| 132 |
| 133 void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient( |
| 134 const std::string& protocol, ProtocolHandlerRegistry* registry) { |
| 135 DefaultClientObserver* observer = CreateShellObserver(registry); |
| 136 // The worker pointer is reference counted. While it is running the |
| 137 // message loops of the FILE and UI thread will hold references to it |
| 138 // and it will be automatically freed once all its tasks have finished. |
| 139 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; |
| 140 worker = CreateShellWorker(observer, protocol); |
| 141 observer->SetWorker(worker); |
| 142 registry->default_client_observers_.push_back(observer); |
| 143 worker->StartSetAsDefault(); |
| 144 } |
| 145 |
| 146 // ProtocolHandlerRegistry ----------------------------------------------------- |
| 147 |
| 148 ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile, |
| 149 Delegate* delegate) |
| 150 : profile_(profile), |
| 151 delegate_(delegate), |
| 152 enabled_(true), |
| 153 enabled_io_(enabled_), |
| 154 is_loading_(false) { |
| 155 } |
| 156 |
| 157 bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest( |
| 158 const ProtocolHandler& handler) { |
| 159 if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol())) |
| 160 return true; |
| 161 |
| 162 if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler)) |
| 163 return true; |
| 164 |
| 165 if (AttemptReplace(handler)) |
| 166 return true; |
| 167 |
| 168 return false; |
| 169 } |
| 170 |
| 171 void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler( |
| 172 const ProtocolHandler& handler) { |
| 173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 174 RegisterProtocolHandler(handler); |
| 175 SetDefault(handler); |
| 176 Save(); |
| 177 NotifyChanged(); |
| 178 } |
| 179 |
| 180 void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler( |
| 181 const ProtocolHandler& handler) { |
| 182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 183 RegisterProtocolHandler(handler); |
| 184 Save(); |
| 185 NotifyChanged(); |
| 186 } |
| 187 |
| 188 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler( |
| 189 const ProtocolHandler& handler) { |
| 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 191 IgnoreProtocolHandler(handler); |
| 192 Save(); |
| 193 NotifyChanged(); |
| 194 } |
| 195 |
| 196 bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) { |
| 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 198 ProtocolHandler old_default = GetHandlerFor(handler.protocol()); |
| 199 bool make_new_handler_default = handler.IsSameOrigin(old_default); |
| 200 ProtocolHandlerList to_replace(GetReplacedHandlers(handler)); |
| 201 if (to_replace.empty()) |
| 202 return false; |
| 203 for (ProtocolHandlerList::iterator p = to_replace.begin(); |
| 204 p != to_replace.end(); ++p) { |
| 205 RemoveHandler(*p); |
| 206 } |
| 207 if (make_new_handler_default) { |
| 208 OnAcceptRegisterProtocolHandler(handler); |
| 209 } else { |
| 210 InsertHandler(handler); |
| 211 NotifyChanged(); |
| 212 } |
| 213 return true; |
| 214 } |
| 215 |
| 216 ProtocolHandlerRegistry::ProtocolHandlerList |
| 217 ProtocolHandlerRegistry::GetReplacedHandlers( |
| 218 const ProtocolHandler& handler) const { |
| 219 ProtocolHandlerList replaced_handlers; |
| 220 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); |
| 221 if (!handlers) |
| 222 return replaced_handlers; |
| 223 for (ProtocolHandlerList::const_iterator p = handlers->begin(); |
| 224 p != handlers->end(); p++) { |
| 225 if (handler.IsSameOrigin(*p)) { |
| 226 replaced_handlers.push_back(*p); |
| 227 } |
| 228 } |
| 229 return replaced_handlers; |
| 230 } |
| 231 |
| 232 void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) { |
| 233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 234 default_handlers_.erase(scheme); |
| 235 BrowserThread::PostTask( |
| 236 BrowserThread::IO, |
| 237 FROM_HERE, |
| 238 base::Bind(&ProtocolHandlerRegistry::ClearDefaultIO, this, scheme)); |
| 239 Save(); |
| 240 NotifyChanged(); |
| 241 } |
| 242 |
| 243 bool ProtocolHandlerRegistry::IsDefault( |
| 244 const ProtocolHandler& handler) const { |
| 245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 246 return GetHandlerFor(handler.protocol()) == handler; |
| 247 } |
| 248 |
| 197 void ProtocolHandlerRegistry::Load() { | 249 void ProtocolHandlerRegistry::Load() { |
| 198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 199 is_loading_ = true; | 251 is_loading_ = true; |
| 200 PrefService* prefs = profile_->GetPrefs(); | 252 PrefService* prefs = profile_->GetPrefs(); |
| 201 if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) { | 253 if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) { |
| 202 enabled_ = prefs->GetBoolean(prefs::kCustomHandlersEnabled); | 254 enabled_ = prefs->GetBoolean(prefs::kCustomHandlersEnabled); |
| 203 BrowserThread::PostTask( | 255 BrowserThread::PostTask( |
| 204 BrowserThread::IO, | 256 BrowserThread::IO, |
| 205 FROM_HERE, | 257 FROM_HERE, |
| 206 base::Bind(enabled_ ? &ProtocolHandlerRegistry::EnableIO : | 258 base::Bind(enabled_ ? &ProtocolHandlerRegistry::EnableIO : |
| (...skipping 29 matching lines...) Expand all Loading... |
| 236 DefaultClientObserver* observer = delegate_->CreateShellObserver(this); | 288 DefaultClientObserver* observer = delegate_->CreateShellObserver(this); |
| 237 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; | 289 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; |
| 238 worker = delegate_->CreateShellWorker(observer, handler.protocol()); | 290 worker = delegate_->CreateShellWorker(observer, handler.protocol()); |
| 239 observer->SetWorker(worker); | 291 observer->SetWorker(worker); |
| 240 default_client_observers_.push_back(observer); | 292 default_client_observers_.push_back(observer); |
| 241 worker->StartCheckIsDefault(); | 293 worker->StartCheckIsDefault(); |
| 242 } | 294 } |
| 243 } | 295 } |
| 244 } | 296 } |
| 245 | 297 |
| 246 void ProtocolHandlerRegistry::Save() { | 298 int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const { |
| 247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 248 if (is_loading_) { | 300 const ProtocolHandler& handler = GetHandlerFor(scheme); |
| 249 return; | 301 if (handler.IsEmpty()) |
| 302 return -1; |
| 303 const ProtocolHandlerList* handlers = GetHandlerList(scheme); |
| 304 if (!handlers) |
| 305 return -1; |
| 306 |
| 307 ProtocolHandlerList::const_iterator p; |
| 308 int i; |
| 309 for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) { |
| 310 if (*p == handler) |
| 311 return i; |
| 250 } | 312 } |
| 251 scoped_ptr<Value> registered_protocol_handlers(EncodeRegisteredHandlers()); | 313 return -1; |
| 252 scoped_ptr<Value> ignored_protocol_handlers(EncodeIgnoredHandlers()); | |
| 253 scoped_ptr<Value> enabled(Value::CreateBooleanValue(enabled_)); | |
| 254 profile_->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers, | |
| 255 *registered_protocol_handlers); | |
| 256 profile_->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers, | |
| 257 *ignored_protocol_handlers); | |
| 258 profile_->GetPrefs()->Set(prefs::kCustomHandlersEnabled, *enabled); | |
| 259 } | 314 } |
| 260 | 315 |
| 261 bool ProtocolHandlerRegistry::CanSchemeBeOverridden( | 316 ProtocolHandlerRegistry::ProtocolHandlerList |
| 317 ProtocolHandlerRegistry::GetHandlersFor( |
| 262 const std::string& scheme) const { | 318 const std::string& scheme) const { |
| 263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 264 const ProtocolHandlerList* handlers = GetHandlerList(scheme); | 320 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); |
| 265 // If we already have a handler for this scheme, we can add more. | 321 if (p == protocol_handlers_.end()) { |
| 266 if (handlers != NULL && !handlers->empty()) | 322 return ProtocolHandlerList(); |
| 267 return true; | 323 } |
| 268 // Don't override a scheme if it already has an external handler. | 324 return p->second; |
| 269 return !delegate_->IsExternalHandlerRegistered(scheme); | 325 } |
| 326 |
| 327 ProtocolHandlerRegistry::ProtocolHandlerList |
| 328 ProtocolHandlerRegistry::GetIgnoredHandlers() { |
| 329 return ignored_protocol_handlers_; |
| 270 } | 330 } |
| 271 | 331 |
| 272 void ProtocolHandlerRegistry::GetRegisteredProtocols( | 332 void ProtocolHandlerRegistry::GetRegisteredProtocols( |
| 273 std::vector<std::string>* output) const { | 333 std::vector<std::string>* output) const { |
| 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 275 ProtocolHandlerMultiMap::const_iterator p; | 335 ProtocolHandlerMultiMap::const_iterator p; |
| 276 for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) { | 336 for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) { |
| 277 if (!p->second.empty()) | 337 if (!p->second.empty()) |
| 278 output->push_back(p->first); | 338 output->push_back(p->first); |
| 279 } | 339 } |
| 280 } | 340 } |
| 281 | 341 |
| 282 void ProtocolHandlerRegistry::RemoveIgnoredHandler( | 342 bool ProtocolHandlerRegistry::CanSchemeBeOverridden( |
| 283 const ProtocolHandler& handler) { | 343 const std::string& scheme) const { |
| 284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 285 bool should_notify = false; | 345 const ProtocolHandlerList* handlers = GetHandlerList(scheme); |
| 286 ProtocolHandlerList::iterator p = std::find( | 346 // If we already have a handler for this scheme, we can add more. |
| 287 ignored_protocol_handlers_.begin(), ignored_protocol_handlers_.end(), | 347 if (handlers != NULL && !handlers->empty()) |
| 288 handler); | 348 return true; |
| 289 if (p != ignored_protocol_handlers_.end()) { | 349 // Don't override a scheme if it already has an external handler. |
| 290 ignored_protocol_handlers_.erase(p); | 350 return !delegate_->IsExternalHandlerRegistered(scheme); |
| 291 Save(); | |
| 292 should_notify = true; | |
| 293 } | |
| 294 if (should_notify) | |
| 295 NotifyChanged(); | |
| 296 } | 351 } |
| 297 | 352 |
| 298 bool ProtocolHandlerRegistry::IsRegistered( | 353 bool ProtocolHandlerRegistry::IsRegistered( |
| 299 const ProtocolHandler& handler) const { | 354 const ProtocolHandler& handler) const { |
| 300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 301 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); | 356 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); |
| 302 if (!handlers) { | 357 if (!handlers) { |
| 303 return false; | 358 return false; |
| 304 } | 359 } |
| 305 return std::find(handlers->begin(), handlers->end(), handler) != | 360 return std::find(handlers->begin(), handlers->end(), handler) != |
| 306 handlers->end(); | 361 handlers->end(); |
| 307 } | 362 } |
| 308 | 363 |
| 364 bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const { |
| 365 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 366 ProtocolHandlerList::const_iterator i; |
| 367 for (i = ignored_protocol_handlers_.begin(); |
| 368 i != ignored_protocol_handlers_.end(); ++i) { |
| 369 if (*i == handler) { |
| 370 return true; |
| 371 } |
| 372 } |
| 373 return false; |
| 374 } |
| 375 |
| 309 bool ProtocolHandlerRegistry::HasRegisteredEquivalent( | 376 bool ProtocolHandlerRegistry::HasRegisteredEquivalent( |
| 310 const ProtocolHandler& handler) const { | 377 const ProtocolHandler& handler) const { |
| 311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 312 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); | 379 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); |
| 313 if (!handlers) { | 380 if (!handlers) { |
| 314 return false; | 381 return false; |
| 315 } | 382 } |
| 316 ProtocolHandlerList::const_iterator i; | 383 ProtocolHandlerList::const_iterator i; |
| 317 for (i = handlers->begin(); i != handlers->end(); ++i) { | 384 for (i = handlers->begin(); i != handlers->end(); ++i) { |
| 318 if (handler.IsEquivalent(*i)) { | 385 if (handler.IsEquivalent(*i)) { |
| 319 return true; | 386 return true; |
| 320 } | 387 } |
| 321 } | 388 } |
| 322 return false; | 389 return false; |
| 323 } | 390 } |
| 324 | 391 |
| 325 bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const { | |
| 326 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 327 ProtocolHandlerList::const_iterator i; | |
| 328 for (i = ignored_protocol_handlers_.begin(); | |
| 329 i != ignored_protocol_handlers_.end(); ++i) { | |
| 330 if (*i == handler) { | |
| 331 return true; | |
| 332 } | |
| 333 } | |
| 334 return false; | |
| 335 } | |
| 336 | |
| 337 bool ProtocolHandlerRegistry::HasIgnoredEquivalent( | 392 bool ProtocolHandlerRegistry::HasIgnoredEquivalent( |
| 338 const ProtocolHandler& handler) const { | 393 const ProtocolHandler& handler) const { |
| 339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 394 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 340 ProtocolHandlerList::const_iterator i; | 395 ProtocolHandlerList::const_iterator i; |
| 341 for (i = ignored_protocol_handlers_.begin(); | 396 for (i = ignored_protocol_handlers_.begin(); |
| 342 i != ignored_protocol_handlers_.end(); ++i) { | 397 i != ignored_protocol_handlers_.end(); ++i) { |
| 343 if (handler.IsEquivalent(*i)) { | 398 if (handler.IsEquivalent(*i)) { |
| 344 return true; | 399 return true; |
| 345 } | 400 } |
| 346 } | 401 } |
| 347 return false; | 402 return false; |
| 348 } | 403 } |
| 349 | 404 |
| 405 void ProtocolHandlerRegistry::RemoveIgnoredHandler( |
| 406 const ProtocolHandler& handler) { |
| 407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 408 bool should_notify = false; |
| 409 ProtocolHandlerList::iterator p = std::find( |
| 410 ignored_protocol_handlers_.begin(), ignored_protocol_handlers_.end(), |
| 411 handler); |
| 412 if (p != ignored_protocol_handlers_.end()) { |
| 413 ignored_protocol_handlers_.erase(p); |
| 414 Save(); |
| 415 should_notify = true; |
| 416 } |
| 417 if (should_notify) |
| 418 NotifyChanged(); |
| 419 } |
| 420 |
| 350 bool ProtocolHandlerRegistry::IsHandledProtocol( | 421 bool ProtocolHandlerRegistry::IsHandledProtocol( |
| 351 const std::string& scheme) const { | 422 const std::string& scheme) const { |
| 352 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 353 return enabled_ && !GetHandlerFor(scheme).IsEmpty(); | 424 return enabled_ && !GetHandlerFor(scheme).IsEmpty(); |
| 354 } | 425 } |
| 355 | 426 |
| 427 bool ProtocolHandlerRegistry::IsHandledProtocolIO( |
| 428 const std::string& scheme) const { |
| 429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 430 return enabled_io_ && !LookupHandler(default_handlers_io_, scheme).IsEmpty(); |
| 431 } |
| 432 |
| 356 void ProtocolHandlerRegistry::RemoveHandler( | 433 void ProtocolHandlerRegistry::RemoveHandler( |
| 357 const ProtocolHandler& handler) { | 434 const ProtocolHandler& handler) { |
| 358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 359 ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()]; | 436 ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()]; |
| 360 ProtocolHandlerList::iterator p = | 437 ProtocolHandlerList::iterator p = |
| 361 std::find(handlers.begin(), handlers.end(), handler); | 438 std::find(handlers.begin(), handlers.end(), handler); |
| 362 if (p != handlers.end()) { | 439 if (p != handlers.end()) { |
| 363 handlers.erase(p); | 440 handlers.erase(p); |
| 364 } | 441 } |
| 365 ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol()); | 442 ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol()); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 384 NotifyChanged(); | 461 NotifyChanged(); |
| 385 } | 462 } |
| 386 | 463 |
| 387 void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) { | 464 void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) { |
| 388 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 465 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 389 ProtocolHandler current_default = GetHandlerFor(scheme); | 466 ProtocolHandler current_default = GetHandlerFor(scheme); |
| 390 if (!current_default.IsEmpty()) | 467 if (!current_default.IsEmpty()) |
| 391 RemoveHandler(current_default); | 468 RemoveHandler(current_default); |
| 392 } | 469 } |
| 393 | 470 |
| 394 static const ProtocolHandler& LookupHandler( | 471 const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor( |
| 395 const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map, | 472 const std::string& scheme) const { |
| 396 const std::string& scheme) { | 473 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 397 ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p = | 474 return LookupHandler(default_handlers_, scheme); |
| 398 handler_map.find(scheme); | |
| 399 if (p != handler_map.end()) { | |
| 400 return p->second; | |
| 401 } | |
| 402 return ProtocolHandler::EmptyProtocolHandler(); | |
| 403 } | 475 } |
| 404 | 476 |
| 405 Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() { | 477 net::URLRequestJob* ProtocolHandlerRegistry::MaybeCreateJob( |
| 406 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 478 net::URLRequest* request) const { |
| 407 ListValue* protocol_handlers = new ListValue(); | 479 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 408 for (ProtocolHandlerMultiMap::iterator i = protocol_handlers_.begin(); | 480 ProtocolHandler handler = LookupHandler(default_handlers_io_, |
| 409 i != protocol_handlers_.end(); ++i) { | 481 request->url().scheme()); |
| 410 for (ProtocolHandlerList::iterator j = i->second.begin(); | 482 if (handler.IsEmpty()) { |
| 411 j != i->second.end(); ++j) { | 483 return NULL; |
| 412 DictionaryValue* encoded = j->Encode(); | |
| 413 if (IsDefault(*j)) { | |
| 414 encoded->Set("default", Value::CreateBooleanValue(true)); | |
| 415 } | |
| 416 protocol_handlers->Append(encoded); | |
| 417 } | |
| 418 } | 484 } |
| 419 return protocol_handlers; | 485 GURL translated_url(handler.TranslateUrl(request->url())); |
| 486 if (!translated_url.is_valid()) { |
| 487 return NULL; |
| 488 } |
| 489 return new net::URLRequestRedirectJob(request, translated_url); |
| 420 } | 490 } |
| 421 | 491 |
| 422 Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() { | 492 void ProtocolHandlerRegistry::Enable() { |
| 423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 493 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 424 ListValue* handlers = new ListValue(); | 494 if (enabled_) { |
| 425 for (ProtocolHandlerList::iterator i = ignored_protocol_handlers_.begin(); | 495 return; |
| 426 i != ignored_protocol_handlers_.end(); ++i) { | |
| 427 handlers->Append(i->Encode()); | |
| 428 } | 496 } |
| 429 return handlers; | 497 enabled_ = true; |
| 430 } | 498 BrowserThread::PostTask( |
| 431 | 499 BrowserThread::IO, |
| 432 bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest( | 500 FROM_HERE, |
| 433 const ProtocolHandler& handler) { | 501 base::Bind(&ProtocolHandlerRegistry::EnableIO, this)); |
| 434 if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol())) | 502 ProtocolHandlerMap::const_iterator p; |
| 435 return true; | 503 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { |
| 436 | 504 delegate_->RegisterExternalHandler(p->first); |
| 437 if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler)) | 505 } |
| 438 return true; | |
| 439 | |
| 440 if (AttemptReplace(handler)) | |
| 441 return true; | |
| 442 | |
| 443 return false; | |
| 444 } | |
| 445 | |
| 446 void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler( | |
| 447 const ProtocolHandler& handler) { | |
| 448 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 449 RegisterProtocolHandler(handler); | |
| 450 SetDefault(handler); | |
| 451 Save(); | 506 Save(); |
| 452 NotifyChanged(); | 507 NotifyChanged(); |
| 453 } | 508 } |
| 454 | 509 |
| 455 void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler( | 510 void ProtocolHandlerRegistry::Disable() { |
| 456 const ProtocolHandler& handler) { | |
| 457 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 511 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 458 RegisterProtocolHandler(handler); | 512 if (!enabled_) { |
| 513 return; |
| 514 } |
| 515 enabled_ = false; |
| 516 BrowserThread::PostTask( |
| 517 BrowserThread::IO, |
| 518 FROM_HERE, |
| 519 base::Bind(&ProtocolHandlerRegistry::DisableIO, this)); |
| 520 ProtocolHandlerMap::const_iterator p; |
| 521 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { |
| 522 delegate_->DeregisterExternalHandler(p->first); |
| 523 } |
| 459 Save(); | 524 Save(); |
| 460 NotifyChanged(); | 525 NotifyChanged(); |
| 461 } | 526 } |
| 462 | 527 |
| 463 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler( | 528 void ProtocolHandlerRegistry::Finalize() { |
| 464 const ProtocolHandler& handler) { | |
| 465 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 529 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 466 IgnoreProtocolHandler(handler); | 530 delegate_.reset(NULL); |
| 467 Save(); | 531 // We free these now in case there are any outstanding workers running. If |
| 468 NotifyChanged(); | 532 // we didn't free them they could respond to workers and try to update the |
| 533 // protocol handler registry after it was deleted. |
| 534 // Observers remove themselves from this list when they are deleted; so |
| 535 // we delete the last item until none are left in the list. |
| 536 while (!default_client_observers_.empty()) { |
| 537 delete default_client_observers_.back(); |
| 538 } |
| 469 } | 539 } |
| 470 | 540 |
| 471 bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) { | |
| 472 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 473 ProtocolHandler old_default = GetHandlerFor(handler.protocol()); | |
| 474 bool make_new_handler_default = handler.IsSameOrigin(old_default); | |
| 475 ProtocolHandlerList to_replace(GetReplacedHandlers(handler)); | |
| 476 if (to_replace.empty()) | |
| 477 return false; | |
| 478 for (ProtocolHandlerList::iterator p = to_replace.begin(); | |
| 479 p != to_replace.end(); ++p) { | |
| 480 RemoveHandler(*p); | |
| 481 } | |
| 482 if (make_new_handler_default) { | |
| 483 OnAcceptRegisterProtocolHandler(handler); | |
| 484 } else { | |
| 485 InsertHandler(handler); | |
| 486 NotifyChanged(); | |
| 487 } | |
| 488 return true; | |
| 489 } | |
| 490 | |
| 491 ProtocolHandlerRegistry::ProtocolHandlerList | |
| 492 ProtocolHandlerRegistry::GetReplacedHandlers( | |
| 493 const ProtocolHandler& handler) const { | |
| 494 ProtocolHandlerList replaced_handlers; | |
| 495 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); | |
| 496 if (!handlers) | |
| 497 return replaced_handlers; | |
| 498 for (ProtocolHandlerList::const_iterator p = handlers->begin(); | |
| 499 p != handlers->end(); p++) { | |
| 500 if (handler.IsSameOrigin(*p)) { | |
| 501 replaced_handlers.push_back(*p); | |
| 502 } | |
| 503 } | |
| 504 return replaced_handlers; | |
| 505 } | |
| 506 | |
| 507 | |
| 508 // static | 541 // static |
| 509 void ProtocolHandlerRegistry::RegisterPrefs(PrefService* pref_service) { | 542 void ProtocolHandlerRegistry::RegisterPrefs(PrefService* pref_service) { |
| 510 pref_service->RegisterListPref(prefs::kRegisteredProtocolHandlers, | 543 pref_service->RegisterListPref(prefs::kRegisteredProtocolHandlers, |
| 511 PrefService::UNSYNCABLE_PREF); | 544 PrefService::UNSYNCABLE_PREF); |
| 512 pref_service->RegisterListPref(prefs::kIgnoredProtocolHandlers, | 545 pref_service->RegisterListPref(prefs::kIgnoredProtocolHandlers, |
| 513 PrefService::UNSYNCABLE_PREF); | 546 PrefService::UNSYNCABLE_PREF); |
| 514 pref_service->RegisterBooleanPref(prefs::kCustomHandlersEnabled, true, | 547 pref_service->RegisterBooleanPref(prefs::kCustomHandlersEnabled, true, |
| 515 PrefService::UNSYNCABLE_PREF); | 548 PrefService::UNSYNCABLE_PREF); |
| 516 } | 549 } |
| 517 | 550 |
| 518 void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) { | 551 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() { |
| 519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 552 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 520 ProtocolHandlerMap::const_iterator p = default_handlers_.find( | 553 DCHECK(default_client_observers_.empty()); |
| 521 handler.protocol()); | |
| 522 // If we're not loading, and we are setting a default for a new protocol, | |
| 523 // register with the OS. | |
| 524 if (!is_loading_ && p == default_handlers_.end()) | |
| 525 delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this); | |
| 526 default_handlers_.erase(handler.protocol()); | |
| 527 default_handlers_.insert(std::make_pair(handler.protocol(), handler)); | |
| 528 PromoteHandler(handler); | |
| 529 BrowserThread::PostTask( | |
| 530 BrowserThread::IO, | |
| 531 FROM_HERE, | |
| 532 base::Bind(&ProtocolHandlerRegistry::SetDefaultIO, this, handler)); | |
| 533 } | |
| 534 | |
| 535 void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) { | |
| 536 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 537 default_handlers_.erase(scheme); | |
| 538 BrowserThread::PostTask( | |
| 539 BrowserThread::IO, | |
| 540 FROM_HERE, | |
| 541 base::Bind(&ProtocolHandlerRegistry::ClearDefaultIO, this, scheme)); | |
| 542 Save(); | |
| 543 NotifyChanged(); | |
| 544 } | |
| 545 | |
| 546 bool ProtocolHandlerRegistry::IsDefault( | |
| 547 const ProtocolHandler& handler) const { | |
| 548 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 549 return GetHandlerFor(handler.protocol()) == handler; | |
| 550 } | |
| 551 | |
| 552 const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor( | |
| 553 const std::string& scheme) const { | |
| 554 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 555 return LookupHandler(default_handlers_, scheme); | |
| 556 } | |
| 557 | |
| 558 int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const { | |
| 559 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 560 const ProtocolHandler& handler = GetHandlerFor(scheme); | |
| 561 if (handler.IsEmpty()) | |
| 562 return -1; | |
| 563 const ProtocolHandlerList* handlers = GetHandlerList(scheme); | |
| 564 if (!handlers) | |
| 565 return -1; | |
| 566 | |
| 567 ProtocolHandlerList::const_iterator p; | |
| 568 int i; | |
| 569 for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) { | |
| 570 if (*p == handler) | |
| 571 return i; | |
| 572 } | |
| 573 return -1; | |
| 574 } | 554 } |
| 575 | 555 |
| 576 void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) { | 556 void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) { |
| 577 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 557 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 578 DCHECK(IsRegistered(handler)); | 558 DCHECK(IsRegistered(handler)); |
| 579 ProtocolHandlerMultiMap::iterator p = | 559 ProtocolHandlerMultiMap::iterator p = |
| 580 protocol_handlers_.find(handler.protocol()); | 560 protocol_handlers_.find(handler.protocol()); |
| 581 ProtocolHandlerList& list = p->second; | 561 ProtocolHandlerList& list = p->second; |
| 582 list.erase(std::find(list.begin(), list.end(), handler)); | 562 list.erase(std::find(list.begin(), list.end(), handler)); |
| 583 list.insert(list.begin(), handler); | 563 list.insert(list.begin(), handler); |
| 584 } | 564 } |
| 585 | 565 |
| 586 void ProtocolHandlerRegistry::NotifyChanged() { | |
| 587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 588 content::NotificationService::current()->Notify( | |
| 589 chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, | |
| 590 content::Source<Profile>(profile_), | |
| 591 content::NotificationService::NoDetails()); | |
| 592 } | |
| 593 | |
| 594 // IO thread methods ----------------------------------------------------------- | |
| 595 | |
| 596 void ProtocolHandlerRegistry::ClearDefaultIO(const std::string& scheme) { | 566 void ProtocolHandlerRegistry::ClearDefaultIO(const std::string& scheme) { |
| 597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 567 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 598 default_handlers_io_.erase(scheme); | 568 default_handlers_io_.erase(scheme); |
| 599 } | 569 } |
| 600 | 570 |
| 601 void ProtocolHandlerRegistry::SetDefaultIO(const ProtocolHandler& handler) { | 571 void ProtocolHandlerRegistry::SetDefaultIO(const ProtocolHandler& handler) { |
| 602 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 572 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 603 ClearDefaultIO(handler.protocol()); | 573 ClearDefaultIO(handler.protocol()); |
| 604 default_handlers_io_.insert(std::make_pair(handler.protocol(), handler)); | 574 default_handlers_io_.insert(std::make_pair(handler.protocol(), handler)); |
| 605 } | 575 } |
| 606 | 576 |
| 607 bool ProtocolHandlerRegistry::IsHandledProtocolIO( | 577 void ProtocolHandlerRegistry::Save() { |
| 608 const std::string& scheme) const { | 578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 609 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 579 if (is_loading_) { |
| 610 return enabled_io_ && !LookupHandler(default_handlers_io_, scheme).IsEmpty(); | 580 return; |
| 581 } |
| 582 scoped_ptr<Value> registered_protocol_handlers(EncodeRegisteredHandlers()); |
| 583 scoped_ptr<Value> ignored_protocol_handlers(EncodeIgnoredHandlers()); |
| 584 scoped_ptr<Value> enabled(Value::CreateBooleanValue(enabled_)); |
| 585 profile_->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers, |
| 586 *registered_protocol_handlers); |
| 587 profile_->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers, |
| 588 *ignored_protocol_handlers); |
| 589 profile_->GetPrefs()->Set(prefs::kCustomHandlersEnabled, *enabled); |
| 611 } | 590 } |
| 612 | 591 |
| 613 net::URLRequestJob* ProtocolHandlerRegistry::MaybeCreateJob( | 592 const ProtocolHandlerRegistry::ProtocolHandlerList* |
| 614 net::URLRequest* request) const { | 593 ProtocolHandlerRegistry::GetHandlerList( |
| 615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 594 const std::string& scheme) const { |
| 616 ProtocolHandler handler = LookupHandler(default_handlers_io_, | 595 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 617 request->url().scheme()); | 596 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); |
| 618 if (handler.IsEmpty()) { | 597 if (p == protocol_handlers_.end()) { |
| 619 return NULL; | 598 return NULL; |
| 620 } | 599 } |
| 621 GURL translated_url(handler.TranslateUrl(request->url())); | 600 return &p->second; |
| 622 if (!translated_url.is_valid()) { | |
| 623 return NULL; | |
| 624 } | |
| 625 return new net::URLRequestRedirectJob(request, translated_url); | |
| 626 } | 601 } |
| 627 | 602 |
| 628 // Delegate -------------------------------------------------------------------- | 603 void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) { |
| 629 | 604 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 630 ProtocolHandlerRegistry::Delegate::~Delegate() { | 605 ProtocolHandlerMap::const_iterator p = default_handlers_.find( |
| 606 handler.protocol()); |
| 607 // If we're not loading, and we are setting a default for a new protocol, |
| 608 // register with the OS. |
| 609 if (!is_loading_ && p == default_handlers_.end()) |
| 610 delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this); |
| 611 default_handlers_.erase(handler.protocol()); |
| 612 default_handlers_.insert(std::make_pair(handler.protocol(), handler)); |
| 613 PromoteHandler(handler); |
| 614 BrowserThread::PostTask( |
| 615 BrowserThread::IO, |
| 616 FROM_HERE, |
| 617 base::Bind(&ProtocolHandlerRegistry::SetDefaultIO, this, handler)); |
| 631 } | 618 } |
| 632 | 619 |
| 633 void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler( | 620 void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) { |
| 634 const std::string& protocol) { | 621 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 635 ChildProcessSecurityPolicy* policy = | 622 ProtocolHandlerMultiMap::iterator p = |
| 636 ChildProcessSecurityPolicy::GetInstance(); | 623 protocol_handlers_.find(handler.protocol()); |
| 637 if (!policy->IsWebSafeScheme(protocol)) { | 624 |
| 638 policy->RegisterWebSafeScheme(protocol); | 625 if (p != protocol_handlers_.end()) { |
| 626 p->second.push_back(handler); |
| 627 return; |
| 639 } | 628 } |
| 629 |
| 630 ProtocolHandlerList new_list; |
| 631 new_list.push_back(handler); |
| 632 protocol_handlers_[handler.protocol()] = new_list; |
| 640 } | 633 } |
| 641 | 634 |
| 642 void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler( | 635 Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() { |
| 643 const std::string& protocol) { | 636 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 637 ListValue* protocol_handlers = new ListValue(); |
| 638 for (ProtocolHandlerMultiMap::iterator i = protocol_handlers_.begin(); |
| 639 i != protocol_handlers_.end(); ++i) { |
| 640 for (ProtocolHandlerList::iterator j = i->second.begin(); |
| 641 j != i->second.end(); ++j) { |
| 642 DictionaryValue* encoded = j->Encode(); |
| 643 if (IsDefault(*j)) { |
| 644 encoded->Set("default", Value::CreateBooleanValue(true)); |
| 645 } |
| 646 protocol_handlers->Append(encoded); |
| 647 } |
| 648 } |
| 649 return protocol_handlers; |
| 644 } | 650 } |
| 645 | 651 |
| 646 ShellIntegration::DefaultProtocolClientWorker* | 652 Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() { |
| 647 ProtocolHandlerRegistry::Delegate::CreateShellWorker( | 653 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 648 ShellIntegration::DefaultWebClientObserver* observer, | 654 ListValue* handlers = new ListValue(); |
| 649 const std::string& protocol) { | 655 for (ProtocolHandlerList::iterator i = ignored_protocol_handlers_.begin(); |
| 650 return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol); | 656 i != ignored_protocol_handlers_.end(); ++i) { |
| 657 handlers->Append(i->Encode()); |
| 658 } |
| 659 return handlers; |
| 651 } | 660 } |
| 652 | 661 |
| 653 ProtocolHandlerRegistry::DefaultClientObserver* | 662 void ProtocolHandlerRegistry::NotifyChanged() { |
| 654 ProtocolHandlerRegistry::Delegate::CreateShellObserver( | 663 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 655 ProtocolHandlerRegistry* registry) { | 664 content::NotificationService::current()->Notify( |
| 656 return new DefaultClientObserver(registry); | 665 chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, |
| 666 content::Source<Profile>(profile_), |
| 667 content::NotificationService::NoDetails()); |
| 657 } | 668 } |
| 658 | 669 |
| 659 void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient( | 670 void ProtocolHandlerRegistry::RegisterProtocolHandler( |
| 660 const std::string& protocol, ProtocolHandlerRegistry* registry) { | 671 const ProtocolHandler& handler) { |
| 661 DefaultClientObserver* observer = CreateShellObserver(registry); | 672 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 662 // The worker pointer is reference counted. While it is running the | 673 DCHECK(CanSchemeBeOverridden(handler.protocol())); |
| 663 // message loops of the FILE and UI thread will hold references to it | 674 DCHECK(!handler.IsEmpty()); |
| 664 // and it will be automatically freed once all its tasks have finished. | 675 if (IsRegistered(handler)) { |
| 665 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; | 676 return; |
| 666 worker = CreateShellWorker(observer, protocol); | 677 } |
| 667 observer->SetWorker(worker); | 678 if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol())) |
| 668 registry->default_client_observers_.push_back(observer); | 679 delegate_->RegisterExternalHandler(handler.protocol()); |
| 669 worker->StartSetAsDefault(); | 680 InsertHandler(handler); |
| 670 } | 681 } |
| 671 | 682 |
| 672 bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered( | 683 std::vector<const DictionaryValue*> |
| 673 const std::string& protocol) { | 684 ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const { |
| 674 // NOTE(koz): This function is safe to call from any thread, despite living | 685 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 675 // in ProfileIOData. | 686 std::vector<const DictionaryValue*> result; |
| 676 return ProfileIOData::IsHandledProtocol(protocol); | 687 PrefService* prefs = profile_->GetPrefs(); |
| 688 if (!prefs->HasPrefPath(pref_name)) { |
| 689 return result; |
| 690 } |
| 691 |
| 692 const ListValue* handlers = prefs->GetList(pref_name); |
| 693 if (handlers) { |
| 694 for (size_t i = 0; i < handlers->GetSize(); ++i) { |
| 695 DictionaryValue* dict; |
| 696 if (!handlers->GetDictionary(i, &dict)) |
| 697 continue; |
| 698 if (ProtocolHandler::IsValidDict(dict)) { |
| 699 result.push_back(dict); |
| 700 } |
| 701 } |
| 702 } |
| 703 return result; |
| 677 } | 704 } |
| 678 | 705 |
| 679 // DefaultClientObserver ------------------------------------------------------ | 706 void ProtocolHandlerRegistry::IgnoreProtocolHandler( |
| 680 | 707 const ProtocolHandler& handler) { |
| 681 ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver( | 708 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 682 ProtocolHandlerRegistry* registry) | 709 ignored_protocol_handlers_.push_back(handler); |
| 683 : worker_(NULL), registry_(registry) { | |
| 684 DCHECK(registry_); | |
| 685 } | 710 } |
| 686 | |
| 687 ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() { | |
| 688 if (worker_) { | |
| 689 worker_->ObserverDestroyed(); | |
| 690 }; | |
| 691 DefaultClientObserverList::iterator iter = std::find( | |
| 692 registry_->default_client_observers_.begin(), | |
| 693 registry_->default_client_observers_.end(), this); | |
| 694 registry_->default_client_observers_.erase(iter); | |
| 695 } | |
| 696 | |
| 697 void | |
| 698 ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState( | |
| 699 ShellIntegration::DefaultWebClientUIState state) { | |
| 700 if (worker_) { | |
| 701 if (ShouldRemoveHandlersNotInOS() && | |
| 702 (state == ShellIntegration::STATE_NOT_DEFAULT)) { | |
| 703 registry_->ClearDefault(worker_->protocol()); | |
| 704 } | |
| 705 } else { | |
| 706 NOTREACHED(); | |
| 707 } | |
| 708 } | |
| 709 | |
| 710 void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker( | |
| 711 ShellIntegration::DefaultProtocolClientWorker* worker) { | |
| 712 worker_ = worker; | |
| 713 } | |
| OLD | NEW |