Add GCMChannelStatusSyncer to schedule requests and enable/disable GCM
[chromium-blink-merge.git] / chrome / browser / custom_handlers / protocol_handler_registry.cc
blob72f134d64b226ee68dbb230ea0500d693a1e55c4
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
3 // found in the LICENSE file.
5 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
7 #include <utility>
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/logging.h"
12 #include "base/prefs/pref_service.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h"
15 #include "chrome/browser/profiles/profile_io_data.h"
16 #include "chrome/common/custom_handlers/protocol_handler.h"
17 #include "chrome/common/pref_names.h"
18 #include "chrome/grit/generated_resources.h"
19 #include "components/pref_registry/pref_registry_syncable.h"
20 #include "components/user_prefs/user_prefs.h"
21 #include "content/public/browser/child_process_security_policy.h"
22 #include "net/base/network_delegate.h"
23 #include "net/url_request/url_request_redirect_job.h"
24 #include "ui/base/l10n/l10n_util.h"
26 using content::BrowserThread;
27 using content::ChildProcessSecurityPolicy;
29 namespace {
31 const ProtocolHandler& LookupHandler(
32 const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map,
33 const std::string& scheme) {
34 ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p =
35 handler_map.find(scheme);
37 if (p != handler_map.end())
38 return p->second;
40 return ProtocolHandler::EmptyProtocolHandler();
43 // If true default protocol handlers will be removed if the OS level
44 // registration for a protocol is no longer Chrome.
45 bool ShouldRemoveHandlersNotInOS() {
46 #if defined(OS_LINUX)
47 // We don't do this on Linux as the OS registration there is not reliable,
48 // and Chrome OS doesn't have any notion of OS registration.
49 // TODO(benwells): When Linux support is more reliable remove this
50 // difference (http://crbug.com/88255).
51 return false;
52 #else
53 return ShellIntegration::CanSetAsDefaultProtocolClient() !=
54 ShellIntegration::SET_DEFAULT_NOT_ALLOWED;
55 #endif
58 } // namespace
60 // IOThreadDelegate ------------------------------------------------------------
62 // IOThreadDelegate is an IO thread specific object. Access to the class should
63 // all be done via the IO thread. The registry living on the UI thread makes
64 // a best effort to update the IO object after local updates are completed.
65 class ProtocolHandlerRegistry::IOThreadDelegate
66 : public base::RefCountedThreadSafe<
67 ProtocolHandlerRegistry::IOThreadDelegate> {
68 public:
70 // Creates a new instance. If |enabled| is true the registry is considered
71 // enabled on the IO thread.
72 explicit IOThreadDelegate(bool enabled);
74 // Returns true if the protocol has a default protocol handler.
75 // Should be called only from the IO thread.
76 bool IsHandledProtocol(const std::string& scheme) const;
78 // Clears the default for the provided protocol.
79 // Should be called only from the IO thread.
80 void ClearDefault(const std::string& scheme);
82 // Makes this ProtocolHandler the default handler for its protocol.
83 // Should be called only from the IO thread.
84 void SetDefault(const ProtocolHandler& handler);
86 // Creates a URL request job for the given request if there is a matching
87 // protocol handler, returns NULL otherwise.
88 net::URLRequestJob* MaybeCreateJob(
89 net::URLRequest* request, net::NetworkDelegate* network_delegate) const;
91 // Indicate that the registry has been enabled in the IO thread's
92 // copy of the data.
93 void Enable() { enabled_ = true; }
95 // Indicate that the registry has been disabled in the IO thread's copy of
96 // the data.
97 void Disable() { enabled_ = false; }
99 private:
100 friend class base::RefCountedThreadSafe<IOThreadDelegate>;
101 virtual ~IOThreadDelegate();
103 // Copy of protocol handlers use only on the IO thread.
104 ProtocolHandlerRegistry::ProtocolHandlerMap default_handlers_;
106 // Is the registry enabled on the IO thread.
107 bool enabled_;
109 DISALLOW_COPY_AND_ASSIGN(IOThreadDelegate);
112 ProtocolHandlerRegistry::IOThreadDelegate::IOThreadDelegate(bool)
113 : enabled_(true) {}
114 ProtocolHandlerRegistry::IOThreadDelegate::~IOThreadDelegate() {}
116 bool ProtocolHandlerRegistry::IOThreadDelegate::IsHandledProtocol(
117 const std::string& scheme) const {
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
119 return enabled_ && !LookupHandler(default_handlers_, scheme).IsEmpty();
122 void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault(
123 const std::string& scheme) {
124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
125 default_handlers_.erase(scheme);
128 void ProtocolHandlerRegistry::IOThreadDelegate::SetDefault(
129 const ProtocolHandler& handler) {
130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
131 ClearDefault(handler.protocol());
132 default_handlers_.insert(std::make_pair(handler.protocol(), handler));
135 // Create a new job for the supplied |URLRequest| if a default handler
136 // is registered and the associated handler is able to interpret
137 // the url from |request|.
138 net::URLRequestJob* ProtocolHandlerRegistry::IOThreadDelegate::MaybeCreateJob(
139 net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
142 ProtocolHandler handler = LookupHandler(default_handlers_,
143 request->url().scheme());
144 if (handler.IsEmpty())
145 return NULL;
147 GURL translated_url(handler.TranslateUrl(request->url()));
148 if (!translated_url.is_valid())
149 return NULL;
151 return new net::URLRequestRedirectJob(
152 request, network_delegate, translated_url,
153 net::URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT,
154 "Protocol Handler Registry");
157 // JobInterceptorFactory -------------------------------------------------------
159 // Instances of JobInterceptorFactory are produced for ownership by the IO
160 // thread where it handler URL requests. We should never hold
161 // any pointers on this class, only produce them in response to
162 // requests via |ProtocolHandlerRegistry::CreateJobInterceptorFactory|.
163 ProtocolHandlerRegistry::JobInterceptorFactory::JobInterceptorFactory(
164 IOThreadDelegate* io_thread_delegate)
165 : io_thread_delegate_(io_thread_delegate) {
166 DCHECK(io_thread_delegate_.get());
167 DetachFromThread();
170 ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() {
173 void ProtocolHandlerRegistry::JobInterceptorFactory::Chain(
174 scoped_ptr<net::URLRequestJobFactory> job_factory) {
175 job_factory_ = job_factory.Pass();
178 net::URLRequestJob*
179 ProtocolHandlerRegistry::JobInterceptorFactory::
180 MaybeCreateJobWithProtocolHandler(
181 const std::string& scheme,
182 net::URLRequest* request,
183 net::NetworkDelegate* network_delegate) const {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
185 net::URLRequestJob* job = io_thread_delegate_->MaybeCreateJob(
186 request, network_delegate);
187 if (job)
188 return job;
189 return job_factory_->MaybeCreateJobWithProtocolHandler(
190 scheme, request, network_delegate);
193 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledProtocol(
194 const std::string& scheme) const {
195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
196 return io_thread_delegate_->IsHandledProtocol(scheme) ||
197 job_factory_->IsHandledProtocol(scheme);
200 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledURL(
201 const GURL& url) const {
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
203 return (url.is_valid() &&
204 io_thread_delegate_->IsHandledProtocol(url.scheme())) ||
205 job_factory_->IsHandledURL(url);
208 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsSafeRedirectTarget(
209 const GURL& location) const {
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
211 return job_factory_->IsSafeRedirectTarget(location);
214 // DefaultClientObserver ------------------------------------------------------
216 ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver(
217 ProtocolHandlerRegistry* registry)
218 : worker_(NULL),
219 registry_(registry) {
220 DCHECK(registry_);
223 ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() {
224 if (worker_)
225 worker_->ObserverDestroyed();
227 DefaultClientObserverList::iterator iter = std::find(
228 registry_->default_client_observers_.begin(),
229 registry_->default_client_observers_.end(), this);
230 registry_->default_client_observers_.erase(iter);
233 void ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState(
234 ShellIntegration::DefaultWebClientUIState state) {
235 if (worker_) {
236 if (ShouldRemoveHandlersNotInOS() &&
237 (state == ShellIntegration::STATE_NOT_DEFAULT)) {
238 registry_->ClearDefault(worker_->protocol());
240 } else {
241 NOTREACHED();
245 bool ProtocolHandlerRegistry::DefaultClientObserver::
246 IsInteractiveSetDefaultPermitted() {
247 return true;
250 void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker(
251 ShellIntegration::DefaultProtocolClientWorker* worker) {
252 worker_ = worker;
255 bool ProtocolHandlerRegistry::DefaultClientObserver::IsOwnedByWorker() {
256 return true;
259 // Delegate --------------------------------------------------------------------
261 ProtocolHandlerRegistry::Delegate::~Delegate() {}
263 void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler(
264 const std::string& protocol) {
265 ChildProcessSecurityPolicy* policy =
266 ChildProcessSecurityPolicy::GetInstance();
267 if (!policy->IsWebSafeScheme(protocol)) {
268 policy->RegisterWebSafeScheme(protocol);
272 void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
273 const std::string& protocol) {
276 bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered(
277 const std::string& protocol) {
278 // NOTE(koz): This function is safe to call from any thread, despite living
279 // in ProfileIOData.
280 return ProfileIOData::IsHandledProtocol(protocol);
283 ShellIntegration::DefaultProtocolClientWorker*
284 ProtocolHandlerRegistry::Delegate::CreateShellWorker(
285 ShellIntegration::DefaultWebClientObserver* observer,
286 const std::string& protocol) {
287 return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol);
290 ProtocolHandlerRegistry::DefaultClientObserver*
291 ProtocolHandlerRegistry::Delegate::CreateShellObserver(
292 ProtocolHandlerRegistry* registry) {
293 return new DefaultClientObserver(registry);
296 void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient(
297 const std::string& protocol, ProtocolHandlerRegistry* registry) {
298 DefaultClientObserver* observer = CreateShellObserver(registry);
299 // The worker pointer is reference counted. While it is running the
300 // message loops of the FILE and UI thread will hold references to it
301 // and it will be automatically freed once all its tasks have finished.
302 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker;
303 worker = CreateShellWorker(observer, protocol);
304 observer->SetWorker(worker.get());
305 registry->default_client_observers_.push_back(observer);
306 worker->StartSetAsDefault();
309 // ProtocolHandlerRegistry -----------------------------------------------------
311 ProtocolHandlerRegistry::ProtocolHandlerRegistry(
312 content::BrowserContext* context, Delegate* delegate)
313 : context_(context),
314 delegate_(delegate),
315 enabled_(true),
316 is_loading_(false),
317 is_loaded_(false),
318 io_thread_delegate_(new IOThreadDelegate(enabled_)){
321 bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest(
322 const ProtocolHandler& handler) {
323 if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol()))
324 return true;
326 if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler))
327 return true;
329 if (AttemptReplace(handler))
330 return true;
332 return false;
335 void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler(
336 const ProtocolHandler& handler) {
337 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
338 RegisterProtocolHandler(handler, USER);
339 SetDefault(handler);
340 Save();
341 NotifyChanged();
344 void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
345 const ProtocolHandler& handler) {
346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
347 RegisterProtocolHandler(handler, USER);
348 Save();
349 NotifyChanged();
352 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
353 const ProtocolHandler& handler) {
354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
355 IgnoreProtocolHandler(handler, USER);
356 Save();
357 NotifyChanged();
360 bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) {
361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
362 ProtocolHandler old_default = GetHandlerFor(handler.protocol());
363 bool make_new_handler_default = handler.IsSameOrigin(old_default);
364 ProtocolHandlerList to_replace(GetReplacedHandlers(handler));
365 if (to_replace.empty())
366 return false;
367 for (ProtocolHandlerList::iterator p = to_replace.begin();
368 p != to_replace.end(); ++p) {
369 RemoveHandler(*p);
371 if (make_new_handler_default) {
372 OnAcceptRegisterProtocolHandler(handler);
373 } else {
374 InsertHandler(handler);
375 NotifyChanged();
377 return true;
380 ProtocolHandlerRegistry::ProtocolHandlerList
381 ProtocolHandlerRegistry::GetReplacedHandlers(
382 const ProtocolHandler& handler) const {
383 ProtocolHandlerList replaced_handlers;
384 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
385 if (!handlers)
386 return replaced_handlers;
387 for (ProtocolHandlerList::const_iterator p = handlers->begin();
388 p != handlers->end(); p++) {
389 if (handler.IsSameOrigin(*p)) {
390 replaced_handlers.push_back(*p);
393 return replaced_handlers;
396 void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) {
397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
399 default_handlers_.erase(scheme);
400 BrowserThread::PostTask(
401 BrowserThread::IO,
402 FROM_HERE,
403 base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_, scheme));
404 Save();
405 NotifyChanged();
408 bool ProtocolHandlerRegistry::IsDefault(
409 const ProtocolHandler& handler) const {
410 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
411 return GetHandlerFor(handler.protocol()) == handler;
414 void ProtocolHandlerRegistry::InstallDefaultsForChromeOS() {
415 #if defined(OS_CHROMEOS)
416 // Only chromeos has default protocol handlers at this point.
417 AddPredefinedHandler(
418 ProtocolHandler::CreateProtocolHandler(
419 "mailto",
420 GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_MAILTO_HANDLER_URL))));
421 AddPredefinedHandler(
422 ProtocolHandler::CreateProtocolHandler(
423 "webcal",
424 GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL))));
425 #else
426 NOTREACHED(); // this method should only ever be called in chromeos.
427 #endif
430 void ProtocolHandlerRegistry::InitProtocolSettings() {
431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
433 // Any further default additions to the table will get rejected from now on.
434 is_loaded_ = true;
435 is_loading_ = true;
437 PrefService* prefs = user_prefs::UserPrefs::Get(context_);
438 if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) {
439 if (prefs->GetBoolean(prefs::kCustomHandlersEnabled)) {
440 Enable();
441 } else {
442 Disable();
446 RegisterProtocolHandlersFromPref(prefs::kPolicyRegisteredProtocolHandlers,
447 POLICY);
448 RegisterProtocolHandlersFromPref(prefs::kRegisteredProtocolHandlers, USER);
449 IgnoreProtocolHandlersFromPref(prefs::kPolicyIgnoredProtocolHandlers, POLICY);
450 IgnoreProtocolHandlersFromPref(prefs::kIgnoredProtocolHandlers, USER);
452 is_loading_ = false;
454 // For each default protocol handler, check that we are still registered
455 // with the OS as the default application.
456 if (ShouldRemoveHandlersNotInOS()) {
457 for (ProtocolHandlerMap::const_iterator p = default_handlers_.begin();
458 p != default_handlers_.end(); ++p) {
459 ProtocolHandler handler = p->second;
460 DefaultClientObserver* observer = delegate_->CreateShellObserver(this);
461 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker;
462 worker = delegate_->CreateShellWorker(observer, handler.protocol());
463 observer->SetWorker(worker.get());
464 default_client_observers_.push_back(observer);
465 worker->StartCheckIsDefault();
470 int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const {
471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
472 const ProtocolHandler& handler = GetHandlerFor(scheme);
473 if (handler.IsEmpty())
474 return -1;
475 const ProtocolHandlerList* handlers = GetHandlerList(scheme);
476 if (!handlers)
477 return -1;
479 ProtocolHandlerList::const_iterator p;
480 int i;
481 for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) {
482 if (*p == handler)
483 return i;
485 return -1;
488 ProtocolHandlerRegistry::ProtocolHandlerList
489 ProtocolHandlerRegistry::GetHandlersFor(
490 const std::string& scheme) const {
491 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
492 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
493 if (p == protocol_handlers_.end()) {
494 return ProtocolHandlerList();
496 return p->second;
499 ProtocolHandlerRegistry::ProtocolHandlerList
500 ProtocolHandlerRegistry::GetIgnoredHandlers() {
501 return ignored_protocol_handlers_;
504 void ProtocolHandlerRegistry::GetRegisteredProtocols(
505 std::vector<std::string>* output) const {
506 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
507 ProtocolHandlerMultiMap::const_iterator p;
508 for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) {
509 if (!p->second.empty())
510 output->push_back(p->first);
514 bool ProtocolHandlerRegistry::CanSchemeBeOverridden(
515 const std::string& scheme) const {
516 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
517 const ProtocolHandlerList* handlers = GetHandlerList(scheme);
518 // If we already have a handler for this scheme, we can add more.
519 if (handlers != NULL && !handlers->empty())
520 return true;
521 // Don't override a scheme if it already has an external handler.
522 return !delegate_->IsExternalHandlerRegistered(scheme);
525 bool ProtocolHandlerRegistry::IsRegistered(
526 const ProtocolHandler& handler) const {
527 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
528 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
529 if (!handlers) {
530 return false;
532 return std::find(handlers->begin(), handlers->end(), handler) !=
533 handlers->end();
536 bool ProtocolHandlerRegistry::IsRegisteredByUser(
537 const ProtocolHandler& handler) {
538 return HandlerExists(handler, &user_protocol_handlers_);
541 bool ProtocolHandlerRegistry::HasPolicyRegisteredHandler(
542 const std::string& scheme) {
543 return (policy_protocol_handlers_.find(scheme) !=
544 policy_protocol_handlers_.end());
547 bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const {
548 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
549 ProtocolHandlerList::const_iterator i;
550 for (i = ignored_protocol_handlers_.begin();
551 i != ignored_protocol_handlers_.end(); ++i) {
552 if (*i == handler) {
553 return true;
556 return false;
559 bool ProtocolHandlerRegistry::HasRegisteredEquivalent(
560 const ProtocolHandler& handler) const {
561 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
562 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
563 if (!handlers) {
564 return false;
566 ProtocolHandlerList::const_iterator i;
567 for (i = handlers->begin(); i != handlers->end(); ++i) {
568 if (handler.IsEquivalent(*i)) {
569 return true;
572 return false;
575 bool ProtocolHandlerRegistry::HasIgnoredEquivalent(
576 const ProtocolHandler& handler) const {
577 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
578 ProtocolHandlerList::const_iterator i;
579 for (i = ignored_protocol_handlers_.begin();
580 i != ignored_protocol_handlers_.end(); ++i) {
581 if (handler.IsEquivalent(*i)) {
582 return true;
585 return false;
588 void ProtocolHandlerRegistry::RemoveIgnoredHandler(
589 const ProtocolHandler& handler) {
590 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
591 bool should_notify = false;
592 if (HandlerExists(handler, ignored_protocol_handlers_) &&
593 HandlerExists(handler, user_ignored_protocol_handlers_)) {
594 EraseHandler(handler, &user_ignored_protocol_handlers_);
595 Save();
596 if (!HandlerExists(handler, policy_ignored_protocol_handlers_)) {
597 EraseHandler(handler, &ignored_protocol_handlers_);
598 should_notify = true;
601 if (should_notify)
602 NotifyChanged();
605 bool ProtocolHandlerRegistry::IsHandledProtocol(
606 const std::string& scheme) const {
607 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
608 return enabled_ && !GetHandlerFor(scheme).IsEmpty();
611 void ProtocolHandlerRegistry::RemoveHandler(
612 const ProtocolHandler& handler) {
613 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
614 ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()];
615 bool erase_success = false;
616 if (HandlerExists(handler, handlers) &&
617 HandlerExists(handler, &user_protocol_handlers_)) {
618 EraseHandler(handler, &user_protocol_handlers_);
619 erase_success = true;
620 if (!HandlerExists(handler, &policy_protocol_handlers_))
621 EraseHandler(handler, &protocol_handlers_);
623 ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol());
624 if (erase_success && q != default_handlers_.end() && q->second == handler) {
625 // Make the new top handler in the list the default.
626 if (!handlers.empty()) {
627 // NOTE We pass a copy because SetDefault() modifies handlers.
628 SetDefault(ProtocolHandler(handlers[0]));
629 } else {
630 BrowserThread::PostTask(
631 BrowserThread::IO, FROM_HERE,
632 base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_,
633 q->second.protocol()));
635 default_handlers_.erase(q);
639 if (erase_success && !IsHandledProtocol(handler.protocol())) {
640 delegate_->DeregisterExternalHandler(handler.protocol());
642 Save();
643 if (erase_success)
644 NotifyChanged();
647 void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) {
648 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
649 ProtocolHandler current_default = GetHandlerFor(scheme);
650 if (!current_default.IsEmpty())
651 RemoveHandler(current_default);
654 const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor(
655 const std::string& scheme) const {
656 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
657 return LookupHandler(default_handlers_, scheme);
660 void ProtocolHandlerRegistry::Enable() {
661 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
662 if (enabled_) {
663 return;
665 enabled_ = true;
666 BrowserThread::PostTask(
667 BrowserThread::IO,
668 FROM_HERE,
669 base::Bind(&IOThreadDelegate::Enable, io_thread_delegate_));
671 ProtocolHandlerMap::const_iterator p;
672 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
673 delegate_->RegisterExternalHandler(p->first);
675 Save();
676 NotifyChanged();
679 void ProtocolHandlerRegistry::Disable() {
680 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
681 if (!enabled_) {
682 return;
684 enabled_ = false;
685 BrowserThread::PostTask(
686 BrowserThread::IO,
687 FROM_HERE,
688 base::Bind(&IOThreadDelegate::Disable, io_thread_delegate_));
690 ProtocolHandlerMap::const_iterator p;
691 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
692 delegate_->DeregisterExternalHandler(p->first);
694 Save();
695 NotifyChanged();
698 void ProtocolHandlerRegistry::Shutdown() {
699 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
700 delegate_.reset(NULL);
701 // We free these now in case there are any outstanding workers running. If
702 // we didn't free them they could respond to workers and try to update the
703 // protocol handler registry after it was deleted.
704 // Observers remove themselves from this list when they are deleted; so
705 // we delete the last item until none are left in the list.
706 while (!default_client_observers_.empty()) {
707 delete default_client_observers_.back();
711 // static
712 void ProtocolHandlerRegistry::RegisterProfilePrefs(
713 user_prefs::PrefRegistrySyncable* registry) {
714 registry->RegisterListPref(prefs::kRegisteredProtocolHandlers,
715 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
716 registry->RegisterListPref(prefs::kIgnoredProtocolHandlers,
717 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
718 registry->RegisterListPref(prefs::kPolicyRegisteredProtocolHandlers,
719 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
720 registry->RegisterListPref(prefs::kPolicyIgnoredProtocolHandlers,
721 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
722 registry->RegisterBooleanPref(
723 prefs::kCustomHandlersEnabled,
724 true,
725 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
728 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
729 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
730 DCHECK(default_client_observers_.empty());
733 void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) {
734 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
735 DCHECK(IsRegistered(handler));
736 ProtocolHandlerMultiMap::iterator p =
737 protocol_handlers_.find(handler.protocol());
738 ProtocolHandlerList& list = p->second;
739 list.erase(std::find(list.begin(), list.end(), handler));
740 list.insert(list.begin(), handler);
743 void ProtocolHandlerRegistry::Save() {
744 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
745 if (is_loading_) {
746 return;
748 scoped_ptr<base::Value> registered_protocol_handlers(
749 EncodeRegisteredHandlers());
750 scoped_ptr<base::Value> ignored_protocol_handlers(EncodeIgnoredHandlers());
751 PrefService* prefs = user_prefs::UserPrefs::Get(context_);
753 prefs->Set(prefs::kRegisteredProtocolHandlers,
754 *registered_protocol_handlers);
755 prefs->Set(prefs::kIgnoredProtocolHandlers,
756 *ignored_protocol_handlers);
757 prefs->SetBoolean(prefs::kCustomHandlersEnabled, enabled_);
760 const ProtocolHandlerRegistry::ProtocolHandlerList*
761 ProtocolHandlerRegistry::GetHandlerList(
762 const std::string& scheme) const {
763 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
764 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
765 if (p == protocol_handlers_.end()) {
766 return NULL;
768 return &p->second;
771 void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) {
772 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
773 ProtocolHandlerMap::const_iterator p = default_handlers_.find(
774 handler.protocol());
775 // If we're not loading, and we are setting a default for a new protocol,
776 // register with the OS.
777 if (!is_loading_ && p == default_handlers_.end())
778 delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this);
779 default_handlers_.erase(handler.protocol());
780 default_handlers_.insert(std::make_pair(handler.protocol(), handler));
781 PromoteHandler(handler);
782 BrowserThread::PostTask(
783 BrowserThread::IO,
784 FROM_HERE,
785 base::Bind(&IOThreadDelegate::SetDefault, io_thread_delegate_, handler));
788 void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) {
789 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
790 ProtocolHandlerMultiMap::iterator p =
791 protocol_handlers_.find(handler.protocol());
793 if (p != protocol_handlers_.end()) {
794 p->second.push_back(handler);
795 return;
798 ProtocolHandlerList new_list;
799 new_list.push_back(handler);
800 protocol_handlers_[handler.protocol()] = new_list;
803 base::Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() {
804 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
805 base::ListValue* protocol_handlers = new base::ListValue();
806 for (ProtocolHandlerMultiMap::iterator i = user_protocol_handlers_.begin();
807 i != user_protocol_handlers_.end();
808 ++i) {
809 for (ProtocolHandlerList::iterator j = i->second.begin();
810 j != i->second.end(); ++j) {
811 base::DictionaryValue* encoded = j->Encode();
812 if (IsDefault(*j)) {
813 encoded->Set("default", new base::FundamentalValue(true));
815 protocol_handlers->Append(encoded);
818 return protocol_handlers;
821 base::Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
822 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
823 base::ListValue* handlers = new base::ListValue();
824 for (ProtocolHandlerList::iterator i =
825 user_ignored_protocol_handlers_.begin();
826 i != user_ignored_protocol_handlers_.end();
827 ++i) {
828 handlers->Append(i->Encode());
830 return handlers;
833 void ProtocolHandlerRegistry::NotifyChanged() {
834 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
835 content::NotificationService::current()->Notify(
836 chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
837 content::Source<content::BrowserContext>(context_),
838 content::NotificationService::NoDetails());
841 void ProtocolHandlerRegistry::RegisterProtocolHandler(
842 const ProtocolHandler& handler,
843 const HandlerSource source) {
844 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
845 DCHECK(CanSchemeBeOverridden(handler.protocol()));
846 DCHECK(!handler.IsEmpty());
847 ProtocolHandlerMultiMap& map =
848 (source == POLICY) ? policy_protocol_handlers_ : user_protocol_handlers_;
849 ProtocolHandlerList& list = map[handler.protocol()];
850 if (!HandlerExists(handler, list))
851 list.push_back(handler);
852 if (IsRegistered(handler)) {
853 return;
855 if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol()))
856 delegate_->RegisterExternalHandler(handler.protocol());
857 InsertHandler(handler);
860 std::vector<const base::DictionaryValue*>
861 ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const {
862 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
863 std::vector<const base::DictionaryValue*> result;
864 PrefService* prefs = user_prefs::UserPrefs::Get(context_);
865 if (!prefs->HasPrefPath(pref_name)) {
866 return result;
869 const base::ListValue* handlers = prefs->GetList(pref_name);
870 if (handlers) {
871 for (size_t i = 0; i < handlers->GetSize(); ++i) {
872 const base::DictionaryValue* dict;
873 if (!handlers->GetDictionary(i, &dict))
874 continue;
875 if (ProtocolHandler::IsValidDict(dict)) {
876 result.push_back(dict);
880 return result;
883 void ProtocolHandlerRegistry::RegisterProtocolHandlersFromPref(
884 const char* pref_name,
885 const HandlerSource source) {
886 std::vector<const base::DictionaryValue*> registered_handlers =
887 GetHandlersFromPref(pref_name);
888 for (std::vector<const base::DictionaryValue*>::const_iterator p =
889 registered_handlers.begin();
890 p != registered_handlers.end();
891 ++p) {
892 ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p);
893 RegisterProtocolHandler(handler, source);
894 bool is_default = false;
895 if ((*p)->GetBoolean("default", &is_default) && is_default) {
896 SetDefault(handler);
901 void ProtocolHandlerRegistry::IgnoreProtocolHandler(
902 const ProtocolHandler& handler,
903 const HandlerSource source) {
904 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
905 ProtocolHandlerList& list = (source == POLICY)
906 ? policy_ignored_protocol_handlers_
907 : user_ignored_protocol_handlers_;
908 if (!HandlerExists(handler, list))
909 list.push_back(handler);
910 if (HandlerExists(handler, ignored_protocol_handlers_))
911 return;
912 ignored_protocol_handlers_.push_back(handler);
915 void ProtocolHandlerRegistry::IgnoreProtocolHandlersFromPref(
916 const char* pref_name,
917 const HandlerSource source) {
918 std::vector<const base::DictionaryValue*> ignored_handlers =
919 GetHandlersFromPref(pref_name);
920 for (std::vector<const base::DictionaryValue*>::const_iterator p =
921 ignored_handlers.begin();
922 p != ignored_handlers.end();
923 ++p) {
924 IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p), source);
928 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
929 ProtocolHandlerMultiMap* map) {
930 return HandlerExists(handler, (*map)[handler.protocol()]);
933 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
934 const ProtocolHandlerList& list) {
935 return std::find(list.begin(), list.end(), handler) != list.end();
938 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
939 ProtocolHandlerMultiMap* map) {
940 EraseHandler(handler, &(*map)[handler.protocol()]);
943 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
944 ProtocolHandlerList* list) {
945 list->erase(std::find(list->begin(), list->end(), handler));
948 void ProtocolHandlerRegistry::AddPredefinedHandler(
949 const ProtocolHandler& handler) {
950 DCHECK(!is_loaded_); // Must be called prior InitProtocolSettings.
951 RegisterProtocolHandler(handler, USER);
952 SetDefault(handler);
955 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
956 ProtocolHandlerRegistry::CreateJobInterceptorFactory() {
957 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
958 // this is always created on the UI thread (in profile_io's
959 // InitializeOnUIThread. Any method calls must be done
960 // on the IO thread (this is checked).
961 return scoped_ptr<JobInterceptorFactory>(
962 new JobInterceptorFactory(io_thread_delegate_.get()));