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/net/chrome_url_request_context.h"
16 #include "chrome/browser/profiles/profile_io_data.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/custom_handlers/protocol_handler.h"
19 #include "chrome/common/pref_names.h"
20 #include "components/pref_registry/pref_registry_syncable.h"
21 #include "content/public/browser/child_process_security_policy.h"
22 #include "grit/generated_resources.h"
23 #include "net/base/network_delegate.h"
24 #include "net/url_request/url_request_redirect_job.h"
25 #include "ui/base/l10n/l10n_util.h"
27 using content::BrowserThread
;
28 using content::ChildProcessSecurityPolicy
;
32 const ProtocolHandler
& LookupHandler(
33 const ProtocolHandlerRegistry::ProtocolHandlerMap
& handler_map
,
34 const std::string
& scheme
) {
35 ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p
=
36 handler_map
.find(scheme
);
38 if (p
!= handler_map
.end())
41 return ProtocolHandler::EmptyProtocolHandler();
44 // If true default protocol handlers will be removed if the OS level
45 // registration for a protocol is no longer Chrome.
46 bool ShouldRemoveHandlersNotInOS() {
48 // We don't do this on Linux as the OS registration there is not reliable,
49 // and Chrome OS doesn't have any notion of OS registration.
50 // TODO(benwells): When Linux support is more reliable remove this
51 // difference (http://crbug.com/88255).
54 return ShellIntegration::CanSetAsDefaultProtocolClient() !=
55 ShellIntegration::SET_DEFAULT_NOT_ALLOWED
;
61 // IOThreadDelegate ------------------------------------------------------------
63 // IOThreadDelegate is an IO thread specific object. Access to the class should
64 // all be done via the IO thread. The registry living on the UI thread makes
65 // a best effort to update the IO object after local updates are completed.
66 class ProtocolHandlerRegistry::IOThreadDelegate
67 : public base::RefCountedThreadSafe
<
68 ProtocolHandlerRegistry::IOThreadDelegate
> {
71 // Creates a new instance. If |enabled| is true the registry is considered
72 // enabled on the IO thread.
73 explicit IOThreadDelegate(bool enabled
);
75 // Returns true if the protocol has a default protocol handler.
76 // Should be called only from the IO thread.
77 bool IsHandledProtocol(const std::string
& scheme
) const;
79 // Clears the default for the provided protocol.
80 // Should be called only from the IO thread.
81 void ClearDefault(const std::string
& scheme
);
83 // Makes this ProtocolHandler the default handler for its protocol.
84 // Should be called only from the IO thread.
85 void SetDefault(const ProtocolHandler
& handler
);
87 // Creates a URL request job for the given request if there is a matching
88 // protocol handler, returns NULL otherwise.
89 net::URLRequestJob
* MaybeCreateJob(
90 net::URLRequest
* request
, net::NetworkDelegate
* network_delegate
) const;
92 // Indicate that the registry has been enabled in the IO thread's
94 void Enable() { enabled_
= true; }
96 // Indicate that the registry has been disabled in the IO thread's copy of
98 void Disable() { enabled_
= false; }
101 friend class base::RefCountedThreadSafe
<IOThreadDelegate
>;
102 virtual ~IOThreadDelegate();
104 // Copy of protocol handlers use only on the IO thread.
105 ProtocolHandlerRegistry::ProtocolHandlerMap default_handlers_
;
107 // Is the registry enabled on the IO thread.
110 DISALLOW_COPY_AND_ASSIGN(IOThreadDelegate
);
113 ProtocolHandlerRegistry::IOThreadDelegate::IOThreadDelegate(bool)
115 ProtocolHandlerRegistry::IOThreadDelegate::~IOThreadDelegate() {}
117 bool ProtocolHandlerRegistry::IOThreadDelegate::IsHandledProtocol(
118 const std::string
& scheme
) const {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
120 return enabled_
&& !LookupHandler(default_handlers_
, scheme
).IsEmpty();
123 void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault(
124 const std::string
& scheme
) {
125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
126 default_handlers_
.erase(scheme
);
129 void ProtocolHandlerRegistry::IOThreadDelegate::SetDefault(
130 const ProtocolHandler
& handler
) {
131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
132 ClearDefault(handler
.protocol());
133 default_handlers_
.insert(std::make_pair(handler
.protocol(), handler
));
136 // Create a new job for the supplied |URLRequest| if a default handler
137 // is registered and the associated handler is able to interpret
138 // the url from |request|.
139 net::URLRequestJob
* ProtocolHandlerRegistry::IOThreadDelegate::MaybeCreateJob(
140 net::URLRequest
* request
, net::NetworkDelegate
* network_delegate
) const {
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
143 ProtocolHandler handler
= LookupHandler(default_handlers_
,
144 request
->url().scheme());
145 if (handler
.IsEmpty())
148 GURL
translated_url(handler
.TranslateUrl(request
->url()));
149 if (!translated_url
.is_valid())
152 return new net::URLRequestRedirectJob(
153 request
, network_delegate
, translated_url
,
154 net::URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT
,
155 "Protocol Handler Registry");
158 // JobInterceptorFactory -------------------------------------------------------
160 // Instances of JobInterceptorFactory are produced for ownership by the IO
161 // thread where it handler URL requests. We should never hold
162 // any pointers on this class, only produce them in response to
163 // requests via |ProtocolHandlerRegistry::CreateJobInterceptorFactory|.
164 ProtocolHandlerRegistry::JobInterceptorFactory::JobInterceptorFactory(
165 IOThreadDelegate
* io_thread_delegate
)
166 : io_thread_delegate_(io_thread_delegate
) {
167 DCHECK(io_thread_delegate_
.get());
171 ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() {
174 void ProtocolHandlerRegistry::JobInterceptorFactory::Chain(
175 scoped_ptr
<net::URLRequestJobFactory
> job_factory
) {
176 job_factory_
= job_factory
.Pass();
180 ProtocolHandlerRegistry::JobInterceptorFactory::
181 MaybeCreateJobWithProtocolHandler(
182 const std::string
& scheme
,
183 net::URLRequest
* request
,
184 net::NetworkDelegate
* network_delegate
) const {
185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
186 net::URLRequestJob
* job
= io_thread_delegate_
->MaybeCreateJob(
187 request
, network_delegate
);
190 return job_factory_
->MaybeCreateJobWithProtocolHandler(
191 scheme
, request
, network_delegate
);
194 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledProtocol(
195 const std::string
& scheme
) const {
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
197 return io_thread_delegate_
->IsHandledProtocol(scheme
) ||
198 job_factory_
->IsHandledProtocol(scheme
);
201 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledURL(
202 const GURL
& url
) const {
203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
204 return (url
.is_valid() &&
205 io_thread_delegate_
->IsHandledProtocol(url
.scheme())) ||
206 job_factory_
->IsHandledURL(url
);
209 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsSafeRedirectTarget(
210 const GURL
& location
) const {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
212 return job_factory_
->IsSafeRedirectTarget(location
);
215 // DefaultClientObserver ------------------------------------------------------
217 ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver(
218 ProtocolHandlerRegistry
* registry
)
220 registry_(registry
) {
224 ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() {
226 worker_
->ObserverDestroyed();
228 DefaultClientObserverList::iterator iter
= std::find(
229 registry_
->default_client_observers_
.begin(),
230 registry_
->default_client_observers_
.end(), this);
231 registry_
->default_client_observers_
.erase(iter
);
234 void ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState(
235 ShellIntegration::DefaultWebClientUIState state
) {
237 if (ShouldRemoveHandlersNotInOS() &&
238 (state
== ShellIntegration::STATE_NOT_DEFAULT
)) {
239 registry_
->ClearDefault(worker_
->protocol());
246 bool ProtocolHandlerRegistry::DefaultClientObserver::
247 IsInteractiveSetDefaultPermitted() {
251 void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker(
252 ShellIntegration::DefaultProtocolClientWorker
* worker
) {
256 bool ProtocolHandlerRegistry::DefaultClientObserver::IsOwnedByWorker() {
260 // Delegate --------------------------------------------------------------------
262 ProtocolHandlerRegistry::Delegate::~Delegate() {}
264 void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler(
265 const std::string
& protocol
) {
266 ChildProcessSecurityPolicy
* policy
=
267 ChildProcessSecurityPolicy::GetInstance();
268 if (!policy
->IsWebSafeScheme(protocol
)) {
269 policy
->RegisterWebSafeScheme(protocol
);
273 void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
274 const std::string
& protocol
) {
277 bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered(
278 const std::string
& protocol
) {
279 // NOTE(koz): This function is safe to call from any thread, despite living
281 return ProfileIOData::IsHandledProtocol(protocol
);
284 ShellIntegration::DefaultProtocolClientWorker
*
285 ProtocolHandlerRegistry::Delegate::CreateShellWorker(
286 ShellIntegration::DefaultWebClientObserver
* observer
,
287 const std::string
& protocol
) {
288 return new ShellIntegration::DefaultProtocolClientWorker(observer
, protocol
);
291 ProtocolHandlerRegistry::DefaultClientObserver
*
292 ProtocolHandlerRegistry::Delegate::CreateShellObserver(
293 ProtocolHandlerRegistry
* registry
) {
294 return new DefaultClientObserver(registry
);
297 void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient(
298 const std::string
& protocol
, ProtocolHandlerRegistry
* registry
) {
299 DefaultClientObserver
* observer
= CreateShellObserver(registry
);
300 // The worker pointer is reference counted. While it is running the
301 // message loops of the FILE and UI thread will hold references to it
302 // and it will be automatically freed once all its tasks have finished.
303 scoped_refptr
<ShellIntegration::DefaultProtocolClientWorker
> worker
;
304 worker
= CreateShellWorker(observer
, protocol
);
305 observer
->SetWorker(worker
.get());
306 registry
->default_client_observers_
.push_back(observer
);
307 worker
->StartSetAsDefault();
310 // ProtocolHandlerRegistry -----------------------------------------------------
312 ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile
* profile
,
319 io_thread_delegate_(new IOThreadDelegate(enabled_
)){
322 bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest(
323 const ProtocolHandler
& handler
) {
324 if (handler
.IsEmpty() || !CanSchemeBeOverridden(handler
.protocol()))
327 if (!enabled() || IsRegistered(handler
) || HasIgnoredEquivalent(handler
))
330 if (AttemptReplace(handler
))
336 void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler(
337 const ProtocolHandler
& handler
) {
338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
339 RegisterProtocolHandler(handler
, USER
);
345 void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
346 const ProtocolHandler
& handler
) {
347 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
348 RegisterProtocolHandler(handler
, USER
);
353 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
354 const ProtocolHandler
& handler
) {
355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
356 IgnoreProtocolHandler(handler
, USER
);
361 bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler
& handler
) {
362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
363 ProtocolHandler old_default
= GetHandlerFor(handler
.protocol());
364 bool make_new_handler_default
= handler
.IsSameOrigin(old_default
);
365 ProtocolHandlerList
to_replace(GetReplacedHandlers(handler
));
366 if (to_replace
.empty())
368 for (ProtocolHandlerList::iterator p
= to_replace
.begin();
369 p
!= to_replace
.end(); ++p
) {
372 if (make_new_handler_default
) {
373 OnAcceptRegisterProtocolHandler(handler
);
375 InsertHandler(handler
);
381 ProtocolHandlerRegistry::ProtocolHandlerList
382 ProtocolHandlerRegistry::GetReplacedHandlers(
383 const ProtocolHandler
& handler
) const {
384 ProtocolHandlerList replaced_handlers
;
385 const ProtocolHandlerList
* handlers
= GetHandlerList(handler
.protocol());
387 return replaced_handlers
;
388 for (ProtocolHandlerList::const_iterator p
= handlers
->begin();
389 p
!= handlers
->end(); p
++) {
390 if (handler
.IsSameOrigin(*p
)) {
391 replaced_handlers
.push_back(*p
);
394 return replaced_handlers
;
397 void ProtocolHandlerRegistry::ClearDefault(const std::string
& scheme
) {
398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
400 default_handlers_
.erase(scheme
);
401 BrowserThread::PostTask(
404 base::Bind(&IOThreadDelegate::ClearDefault
, io_thread_delegate_
, scheme
));
409 bool ProtocolHandlerRegistry::IsDefault(
410 const ProtocolHandler
& handler
) const {
411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
412 return GetHandlerFor(handler
.protocol()) == handler
;
415 void ProtocolHandlerRegistry::InstallDefaultsForChromeOS() {
416 #if defined(OS_CHROMEOS)
417 // Only chromeos has default protocol handlers at this point.
418 AddPredefinedHandler(
419 ProtocolHandler::CreateProtocolHandler(
421 GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_MAILTO_HANDLER_URL
))));
422 AddPredefinedHandler(
423 ProtocolHandler::CreateProtocolHandler(
425 GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL
))));
427 NOTREACHED(); // this method should only ever be called in chromeos.
431 void ProtocolHandlerRegistry::InitProtocolSettings() {
432 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
434 // Any further default additions to the table will get rejected from now on.
438 PrefService
* prefs
= profile_
->GetPrefs();
439 if (prefs
->HasPrefPath(prefs::kCustomHandlersEnabled
)) {
440 if (prefs
->GetBoolean(prefs::kCustomHandlersEnabled
)) {
447 RegisterProtocolHandlersFromPref(prefs::kPolicyRegisteredProtocolHandlers
,
449 RegisterProtocolHandlersFromPref(prefs::kRegisteredProtocolHandlers
, USER
);
450 IgnoreProtocolHandlersFromPref(prefs::kPolicyIgnoredProtocolHandlers
, POLICY
);
451 IgnoreProtocolHandlersFromPref(prefs::kIgnoredProtocolHandlers
, USER
);
455 // For each default protocol handler, check that we are still registered
456 // with the OS as the default application.
457 if (ShouldRemoveHandlersNotInOS()) {
458 for (ProtocolHandlerMap::const_iterator p
= default_handlers_
.begin();
459 p
!= default_handlers_
.end(); ++p
) {
460 ProtocolHandler handler
= p
->second
;
461 DefaultClientObserver
* observer
= delegate_
->CreateShellObserver(this);
462 scoped_refptr
<ShellIntegration::DefaultProtocolClientWorker
> worker
;
463 worker
= delegate_
->CreateShellWorker(observer
, handler
.protocol());
464 observer
->SetWorker(worker
.get());
465 default_client_observers_
.push_back(observer
);
466 worker
->StartCheckIsDefault();
471 int ProtocolHandlerRegistry::GetHandlerIndex(const std::string
& scheme
) const {
472 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
473 const ProtocolHandler
& handler
= GetHandlerFor(scheme
);
474 if (handler
.IsEmpty())
476 const ProtocolHandlerList
* handlers
= GetHandlerList(scheme
);
480 ProtocolHandlerList::const_iterator p
;
482 for (i
= 0, p
= handlers
->begin(); p
!= handlers
->end(); ++p
, ++i
) {
489 ProtocolHandlerRegistry::ProtocolHandlerList
490 ProtocolHandlerRegistry::GetHandlersFor(
491 const std::string
& scheme
) const {
492 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
493 ProtocolHandlerMultiMap::const_iterator p
= protocol_handlers_
.find(scheme
);
494 if (p
== protocol_handlers_
.end()) {
495 return ProtocolHandlerList();
500 ProtocolHandlerRegistry::ProtocolHandlerList
501 ProtocolHandlerRegistry::GetIgnoredHandlers() {
502 return ignored_protocol_handlers_
;
505 void ProtocolHandlerRegistry::GetRegisteredProtocols(
506 std::vector
<std::string
>* output
) const {
507 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
508 ProtocolHandlerMultiMap::const_iterator p
;
509 for (p
= protocol_handlers_
.begin(); p
!= protocol_handlers_
.end(); ++p
) {
510 if (!p
->second
.empty())
511 output
->push_back(p
->first
);
515 bool ProtocolHandlerRegistry::CanSchemeBeOverridden(
516 const std::string
& scheme
) const {
517 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
518 const ProtocolHandlerList
* handlers
= GetHandlerList(scheme
);
519 // If we already have a handler for this scheme, we can add more.
520 if (handlers
!= NULL
&& !handlers
->empty())
522 // Don't override a scheme if it already has an external handler.
523 return !delegate_
->IsExternalHandlerRegistered(scheme
);
526 bool ProtocolHandlerRegistry::IsRegistered(
527 const ProtocolHandler
& handler
) const {
528 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
529 const ProtocolHandlerList
* handlers
= GetHandlerList(handler
.protocol());
533 return std::find(handlers
->begin(), handlers
->end(), handler
) !=
537 bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler
& handler
) const {
538 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
539 ProtocolHandlerList::const_iterator i
;
540 for (i
= ignored_protocol_handlers_
.begin();
541 i
!= ignored_protocol_handlers_
.end(); ++i
) {
549 bool ProtocolHandlerRegistry::HasRegisteredEquivalent(
550 const ProtocolHandler
& handler
) const {
551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
552 const ProtocolHandlerList
* handlers
= GetHandlerList(handler
.protocol());
556 ProtocolHandlerList::const_iterator i
;
557 for (i
= handlers
->begin(); i
!= handlers
->end(); ++i
) {
558 if (handler
.IsEquivalent(*i
)) {
565 bool ProtocolHandlerRegistry::HasIgnoredEquivalent(
566 const ProtocolHandler
& handler
) const {
567 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
568 ProtocolHandlerList::const_iterator i
;
569 for (i
= ignored_protocol_handlers_
.begin();
570 i
!= ignored_protocol_handlers_
.end(); ++i
) {
571 if (handler
.IsEquivalent(*i
)) {
578 void ProtocolHandlerRegistry::RemoveIgnoredHandler(
579 const ProtocolHandler
& handler
) {
580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
581 bool should_notify
= false;
582 if (HandlerExists(handler
, ignored_protocol_handlers_
) &&
583 HandlerExists(handler
, user_ignored_protocol_handlers_
)) {
584 EraseHandler(handler
, &user_ignored_protocol_handlers_
);
586 if (!HandlerExists(handler
, policy_ignored_protocol_handlers_
)) {
587 EraseHandler(handler
, &ignored_protocol_handlers_
);
588 should_notify
= true;
595 bool ProtocolHandlerRegistry::IsHandledProtocol(
596 const std::string
& scheme
) const {
597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
598 return enabled_
&& !GetHandlerFor(scheme
).IsEmpty();
601 void ProtocolHandlerRegistry::RemoveHandler(
602 const ProtocolHandler
& handler
) {
603 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
604 ProtocolHandlerList
& handlers
= protocol_handlers_
[handler
.protocol()];
605 bool erase_success
= false;
606 if (HandlerExists(handler
, handlers
) &&
607 HandlerExists(handler
, &user_protocol_handlers_
)) {
608 EraseHandler(handler
, &user_protocol_handlers_
);
609 if (!HandlerExists(handler
, &policy_protocol_handlers_
)) {
610 erase_success
= true;
611 EraseHandler(handler
, &protocol_handlers_
);
614 ProtocolHandlerMap::iterator q
= default_handlers_
.find(handler
.protocol());
615 if (erase_success
&& q
!= default_handlers_
.end() && q
->second
== handler
) {
616 // Make the new top handler in the list the default.
617 if (!handlers
.empty()) {
618 // NOTE We pass a copy because SetDefault() modifies handlers.
619 SetDefault(ProtocolHandler(handlers
[0]));
621 BrowserThread::PostTask(
622 BrowserThread::IO
, FROM_HERE
,
623 base::Bind(&IOThreadDelegate::ClearDefault
, io_thread_delegate_
,
624 q
->second
.protocol()));
626 default_handlers_
.erase(q
);
630 if (erase_success
&& !IsHandledProtocol(handler
.protocol())) {
631 delegate_
->DeregisterExternalHandler(handler
.protocol());
638 void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string
& scheme
) {
639 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
640 ProtocolHandler current_default
= GetHandlerFor(scheme
);
641 if (!current_default
.IsEmpty())
642 RemoveHandler(current_default
);
645 const ProtocolHandler
& ProtocolHandlerRegistry::GetHandlerFor(
646 const std::string
& scheme
) const {
647 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
648 return LookupHandler(default_handlers_
, scheme
);
651 void ProtocolHandlerRegistry::Enable() {
652 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
657 BrowserThread::PostTask(
660 base::Bind(&IOThreadDelegate::Enable
, io_thread_delegate_
));
662 ProtocolHandlerMap::const_iterator p
;
663 for (p
= default_handlers_
.begin(); p
!= default_handlers_
.end(); ++p
) {
664 delegate_
->RegisterExternalHandler(p
->first
);
670 void ProtocolHandlerRegistry::Disable() {
671 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
676 BrowserThread::PostTask(
679 base::Bind(&IOThreadDelegate::Disable
, io_thread_delegate_
));
681 ProtocolHandlerMap::const_iterator p
;
682 for (p
= default_handlers_
.begin(); p
!= default_handlers_
.end(); ++p
) {
683 delegate_
->DeregisterExternalHandler(p
->first
);
689 void ProtocolHandlerRegistry::Shutdown() {
690 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
691 delegate_
.reset(NULL
);
692 // We free these now in case there are any outstanding workers running. If
693 // we didn't free them they could respond to workers and try to update the
694 // protocol handler registry after it was deleted.
695 // Observers remove themselves from this list when they are deleted; so
696 // we delete the last item until none are left in the list.
697 while (!default_client_observers_
.empty()) {
698 delete default_client_observers_
.back();
703 void ProtocolHandlerRegistry::RegisterProfilePrefs(
704 user_prefs::PrefRegistrySyncable
* registry
) {
705 registry
->RegisterListPref(prefs::kRegisteredProtocolHandlers
,
706 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
707 registry
->RegisterListPref(prefs::kIgnoredProtocolHandlers
,
708 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
709 registry
->RegisterListPref(prefs::kPolicyRegisteredProtocolHandlers
,
710 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
711 registry
->RegisterListPref(prefs::kPolicyIgnoredProtocolHandlers
,
712 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
713 registry
->RegisterBooleanPref(
714 prefs::kCustomHandlersEnabled
,
716 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
719 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
720 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
721 DCHECK(default_client_observers_
.empty());
724 void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler
& handler
) {
725 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
726 DCHECK(IsRegistered(handler
));
727 ProtocolHandlerMultiMap::iterator p
=
728 protocol_handlers_
.find(handler
.protocol());
729 ProtocolHandlerList
& list
= p
->second
;
730 list
.erase(std::find(list
.begin(), list
.end(), handler
));
731 list
.insert(list
.begin(), handler
);
734 void ProtocolHandlerRegistry::Save() {
735 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
739 scoped_ptr
<base::Value
> registered_protocol_handlers(
740 EncodeRegisteredHandlers());
741 scoped_ptr
<base::Value
> ignored_protocol_handlers(EncodeIgnoredHandlers());
742 scoped_ptr
<base::Value
> enabled(base::Value::CreateBooleanValue(enabled_
));
743 profile_
->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers
,
744 *registered_protocol_handlers
);
745 profile_
->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers
,
746 *ignored_protocol_handlers
);
747 profile_
->GetPrefs()->Set(prefs::kCustomHandlersEnabled
, *enabled
);
750 const ProtocolHandlerRegistry::ProtocolHandlerList
*
751 ProtocolHandlerRegistry::GetHandlerList(
752 const std::string
& scheme
) const {
753 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
754 ProtocolHandlerMultiMap::const_iterator p
= protocol_handlers_
.find(scheme
);
755 if (p
== protocol_handlers_
.end()) {
761 void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler
& handler
) {
762 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
763 ProtocolHandlerMap::const_iterator p
= default_handlers_
.find(
765 // If we're not loading, and we are setting a default for a new protocol,
766 // register with the OS.
767 if (!is_loading_
&& p
== default_handlers_
.end())
768 delegate_
->RegisterWithOSAsDefaultClient(handler
.protocol(), this);
769 default_handlers_
.erase(handler
.protocol());
770 default_handlers_
.insert(std::make_pair(handler
.protocol(), handler
));
771 PromoteHandler(handler
);
772 BrowserThread::PostTask(
775 base::Bind(&IOThreadDelegate::SetDefault
, io_thread_delegate_
, handler
));
778 void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler
& handler
) {
779 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
780 ProtocolHandlerMultiMap::iterator p
=
781 protocol_handlers_
.find(handler
.protocol());
783 if (p
!= protocol_handlers_
.end()) {
784 p
->second
.push_back(handler
);
788 ProtocolHandlerList new_list
;
789 new_list
.push_back(handler
);
790 protocol_handlers_
[handler
.protocol()] = new_list
;
793 base::Value
* ProtocolHandlerRegistry::EncodeRegisteredHandlers() {
794 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
795 base::ListValue
* protocol_handlers
= new base::ListValue();
796 for (ProtocolHandlerMultiMap::iterator i
= user_protocol_handlers_
.begin();
797 i
!= user_protocol_handlers_
.end();
799 for (ProtocolHandlerList::iterator j
= i
->second
.begin();
800 j
!= i
->second
.end(); ++j
) {
801 base::DictionaryValue
* encoded
= j
->Encode();
803 encoded
->Set("default", base::Value::CreateBooleanValue(true));
805 protocol_handlers
->Append(encoded
);
808 return protocol_handlers
;
811 base::Value
* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
812 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
813 base::ListValue
* handlers
= new base::ListValue();
814 for (ProtocolHandlerList::iterator i
=
815 user_ignored_protocol_handlers_
.begin();
816 i
!= user_ignored_protocol_handlers_
.end();
818 handlers
->Append(i
->Encode());
823 void ProtocolHandlerRegistry::NotifyChanged() {
824 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
825 content::NotificationService::current()->Notify(
826 chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED
,
827 content::Source
<Profile
>(profile_
),
828 content::NotificationService::NoDetails());
831 void ProtocolHandlerRegistry::RegisterProtocolHandler(
832 const ProtocolHandler
& handler
,
833 const HandlerSource source
) {
834 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
835 DCHECK(CanSchemeBeOverridden(handler
.protocol()));
836 DCHECK(!handler
.IsEmpty());
837 ProtocolHandlerMultiMap
& map
=
838 (source
== POLICY
) ? policy_protocol_handlers_
: user_protocol_handlers_
;
839 ProtocolHandlerList
& list
= map
[handler
.protocol()];
840 if (!HandlerExists(handler
, list
))
841 list
.push_back(handler
);
842 if (IsRegistered(handler
)) {
845 if (enabled_
&& !delegate_
->IsExternalHandlerRegistered(handler
.protocol()))
846 delegate_
->RegisterExternalHandler(handler
.protocol());
847 InsertHandler(handler
);
850 std::vector
<const base::DictionaryValue
*>
851 ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name
) const {
852 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
853 std::vector
<const base::DictionaryValue
*> result
;
854 PrefService
* prefs
= profile_
->GetPrefs();
855 if (!prefs
->HasPrefPath(pref_name
)) {
859 const base::ListValue
* handlers
= prefs
->GetList(pref_name
);
861 for (size_t i
= 0; i
< handlers
->GetSize(); ++i
) {
862 const base::DictionaryValue
* dict
;
863 if (!handlers
->GetDictionary(i
, &dict
))
865 if (ProtocolHandler::IsValidDict(dict
)) {
866 result
.push_back(dict
);
873 void ProtocolHandlerRegistry::RegisterProtocolHandlersFromPref(
874 const char* pref_name
,
875 const HandlerSource source
) {
876 std::vector
<const base::DictionaryValue
*> registered_handlers
=
877 GetHandlersFromPref(pref_name
);
878 for (std::vector
<const base::DictionaryValue
*>::const_iterator p
=
879 registered_handlers
.begin();
880 p
!= registered_handlers
.end();
882 ProtocolHandler handler
= ProtocolHandler::CreateProtocolHandler(*p
);
883 RegisterProtocolHandler(handler
, source
);
884 bool is_default
= false;
885 if ((*p
)->GetBoolean("default", &is_default
) && is_default
) {
891 void ProtocolHandlerRegistry::IgnoreProtocolHandler(
892 const ProtocolHandler
& handler
,
893 const HandlerSource source
) {
894 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
895 ProtocolHandlerList
& list
= (source
== POLICY
)
896 ? policy_ignored_protocol_handlers_
897 : user_ignored_protocol_handlers_
;
898 if (!HandlerExists(handler
, list
))
899 list
.push_back(handler
);
900 if (HandlerExists(handler
, ignored_protocol_handlers_
))
902 ignored_protocol_handlers_
.push_back(handler
);
905 void ProtocolHandlerRegistry::IgnoreProtocolHandlersFromPref(
906 const char* pref_name
,
907 const HandlerSource source
) {
908 std::vector
<const base::DictionaryValue
*> ignored_handlers
=
909 GetHandlersFromPref(pref_name
);
910 for (std::vector
<const base::DictionaryValue
*>::const_iterator p
=
911 ignored_handlers
.begin();
912 p
!= ignored_handlers
.end();
914 IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p
), source
);
918 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler
& handler
,
919 ProtocolHandlerMultiMap
* map
) {
920 return HandlerExists(handler
, (*map
)[handler
.protocol()]);
923 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler
& handler
,
924 const ProtocolHandlerList
& list
) {
925 return std::find(list
.begin(), list
.end(), handler
) != list
.end();
928 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler
& handler
,
929 ProtocolHandlerMultiMap
* map
) {
930 EraseHandler(handler
, &(*map
)[handler
.protocol()]);
933 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler
& handler
,
934 ProtocolHandlerList
* list
) {
935 list
->erase(std::find(list
->begin(), list
->end(), handler
));
938 void ProtocolHandlerRegistry::AddPredefinedHandler(
939 const ProtocolHandler
& handler
) {
940 DCHECK(!is_loaded_
); // Must be called prior InitProtocolSettings.
941 RegisterProtocolHandler(handler
, USER
);
945 scoped_ptr
<ProtocolHandlerRegistry::JobInterceptorFactory
>
946 ProtocolHandlerRegistry::CreateJobInterceptorFactory() {
947 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
948 // this is always created on the UI thread (in profile_io's
949 // InitializeOnUIThread. Any method calls must be done
950 // on the IO thread (this is checked).
951 return scoped_ptr
<JobInterceptorFactory
>(
952 new JobInterceptorFactory(io_thread_delegate_
.get()));