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"
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
;
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())
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() {
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).
53 return ShellIntegration::CanSetAsDefaultProtocolClient() !=
54 ShellIntegration::SET_DEFAULT_NOT_ALLOWED
;
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
> {
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
93 void Enable() { enabled_
= true; }
95 // Indicate that the registry has been disabled in the IO thread's copy of
97 void Disable() { enabled_
= false; }
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.
109 DISALLOW_COPY_AND_ASSIGN(IOThreadDelegate
);
112 ProtocolHandlerRegistry::IOThreadDelegate::IOThreadDelegate(bool)
114 ProtocolHandlerRegistry::IOThreadDelegate::~IOThreadDelegate() {}
116 bool ProtocolHandlerRegistry::IOThreadDelegate::IsHandledProtocol(
117 const std::string
& scheme
) const {
118 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
119 return enabled_
&& !LookupHandler(default_handlers_
, scheme
).IsEmpty();
122 void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault(
123 const std::string
& scheme
) {
124 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
125 default_handlers_
.erase(scheme
);
128 void ProtocolHandlerRegistry::IOThreadDelegate::SetDefault(
129 const ProtocolHandler
& handler
) {
130 DCHECK_CURRENTLY_ON(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_CURRENTLY_ON(BrowserThread::IO
);
142 ProtocolHandler handler
= LookupHandler(default_handlers_
,
143 request
->url().scheme());
144 if (handler
.IsEmpty())
147 GURL
translated_url(handler
.TranslateUrl(request
->url()));
148 if (!translated_url
.is_valid())
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());
170 ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() {
173 void ProtocolHandlerRegistry::JobInterceptorFactory::Chain(
174 scoped_ptr
<net::URLRequestJobFactory
> job_factory
) {
175 job_factory_
= job_factory
.Pass();
179 ProtocolHandlerRegistry::JobInterceptorFactory::
180 MaybeCreateJobWithProtocolHandler(
181 const std::string
& scheme
,
182 net::URLRequest
* request
,
183 net::NetworkDelegate
* network_delegate
) const {
184 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
185 net::URLRequestJob
* job
= io_thread_delegate_
->MaybeCreateJob(
186 request
, network_delegate
);
189 return job_factory_
->MaybeCreateJobWithProtocolHandler(
190 scheme
, request
, network_delegate
);
194 ProtocolHandlerRegistry::JobInterceptorFactory::MaybeInterceptRedirect(
195 net::URLRequest
* request
,
196 net::NetworkDelegate
* network_delegate
,
197 const GURL
& location
) const {
198 return job_factory_
->MaybeInterceptRedirect(
199 request
, network_delegate
, location
);
203 ProtocolHandlerRegistry::JobInterceptorFactory::MaybeInterceptResponse(
204 net::URLRequest
* request
,
205 net::NetworkDelegate
* network_delegate
) const {
206 return job_factory_
->MaybeInterceptResponse(request
, network_delegate
);
209 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledProtocol(
210 const std::string
& scheme
) const {
211 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
212 return io_thread_delegate_
->IsHandledProtocol(scheme
) ||
213 job_factory_
->IsHandledProtocol(scheme
);
216 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledURL(
217 const GURL
& url
) const {
218 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
219 return (url
.is_valid() &&
220 io_thread_delegate_
->IsHandledProtocol(url
.scheme())) ||
221 job_factory_
->IsHandledURL(url
);
224 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsSafeRedirectTarget(
225 const GURL
& location
) const {
226 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
227 return job_factory_
->IsSafeRedirectTarget(location
);
230 // DefaultClientObserver ------------------------------------------------------
232 ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver(
233 ProtocolHandlerRegistry
* registry
)
235 registry_(registry
) {
239 ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() {
241 worker_
->ObserverDestroyed();
243 DefaultClientObserverList::iterator iter
= std::find(
244 registry_
->default_client_observers_
.begin(),
245 registry_
->default_client_observers_
.end(), this);
246 registry_
->default_client_observers_
.erase(iter
);
249 void ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState(
250 ShellIntegration::DefaultWebClientUIState state
) {
252 if (ShouldRemoveHandlersNotInOS() &&
253 (state
== ShellIntegration::STATE_NOT_DEFAULT
)) {
254 registry_
->ClearDefault(worker_
->protocol());
261 bool ProtocolHandlerRegistry::DefaultClientObserver::
262 IsInteractiveSetDefaultPermitted() {
266 void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker(
267 ShellIntegration::DefaultProtocolClientWorker
* worker
) {
271 bool ProtocolHandlerRegistry::DefaultClientObserver::IsOwnedByWorker() {
275 // Delegate --------------------------------------------------------------------
277 ProtocolHandlerRegistry::Delegate::~Delegate() {}
279 void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler(
280 const std::string
& protocol
) {
281 ChildProcessSecurityPolicy
* policy
=
282 ChildProcessSecurityPolicy::GetInstance();
283 if (!policy
->IsWebSafeScheme(protocol
)) {
284 policy
->RegisterWebSafeScheme(protocol
);
288 void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
289 const std::string
& protocol
) {
292 bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered(
293 const std::string
& protocol
) {
294 // NOTE(koz): This function is safe to call from any thread, despite living
296 return ProfileIOData::IsHandledProtocol(protocol
);
299 ShellIntegration::DefaultProtocolClientWorker
*
300 ProtocolHandlerRegistry::Delegate::CreateShellWorker(
301 ShellIntegration::DefaultWebClientObserver
* observer
,
302 const std::string
& protocol
) {
303 return new ShellIntegration::DefaultProtocolClientWorker(observer
, protocol
);
306 ProtocolHandlerRegistry::DefaultClientObserver
*
307 ProtocolHandlerRegistry::Delegate::CreateShellObserver(
308 ProtocolHandlerRegistry
* registry
) {
309 return new DefaultClientObserver(registry
);
312 void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient(
313 const std::string
& protocol
, ProtocolHandlerRegistry
* registry
) {
314 DefaultClientObserver
* observer
= CreateShellObserver(registry
);
315 // The worker pointer is reference counted. While it is running the
316 // message loops of the FILE and UI thread will hold references to it
317 // and it will be automatically freed once all its tasks have finished.
318 scoped_refptr
<ShellIntegration::DefaultProtocolClientWorker
> worker
;
319 worker
= CreateShellWorker(observer
, protocol
);
320 observer
->SetWorker(worker
.get());
321 registry
->default_client_observers_
.push_back(observer
);
322 worker
->StartSetAsDefault();
325 // ProtocolHandlerRegistry -----------------------------------------------------
327 ProtocolHandlerRegistry::ProtocolHandlerRegistry(
328 content::BrowserContext
* context
, Delegate
* delegate
)
334 io_thread_delegate_(new IOThreadDelegate(enabled_
)){
337 bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest(
338 const ProtocolHandler
& handler
) {
339 if (handler
.IsEmpty() || !CanSchemeBeOverridden(handler
.protocol()))
342 if (!enabled() || IsRegistered(handler
) || HasIgnoredEquivalent(handler
))
345 if (AttemptReplace(handler
))
351 void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler(
352 const ProtocolHandler
& handler
) {
353 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
354 RegisterProtocolHandler(handler
, USER
);
360 void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
361 const ProtocolHandler
& handler
) {
362 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
363 RegisterProtocolHandler(handler
, USER
);
368 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
369 const ProtocolHandler
& handler
) {
370 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
371 IgnoreProtocolHandler(handler
, USER
);
376 bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler
& handler
) {
377 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
378 ProtocolHandler old_default
= GetHandlerFor(handler
.protocol());
379 bool make_new_handler_default
= handler
.IsSameOrigin(old_default
);
380 ProtocolHandlerList
to_replace(GetReplacedHandlers(handler
));
381 if (to_replace
.empty())
383 for (ProtocolHandlerList::iterator p
= to_replace
.begin();
384 p
!= to_replace
.end(); ++p
) {
387 if (make_new_handler_default
) {
388 OnAcceptRegisterProtocolHandler(handler
);
390 InsertHandler(handler
);
396 ProtocolHandlerRegistry::ProtocolHandlerList
397 ProtocolHandlerRegistry::GetReplacedHandlers(
398 const ProtocolHandler
& handler
) const {
399 ProtocolHandlerList replaced_handlers
;
400 const ProtocolHandlerList
* handlers
= GetHandlerList(handler
.protocol());
402 return replaced_handlers
;
403 for (ProtocolHandlerList::const_iterator p
= handlers
->begin();
404 p
!= handlers
->end(); p
++) {
405 if (handler
.IsSameOrigin(*p
)) {
406 replaced_handlers
.push_back(*p
);
409 return replaced_handlers
;
412 void ProtocolHandlerRegistry::ClearDefault(const std::string
& scheme
) {
413 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
415 default_handlers_
.erase(scheme
);
416 BrowserThread::PostTask(
419 base::Bind(&IOThreadDelegate::ClearDefault
, io_thread_delegate_
, scheme
));
424 bool ProtocolHandlerRegistry::IsDefault(
425 const ProtocolHandler
& handler
) const {
426 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
427 return GetHandlerFor(handler
.protocol()) == handler
;
430 void ProtocolHandlerRegistry::InstallDefaultsForChromeOS() {
431 #if defined(OS_CHROMEOS)
432 // Only chromeos has default protocol handlers at this point.
433 AddPredefinedHandler(
434 ProtocolHandler::CreateProtocolHandler(
436 GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_MAILTO_HANDLER_URL
))));
437 AddPredefinedHandler(
438 ProtocolHandler::CreateProtocolHandler(
440 GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL
))));
442 NOTREACHED(); // this method should only ever be called in chromeos.
446 void ProtocolHandlerRegistry::InitProtocolSettings() {
447 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
449 // Any further default additions to the table will get rejected from now on.
453 PrefService
* prefs
= user_prefs::UserPrefs::Get(context_
);
454 if (prefs
->HasPrefPath(prefs::kCustomHandlersEnabled
)) {
455 if (prefs
->GetBoolean(prefs::kCustomHandlersEnabled
)) {
462 RegisterProtocolHandlersFromPref(prefs::kPolicyRegisteredProtocolHandlers
,
464 RegisterProtocolHandlersFromPref(prefs::kRegisteredProtocolHandlers
, USER
);
465 IgnoreProtocolHandlersFromPref(prefs::kPolicyIgnoredProtocolHandlers
, POLICY
);
466 IgnoreProtocolHandlersFromPref(prefs::kIgnoredProtocolHandlers
, USER
);
470 // For each default protocol handler, check that we are still registered
471 // with the OS as the default application.
472 if (ShouldRemoveHandlersNotInOS()) {
473 for (ProtocolHandlerMap::const_iterator p
= default_handlers_
.begin();
474 p
!= default_handlers_
.end(); ++p
) {
475 ProtocolHandler handler
= p
->second
;
476 DefaultClientObserver
* observer
= delegate_
->CreateShellObserver(this);
477 scoped_refptr
<ShellIntegration::DefaultProtocolClientWorker
> worker
;
478 worker
= delegate_
->CreateShellWorker(observer
, handler
.protocol());
479 observer
->SetWorker(worker
.get());
480 default_client_observers_
.push_back(observer
);
481 worker
->StartCheckIsDefault();
486 int ProtocolHandlerRegistry::GetHandlerIndex(const std::string
& scheme
) const {
487 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
488 const ProtocolHandler
& handler
= GetHandlerFor(scheme
);
489 if (handler
.IsEmpty())
491 const ProtocolHandlerList
* handlers
= GetHandlerList(scheme
);
495 ProtocolHandlerList::const_iterator p
;
497 for (i
= 0, p
= handlers
->begin(); p
!= handlers
->end(); ++p
, ++i
) {
504 ProtocolHandlerRegistry::ProtocolHandlerList
505 ProtocolHandlerRegistry::GetHandlersFor(
506 const std::string
& scheme
) const {
507 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
508 ProtocolHandlerMultiMap::const_iterator p
= protocol_handlers_
.find(scheme
);
509 if (p
== protocol_handlers_
.end()) {
510 return ProtocolHandlerList();
515 ProtocolHandlerRegistry::ProtocolHandlerList
516 ProtocolHandlerRegistry::GetIgnoredHandlers() {
517 return ignored_protocol_handlers_
;
520 void ProtocolHandlerRegistry::GetRegisteredProtocols(
521 std::vector
<std::string
>* output
) const {
522 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
523 ProtocolHandlerMultiMap::const_iterator p
;
524 for (p
= protocol_handlers_
.begin(); p
!= protocol_handlers_
.end(); ++p
) {
525 if (!p
->second
.empty())
526 output
->push_back(p
->first
);
530 bool ProtocolHandlerRegistry::CanSchemeBeOverridden(
531 const std::string
& scheme
) const {
532 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
533 const ProtocolHandlerList
* handlers
= GetHandlerList(scheme
);
534 // If we already have a handler for this scheme, we can add more.
535 if (handlers
!= NULL
&& !handlers
->empty())
537 // Don't override a scheme if it already has an external handler.
538 return !delegate_
->IsExternalHandlerRegistered(scheme
);
541 bool ProtocolHandlerRegistry::IsRegistered(
542 const ProtocolHandler
& handler
) const {
543 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
544 const ProtocolHandlerList
* handlers
= GetHandlerList(handler
.protocol());
548 return std::find(handlers
->begin(), handlers
->end(), handler
) !=
552 bool ProtocolHandlerRegistry::IsRegisteredByUser(
553 const ProtocolHandler
& handler
) {
554 return HandlerExists(handler
, &user_protocol_handlers_
);
557 bool ProtocolHandlerRegistry::HasPolicyRegisteredHandler(
558 const std::string
& scheme
) {
559 return (policy_protocol_handlers_
.find(scheme
) !=
560 policy_protocol_handlers_
.end());
563 bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler
& handler
) const {
564 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
565 ProtocolHandlerList::const_iterator i
;
566 for (i
= ignored_protocol_handlers_
.begin();
567 i
!= ignored_protocol_handlers_
.end(); ++i
) {
575 bool ProtocolHandlerRegistry::HasRegisteredEquivalent(
576 const ProtocolHandler
& handler
) const {
577 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
578 const ProtocolHandlerList
* handlers
= GetHandlerList(handler
.protocol());
582 ProtocolHandlerList::const_iterator i
;
583 for (i
= handlers
->begin(); i
!= handlers
->end(); ++i
) {
584 if (handler
.IsEquivalent(*i
)) {
591 bool ProtocolHandlerRegistry::HasIgnoredEquivalent(
592 const ProtocolHandler
& handler
) const {
593 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
594 ProtocolHandlerList::const_iterator i
;
595 for (i
= ignored_protocol_handlers_
.begin();
596 i
!= ignored_protocol_handlers_
.end(); ++i
) {
597 if (handler
.IsEquivalent(*i
)) {
604 void ProtocolHandlerRegistry::RemoveIgnoredHandler(
605 const ProtocolHandler
& handler
) {
606 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
607 bool should_notify
= false;
608 if (HandlerExists(handler
, ignored_protocol_handlers_
) &&
609 HandlerExists(handler
, user_ignored_protocol_handlers_
)) {
610 EraseHandler(handler
, &user_ignored_protocol_handlers_
);
612 if (!HandlerExists(handler
, policy_ignored_protocol_handlers_
)) {
613 EraseHandler(handler
, &ignored_protocol_handlers_
);
614 should_notify
= true;
621 bool ProtocolHandlerRegistry::IsHandledProtocol(
622 const std::string
& scheme
) const {
623 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
624 return enabled_
&& !GetHandlerFor(scheme
).IsEmpty();
627 void ProtocolHandlerRegistry::RemoveHandler(
628 const ProtocolHandler
& handler
) {
629 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
630 ProtocolHandlerList
& handlers
= protocol_handlers_
[handler
.protocol()];
631 bool erase_success
= false;
632 if (HandlerExists(handler
, handlers
) &&
633 HandlerExists(handler
, &user_protocol_handlers_
)) {
634 EraseHandler(handler
, &user_protocol_handlers_
);
635 erase_success
= true;
636 if (!HandlerExists(handler
, &policy_protocol_handlers_
))
637 EraseHandler(handler
, &protocol_handlers_
);
639 ProtocolHandlerMap::iterator q
= default_handlers_
.find(handler
.protocol());
640 if (erase_success
&& q
!= default_handlers_
.end() && q
->second
== handler
) {
641 // Make the new top handler in the list the default.
642 if (!handlers
.empty()) {
643 // NOTE We pass a copy because SetDefault() modifies handlers.
644 SetDefault(ProtocolHandler(handlers
[0]));
646 BrowserThread::PostTask(
647 BrowserThread::IO
, FROM_HERE
,
648 base::Bind(&IOThreadDelegate::ClearDefault
, io_thread_delegate_
,
649 q
->second
.protocol()));
651 default_handlers_
.erase(q
);
655 if (erase_success
&& !IsHandledProtocol(handler
.protocol())) {
656 delegate_
->DeregisterExternalHandler(handler
.protocol());
663 void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string
& scheme
) {
664 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
665 ProtocolHandler current_default
= GetHandlerFor(scheme
);
666 if (!current_default
.IsEmpty())
667 RemoveHandler(current_default
);
670 const ProtocolHandler
& ProtocolHandlerRegistry::GetHandlerFor(
671 const std::string
& scheme
) const {
672 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
673 return LookupHandler(default_handlers_
, scheme
);
676 void ProtocolHandlerRegistry::Enable() {
677 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
682 BrowserThread::PostTask(
685 base::Bind(&IOThreadDelegate::Enable
, io_thread_delegate_
));
687 ProtocolHandlerMap::const_iterator p
;
688 for (p
= default_handlers_
.begin(); p
!= default_handlers_
.end(); ++p
) {
689 delegate_
->RegisterExternalHandler(p
->first
);
695 void ProtocolHandlerRegistry::Disable() {
696 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
701 BrowserThread::PostTask(
704 base::Bind(&IOThreadDelegate::Disable
, io_thread_delegate_
));
706 ProtocolHandlerMap::const_iterator p
;
707 for (p
= default_handlers_
.begin(); p
!= default_handlers_
.end(); ++p
) {
708 delegate_
->DeregisterExternalHandler(p
->first
);
714 void ProtocolHandlerRegistry::Shutdown() {
715 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
716 delegate_
.reset(NULL
);
717 // We free these now in case there are any outstanding workers running. If
718 // we didn't free them they could respond to workers and try to update the
719 // protocol handler registry after it was deleted.
720 // Observers remove themselves from this list when they are deleted; so
721 // we delete the last item until none are left in the list.
722 while (!default_client_observers_
.empty()) {
723 delete default_client_observers_
.back();
728 void ProtocolHandlerRegistry::RegisterProfilePrefs(
729 user_prefs::PrefRegistrySyncable
* registry
) {
730 registry
->RegisterListPref(prefs::kRegisteredProtocolHandlers
);
731 registry
->RegisterListPref(prefs::kIgnoredProtocolHandlers
);
732 registry
->RegisterListPref(prefs::kPolicyRegisteredProtocolHandlers
);
733 registry
->RegisterListPref(prefs::kPolicyIgnoredProtocolHandlers
);
734 registry
->RegisterBooleanPref(prefs::kCustomHandlersEnabled
, true);
737 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
738 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
739 DCHECK(default_client_observers_
.empty());
742 void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler
& handler
) {
743 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
744 DCHECK(IsRegistered(handler
));
745 ProtocolHandlerMultiMap::iterator p
=
746 protocol_handlers_
.find(handler
.protocol());
747 ProtocolHandlerList
& list
= p
->second
;
748 list
.erase(std::find(list
.begin(), list
.end(), handler
));
749 list
.insert(list
.begin(), handler
);
752 void ProtocolHandlerRegistry::Save() {
753 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
757 scoped_ptr
<base::Value
> registered_protocol_handlers(
758 EncodeRegisteredHandlers());
759 scoped_ptr
<base::Value
> ignored_protocol_handlers(EncodeIgnoredHandlers());
760 PrefService
* prefs
= user_prefs::UserPrefs::Get(context_
);
762 prefs
->Set(prefs::kRegisteredProtocolHandlers
,
763 *registered_protocol_handlers
);
764 prefs
->Set(prefs::kIgnoredProtocolHandlers
,
765 *ignored_protocol_handlers
);
766 prefs
->SetBoolean(prefs::kCustomHandlersEnabled
, enabled_
);
769 const ProtocolHandlerRegistry::ProtocolHandlerList
*
770 ProtocolHandlerRegistry::GetHandlerList(
771 const std::string
& scheme
) const {
772 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
773 ProtocolHandlerMultiMap::const_iterator p
= protocol_handlers_
.find(scheme
);
774 if (p
== protocol_handlers_
.end()) {
780 void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler
& handler
) {
781 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
782 ProtocolHandlerMap::const_iterator p
= default_handlers_
.find(
784 // If we're not loading, and we are setting a default for a new protocol,
785 // register with the OS.
786 if (!is_loading_
&& p
== default_handlers_
.end())
787 delegate_
->RegisterWithOSAsDefaultClient(handler
.protocol(), this);
788 default_handlers_
.erase(handler
.protocol());
789 default_handlers_
.insert(std::make_pair(handler
.protocol(), handler
));
790 PromoteHandler(handler
);
791 BrowserThread::PostTask(
794 base::Bind(&IOThreadDelegate::SetDefault
, io_thread_delegate_
, handler
));
797 void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler
& handler
) {
798 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
799 ProtocolHandlerMultiMap::iterator p
=
800 protocol_handlers_
.find(handler
.protocol());
802 if (p
!= protocol_handlers_
.end()) {
803 p
->second
.push_back(handler
);
807 ProtocolHandlerList new_list
;
808 new_list
.push_back(handler
);
809 protocol_handlers_
[handler
.protocol()] = new_list
;
812 base::Value
* ProtocolHandlerRegistry::EncodeRegisteredHandlers() {
813 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
814 base::ListValue
* protocol_handlers
= new base::ListValue();
815 for (ProtocolHandlerMultiMap::iterator i
= user_protocol_handlers_
.begin();
816 i
!= user_protocol_handlers_
.end();
818 for (ProtocolHandlerList::iterator j
= i
->second
.begin();
819 j
!= i
->second
.end(); ++j
) {
820 base::DictionaryValue
* encoded
= j
->Encode();
822 encoded
->Set("default", new base::FundamentalValue(true));
824 protocol_handlers
->Append(encoded
);
827 return protocol_handlers
;
830 base::Value
* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
831 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
832 base::ListValue
* handlers
= new base::ListValue();
833 for (ProtocolHandlerList::iterator i
=
834 user_ignored_protocol_handlers_
.begin();
835 i
!= user_ignored_protocol_handlers_
.end();
837 handlers
->Append(i
->Encode());
842 void ProtocolHandlerRegistry::NotifyChanged() {
843 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
844 content::NotificationService::current()->Notify(
845 chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED
,
846 content::Source
<content::BrowserContext
>(context_
),
847 content::NotificationService::NoDetails());
850 void ProtocolHandlerRegistry::RegisterProtocolHandler(
851 const ProtocolHandler
& handler
,
852 const HandlerSource source
) {
853 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
854 DCHECK(CanSchemeBeOverridden(handler
.protocol()));
855 DCHECK(!handler
.IsEmpty());
856 ProtocolHandlerMultiMap
& map
=
857 (source
== POLICY
) ? policy_protocol_handlers_
: user_protocol_handlers_
;
858 ProtocolHandlerList
& list
= map
[handler
.protocol()];
859 if (!HandlerExists(handler
, list
))
860 list
.push_back(handler
);
861 if (IsRegistered(handler
)) {
864 if (enabled_
&& !delegate_
->IsExternalHandlerRegistered(handler
.protocol()))
865 delegate_
->RegisterExternalHandler(handler
.protocol());
866 InsertHandler(handler
);
869 std::vector
<const base::DictionaryValue
*>
870 ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name
) const {
871 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
872 std::vector
<const base::DictionaryValue
*> result
;
873 PrefService
* prefs
= user_prefs::UserPrefs::Get(context_
);
874 if (!prefs
->HasPrefPath(pref_name
)) {
878 const base::ListValue
* handlers
= prefs
->GetList(pref_name
);
880 for (size_t i
= 0; i
< handlers
->GetSize(); ++i
) {
881 const base::DictionaryValue
* dict
;
882 if (!handlers
->GetDictionary(i
, &dict
))
884 if (ProtocolHandler::IsValidDict(dict
)) {
885 result
.push_back(dict
);
892 void ProtocolHandlerRegistry::RegisterProtocolHandlersFromPref(
893 const char* pref_name
,
894 const HandlerSource source
) {
895 std::vector
<const base::DictionaryValue
*> registered_handlers
=
896 GetHandlersFromPref(pref_name
);
897 for (std::vector
<const base::DictionaryValue
*>::const_iterator p
=
898 registered_handlers
.begin();
899 p
!= registered_handlers
.end();
901 ProtocolHandler handler
= ProtocolHandler::CreateProtocolHandler(*p
);
902 RegisterProtocolHandler(handler
, source
);
903 bool is_default
= false;
904 if ((*p
)->GetBoolean("default", &is_default
) && is_default
) {
910 void ProtocolHandlerRegistry::IgnoreProtocolHandler(
911 const ProtocolHandler
& handler
,
912 const HandlerSource source
) {
913 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
914 ProtocolHandlerList
& list
= (source
== POLICY
)
915 ? policy_ignored_protocol_handlers_
916 : user_ignored_protocol_handlers_
;
917 if (!HandlerExists(handler
, list
))
918 list
.push_back(handler
);
919 if (HandlerExists(handler
, ignored_protocol_handlers_
))
921 ignored_protocol_handlers_
.push_back(handler
);
924 void ProtocolHandlerRegistry::IgnoreProtocolHandlersFromPref(
925 const char* pref_name
,
926 const HandlerSource source
) {
927 std::vector
<const base::DictionaryValue
*> ignored_handlers
=
928 GetHandlersFromPref(pref_name
);
929 for (std::vector
<const base::DictionaryValue
*>::const_iterator p
=
930 ignored_handlers
.begin();
931 p
!= ignored_handlers
.end();
933 IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p
), source
);
937 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler
& handler
,
938 ProtocolHandlerMultiMap
* map
) {
939 return HandlerExists(handler
, (*map
)[handler
.protocol()]);
942 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler
& handler
,
943 const ProtocolHandlerList
& list
) {
944 return std::find(list
.begin(), list
.end(), handler
) != list
.end();
947 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler
& handler
,
948 ProtocolHandlerMultiMap
* map
) {
949 EraseHandler(handler
, &(*map
)[handler
.protocol()]);
952 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler
& handler
,
953 ProtocolHandlerList
* list
) {
954 list
->erase(std::find(list
->begin(), list
->end(), handler
));
957 void ProtocolHandlerRegistry::AddPredefinedHandler(
958 const ProtocolHandler
& handler
) {
959 DCHECK(!is_loaded_
); // Must be called prior InitProtocolSettings.
960 RegisterProtocolHandler(handler
, USER
);
964 scoped_ptr
<ProtocolHandlerRegistry::JobInterceptorFactory
>
965 ProtocolHandlerRegistry::CreateJobInterceptorFactory() {
966 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
967 // this is always created on the UI thread (in profile_io's
968 // InitializeOnUIThread. Any method calls must be done
969 // on the IO thread (this is checked).
970 return scoped_ptr
<JobInterceptorFactory
>(
971 new JobInterceptorFactory(io_thread_delegate_
.get()));