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.
4
5 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
6
7 #include <utility>
8
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/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"
26
27 using content::BrowserThread;
28 using content::ChildProcessSecurityPolicy;
29
30 namespace {
31
LookupHandler(const ProtocolHandlerRegistry::ProtocolHandlerMap & handler_map,const std::string & scheme)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);
37
38 if (p != handler_map.end())
39 return p->second;
40
41 return ProtocolHandler::EmptyProtocolHandler();
42 }
43
44 // If true default protocol handlers will be removed if the OS level
45 // registration for a protocol is no longer Chrome.
ShouldRemoveHandlersNotInOS()46 bool ShouldRemoveHandlersNotInOS() {
47 #if defined(OS_LINUX)
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).
52 return false;
53 #else
54 return ShellIntegration::CanSetAsDefaultProtocolClient() !=
55 ShellIntegration::SET_DEFAULT_NOT_ALLOWED;
56 #endif
57 }
58
59 } // namespace
60
61 // IOThreadDelegate ------------------------------------------------------------
62
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> {
69 public:
70
71 // Creates a new instance. If |enabled| is true the registry is considered
72 // enabled on the IO thread.
73 explicit IOThreadDelegate(bool enabled);
74
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;
78
79 // Clears the default for the provided protocol.
80 // Should be called only from the IO thread.
81 void ClearDefault(const std::string& scheme);
82
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);
86
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;
91
92 // Indicate that the registry has been enabled in the IO thread's
93 // copy of the data.
Enable()94 void Enable() { enabled_ = true; }
95
96 // Indicate that the registry has been disabled in the IO thread's copy of
97 // the data.
Disable()98 void Disable() { enabled_ = false; }
99
100 private:
101 friend class base::RefCountedThreadSafe<IOThreadDelegate>;
102 virtual ~IOThreadDelegate();
103
104 // Copy of protocol handlers use only on the IO thread.
105 ProtocolHandlerRegistry::ProtocolHandlerMap default_handlers_;
106
107 // Is the registry enabled on the IO thread.
108 bool enabled_;
109
110 DISALLOW_COPY_AND_ASSIGN(IOThreadDelegate);
111 };
112
IOThreadDelegate(bool)113 ProtocolHandlerRegistry::IOThreadDelegate::IOThreadDelegate(bool)
114 : enabled_(true) {}
~IOThreadDelegate()115 ProtocolHandlerRegistry::IOThreadDelegate::~IOThreadDelegate() {}
116
IsHandledProtocol(const std::string & scheme) const117 bool ProtocolHandlerRegistry::IOThreadDelegate::IsHandledProtocol(
118 const std::string& scheme) const {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
120 return enabled_ && !LookupHandler(default_handlers_, scheme).IsEmpty();
121 }
122
ClearDefault(const std::string & scheme)123 void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault(
124 const std::string& scheme) {
125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
126 default_handlers_.erase(scheme);
127 }
128
SetDefault(const ProtocolHandler & handler)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));
134 }
135
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|.
MaybeCreateJob(net::URLRequest * request,net::NetworkDelegate * network_delegate) const139 net::URLRequestJob* ProtocolHandlerRegistry::IOThreadDelegate::MaybeCreateJob(
140 net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
142
143 ProtocolHandler handler = LookupHandler(default_handlers_,
144 request->url().scheme());
145 if (handler.IsEmpty())
146 return NULL;
147
148 GURL translated_url(handler.TranslateUrl(request->url()));
149 if (!translated_url.is_valid())
150 return NULL;
151
152 return new net::URLRequestRedirectJob(
153 request, network_delegate, translated_url,
154 net::URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT,
155 "Protocol Handler Registry");
156 }
157
158 // JobInterceptorFactory -------------------------------------------------------
159
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|.
JobInterceptorFactory(IOThreadDelegate * io_thread_delegate)164 ProtocolHandlerRegistry::JobInterceptorFactory::JobInterceptorFactory(
165 IOThreadDelegate* io_thread_delegate)
166 : io_thread_delegate_(io_thread_delegate) {
167 DCHECK(io_thread_delegate_.get());
168 DetachFromThread();
169 }
170
~JobInterceptorFactory()171 ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() {
172 }
173
Chain(scoped_ptr<net::URLRequestJobFactory> job_factory)174 void ProtocolHandlerRegistry::JobInterceptorFactory::Chain(
175 scoped_ptr<net::URLRequestJobFactory> job_factory) {
176 job_factory_ = job_factory.Pass();
177 }
178
179 net::URLRequestJob*
180 ProtocolHandlerRegistry::JobInterceptorFactory::
MaybeCreateJobWithProtocolHandler(const std::string & scheme,net::URLRequest * request,net::NetworkDelegate * network_delegate) const181 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);
188 if (job)
189 return job;
190 return job_factory_->MaybeCreateJobWithProtocolHandler(
191 scheme, request, network_delegate);
192 }
193
IsHandledProtocol(const std::string & scheme) const194 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);
199 }
200
IsHandledURL(const GURL & url) const201 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);
207 }
208
IsSafeRedirectTarget(const GURL & location) const209 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsSafeRedirectTarget(
210 const GURL& location) const {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
212 return job_factory_->IsSafeRedirectTarget(location);
213 }
214
215 // DefaultClientObserver ------------------------------------------------------
216
DefaultClientObserver(ProtocolHandlerRegistry * registry)217 ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver(
218 ProtocolHandlerRegistry* registry)
219 : worker_(NULL),
220 registry_(registry) {
221 DCHECK(registry_);
222 }
223
~DefaultClientObserver()224 ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() {
225 if (worker_)
226 worker_->ObserverDestroyed();
227
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);
232 }
233
SetDefaultWebClientUIState(ShellIntegration::DefaultWebClientUIState state)234 void ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState(
235 ShellIntegration::DefaultWebClientUIState state) {
236 if (worker_) {
237 if (ShouldRemoveHandlersNotInOS() &&
238 (state == ShellIntegration::STATE_NOT_DEFAULT)) {
239 registry_->ClearDefault(worker_->protocol());
240 }
241 } else {
242 NOTREACHED();
243 }
244 }
245
246 bool ProtocolHandlerRegistry::DefaultClientObserver::
IsInteractiveSetDefaultPermitted()247 IsInteractiveSetDefaultPermitted() {
248 return true;
249 }
250
SetWorker(ShellIntegration::DefaultProtocolClientWorker * worker)251 void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker(
252 ShellIntegration::DefaultProtocolClientWorker* worker) {
253 worker_ = worker;
254 }
255
IsOwnedByWorker()256 bool ProtocolHandlerRegistry::DefaultClientObserver::IsOwnedByWorker() {
257 return true;
258 }
259
260 // Delegate --------------------------------------------------------------------
261
~Delegate()262 ProtocolHandlerRegistry::Delegate::~Delegate() {}
263
RegisterExternalHandler(const std::string & protocol)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);
270 }
271 }
272
DeregisterExternalHandler(const std::string & protocol)273 void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
274 const std::string& protocol) {
275 }
276
IsExternalHandlerRegistered(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
280 // in ProfileIOData.
281 return ProfileIOData::IsHandledProtocol(protocol);
282 }
283
284 ShellIntegration::DefaultProtocolClientWorker*
CreateShellWorker(ShellIntegration::DefaultWebClientObserver * observer,const std::string & protocol)285 ProtocolHandlerRegistry::Delegate::CreateShellWorker(
286 ShellIntegration::DefaultWebClientObserver* observer,
287 const std::string& protocol) {
288 return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol);
289 }
290
291 ProtocolHandlerRegistry::DefaultClientObserver*
CreateShellObserver(ProtocolHandlerRegistry * registry)292 ProtocolHandlerRegistry::Delegate::CreateShellObserver(
293 ProtocolHandlerRegistry* registry) {
294 return new DefaultClientObserver(registry);
295 }
296
RegisterWithOSAsDefaultClient(const std::string & protocol,ProtocolHandlerRegistry * 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();
308 }
309
310 // ProtocolHandlerRegistry -----------------------------------------------------
311
ProtocolHandlerRegistry(Profile * profile,Delegate * delegate)312 ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile,
313 Delegate* delegate)
314 : profile_(profile),
315 delegate_(delegate),
316 enabled_(true),
317 is_loading_(false),
318 is_loaded_(false),
319 io_thread_delegate_(new IOThreadDelegate(enabled_)){
320 }
321
SilentlyHandleRegisterHandlerRequest(const ProtocolHandler & handler)322 bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest(
323 const ProtocolHandler& handler) {
324 if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol()))
325 return true;
326
327 if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler))
328 return true;
329
330 if (AttemptReplace(handler))
331 return true;
332
333 return false;
334 }
335
OnAcceptRegisterProtocolHandler(const ProtocolHandler & handler)336 void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler(
337 const ProtocolHandler& handler) {
338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
339 RegisterProtocolHandler(handler, USER);
340 SetDefault(handler);
341 Save();
342 NotifyChanged();
343 }
344
OnDenyRegisterProtocolHandler(const ProtocolHandler & handler)345 void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
346 const ProtocolHandler& handler) {
347 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
348 RegisterProtocolHandler(handler, USER);
349 Save();
350 NotifyChanged();
351 }
352
OnIgnoreRegisterProtocolHandler(const ProtocolHandler & handler)353 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
354 const ProtocolHandler& handler) {
355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
356 IgnoreProtocolHandler(handler, USER);
357 Save();
358 NotifyChanged();
359 }
360
AttemptReplace(const ProtocolHandler & handler)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())
367 return false;
368 for (ProtocolHandlerList::iterator p = to_replace.begin();
369 p != to_replace.end(); ++p) {
370 RemoveHandler(*p);
371 }
372 if (make_new_handler_default) {
373 OnAcceptRegisterProtocolHandler(handler);
374 } else {
375 InsertHandler(handler);
376 NotifyChanged();
377 }
378 return true;
379 }
380
381 ProtocolHandlerRegistry::ProtocolHandlerList
GetReplacedHandlers(const ProtocolHandler & handler) const382 ProtocolHandlerRegistry::GetReplacedHandlers(
383 const ProtocolHandler& handler) const {
384 ProtocolHandlerList replaced_handlers;
385 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
386 if (!handlers)
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);
392 }
393 }
394 return replaced_handlers;
395 }
396
ClearDefault(const std::string & scheme)397 void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) {
398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
399
400 default_handlers_.erase(scheme);
401 BrowserThread::PostTask(
402 BrowserThread::IO,
403 FROM_HERE,
404 base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_, scheme));
405 Save();
406 NotifyChanged();
407 }
408
IsDefault(const ProtocolHandler & handler) const409 bool ProtocolHandlerRegistry::IsDefault(
410 const ProtocolHandler& handler) const {
411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
412 return GetHandlerFor(handler.protocol()) == handler;
413 }
414
InstallDefaultsForChromeOS()415 void ProtocolHandlerRegistry::InstallDefaultsForChromeOS() {
416 #if defined(OS_CHROMEOS)
417 // Only chromeos has default protocol handlers at this point.
418 AddPredefinedHandler(
419 ProtocolHandler::CreateProtocolHandler(
420 "mailto",
421 GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_MAILTO_HANDLER_URL))));
422 AddPredefinedHandler(
423 ProtocolHandler::CreateProtocolHandler(
424 "webcal",
425 GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL))));
426 #else
427 NOTREACHED(); // this method should only ever be called in chromeos.
428 #endif
429 }
430
InitProtocolSettings()431 void ProtocolHandlerRegistry::InitProtocolSettings() {
432 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
433
434 // Any further default additions to the table will get rejected from now on.
435 is_loaded_ = true;
436 is_loading_ = true;
437
438 PrefService* prefs = profile_->GetPrefs();
439 if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) {
440 if (prefs->GetBoolean(prefs::kCustomHandlersEnabled)) {
441 Enable();
442 } else {
443 Disable();
444 }
445 }
446
447 RegisterProtocolHandlersFromPref(prefs::kPolicyRegisteredProtocolHandlers,
448 POLICY);
449 RegisterProtocolHandlersFromPref(prefs::kRegisteredProtocolHandlers, USER);
450 IgnoreProtocolHandlersFromPref(prefs::kPolicyIgnoredProtocolHandlers, POLICY);
451 IgnoreProtocolHandlersFromPref(prefs::kIgnoredProtocolHandlers, USER);
452
453 is_loading_ = false;
454
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();
467 }
468 }
469 }
470
GetHandlerIndex(const std::string & scheme) const471 int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const {
472 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
473 const ProtocolHandler& handler = GetHandlerFor(scheme);
474 if (handler.IsEmpty())
475 return -1;
476 const ProtocolHandlerList* handlers = GetHandlerList(scheme);
477 if (!handlers)
478 return -1;
479
480 ProtocolHandlerList::const_iterator p;
481 int i;
482 for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) {
483 if (*p == handler)
484 return i;
485 }
486 return -1;
487 }
488
489 ProtocolHandlerRegistry::ProtocolHandlerList
GetHandlersFor(const std::string & scheme) const490 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();
496 }
497 return p->second;
498 }
499
500 ProtocolHandlerRegistry::ProtocolHandlerList
GetIgnoredHandlers()501 ProtocolHandlerRegistry::GetIgnoredHandlers() {
502 return ignored_protocol_handlers_;
503 }
504
GetRegisteredProtocols(std::vector<std::string> * output) const505 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);
512 }
513 }
514
CanSchemeBeOverridden(const std::string & scheme) const515 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())
521 return true;
522 // Don't override a scheme if it already has an external handler.
523 return !delegate_->IsExternalHandlerRegistered(scheme);
524 }
525
IsRegistered(const ProtocolHandler & handler) const526 bool ProtocolHandlerRegistry::IsRegistered(
527 const ProtocolHandler& handler) const {
528 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
529 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
530 if (!handlers) {
531 return false;
532 }
533 return std::find(handlers->begin(), handlers->end(), handler) !=
534 handlers->end();
535 }
536
IsIgnored(const ProtocolHandler & handler) const537 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) {
542 if (*i == handler) {
543 return true;
544 }
545 }
546 return false;
547 }
548
HasRegisteredEquivalent(const ProtocolHandler & handler) const549 bool ProtocolHandlerRegistry::HasRegisteredEquivalent(
550 const ProtocolHandler& handler) const {
551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
552 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
553 if (!handlers) {
554 return false;
555 }
556 ProtocolHandlerList::const_iterator i;
557 for (i = handlers->begin(); i != handlers->end(); ++i) {
558 if (handler.IsEquivalent(*i)) {
559 return true;
560 }
561 }
562 return false;
563 }
564
HasIgnoredEquivalent(const ProtocolHandler & handler) const565 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)) {
572 return true;
573 }
574 }
575 return false;
576 }
577
RemoveIgnoredHandler(const ProtocolHandler & handler)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_);
585 Save();
586 if (!HandlerExists(handler, policy_ignored_protocol_handlers_)) {
587 EraseHandler(handler, &ignored_protocol_handlers_);
588 should_notify = true;
589 }
590 }
591 if (should_notify)
592 NotifyChanged();
593 }
594
IsHandledProtocol(const std::string & scheme) const595 bool ProtocolHandlerRegistry::IsHandledProtocol(
596 const std::string& scheme) const {
597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
598 return enabled_ && !GetHandlerFor(scheme).IsEmpty();
599 }
600
RemoveHandler(const ProtocolHandler & handler)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_);
612 }
613 }
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]));
620 } else {
621 BrowserThread::PostTask(
622 BrowserThread::IO, FROM_HERE,
623 base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_,
624 q->second.protocol()));
625
626 default_handlers_.erase(q);
627 }
628 }
629
630 if (erase_success && !IsHandledProtocol(handler.protocol())) {
631 delegate_->DeregisterExternalHandler(handler.protocol());
632 }
633 Save();
634 if (erase_success)
635 NotifyChanged();
636 }
637
RemoveDefaultHandler(const std::string & scheme)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);
643 }
644
GetHandlerFor(const std::string & scheme) const645 const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor(
646 const std::string& scheme) const {
647 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
648 return LookupHandler(default_handlers_, scheme);
649 }
650
Enable()651 void ProtocolHandlerRegistry::Enable() {
652 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
653 if (enabled_) {
654 return;
655 }
656 enabled_ = true;
657 BrowserThread::PostTask(
658 BrowserThread::IO,
659 FROM_HERE,
660 base::Bind(&IOThreadDelegate::Enable, io_thread_delegate_));
661
662 ProtocolHandlerMap::const_iterator p;
663 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
664 delegate_->RegisterExternalHandler(p->first);
665 }
666 Save();
667 NotifyChanged();
668 }
669
Disable()670 void ProtocolHandlerRegistry::Disable() {
671 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
672 if (!enabled_) {
673 return;
674 }
675 enabled_ = false;
676 BrowserThread::PostTask(
677 BrowserThread::IO,
678 FROM_HERE,
679 base::Bind(&IOThreadDelegate::Disable, io_thread_delegate_));
680
681 ProtocolHandlerMap::const_iterator p;
682 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
683 delegate_->DeregisterExternalHandler(p->first);
684 }
685 Save();
686 NotifyChanged();
687 }
688
Shutdown()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();
699 }
700 }
701
702 // static
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)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,
715 true,
716 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
717 }
718
~ProtocolHandlerRegistry()719 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
720 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
721 DCHECK(default_client_observers_.empty());
722 }
723
PromoteHandler(const ProtocolHandler & handler)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);
732 }
733
Save()734 void ProtocolHandlerRegistry::Save() {
735 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
736 if (is_loading_) {
737 return;
738 }
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);
748 }
749
750 const ProtocolHandlerRegistry::ProtocolHandlerList*
GetHandlerList(const std::string & scheme) const751 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()) {
756 return NULL;
757 }
758 return &p->second;
759 }
760
SetDefault(const ProtocolHandler & handler)761 void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) {
762 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
763 ProtocolHandlerMap::const_iterator p = default_handlers_.find(
764 handler.protocol());
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(
773 BrowserThread::IO,
774 FROM_HERE,
775 base::Bind(&IOThreadDelegate::SetDefault, io_thread_delegate_, handler));
776 }
777
InsertHandler(const ProtocolHandler & handler)778 void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) {
779 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
780 ProtocolHandlerMultiMap::iterator p =
781 protocol_handlers_.find(handler.protocol());
782
783 if (p != protocol_handlers_.end()) {
784 p->second.push_back(handler);
785 return;
786 }
787
788 ProtocolHandlerList new_list;
789 new_list.push_back(handler);
790 protocol_handlers_[handler.protocol()] = new_list;
791 }
792
EncodeRegisteredHandlers()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();
798 ++i) {
799 for (ProtocolHandlerList::iterator j = i->second.begin();
800 j != i->second.end(); ++j) {
801 base::DictionaryValue* encoded = j->Encode();
802 if (IsDefault(*j)) {
803 encoded->Set("default", base::Value::CreateBooleanValue(true));
804 }
805 protocol_handlers->Append(encoded);
806 }
807 }
808 return protocol_handlers;
809 }
810
EncodeIgnoredHandlers()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();
817 ++i) {
818 handlers->Append(i->Encode());
819 }
820 return handlers;
821 }
822
NotifyChanged()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());
829 }
830
RegisterProtocolHandler(const ProtocolHandler & handler,const HandlerSource source)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)) {
843 return;
844 }
845 if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol()))
846 delegate_->RegisterExternalHandler(handler.protocol());
847 InsertHandler(handler);
848 }
849
850 std::vector<const base::DictionaryValue*>
GetHandlersFromPref(const char * pref_name) const851 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)) {
856 return result;
857 }
858
859 const base::ListValue* handlers = prefs->GetList(pref_name);
860 if (handlers) {
861 for (size_t i = 0; i < handlers->GetSize(); ++i) {
862 const base::DictionaryValue* dict;
863 if (!handlers->GetDictionary(i, &dict))
864 continue;
865 if (ProtocolHandler::IsValidDict(dict)) {
866 result.push_back(dict);
867 }
868 }
869 }
870 return result;
871 }
872
RegisterProtocolHandlersFromPref(const char * pref_name,const HandlerSource source)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();
881 ++p) {
882 ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p);
883 RegisterProtocolHandler(handler, source);
884 bool is_default = false;
885 if ((*p)->GetBoolean("default", &is_default) && is_default) {
886 SetDefault(handler);
887 }
888 }
889 }
890
IgnoreProtocolHandler(const ProtocolHandler & handler,const HandlerSource source)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_))
901 return;
902 ignored_protocol_handlers_.push_back(handler);
903 }
904
IgnoreProtocolHandlersFromPref(const char * pref_name,const HandlerSource source)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();
913 ++p) {
914 IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p), source);
915 }
916 }
917
HandlerExists(const ProtocolHandler & handler,ProtocolHandlerMultiMap * map)918 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
919 ProtocolHandlerMultiMap* map) {
920 return HandlerExists(handler, (*map)[handler.protocol()]);
921 }
922
HandlerExists(const ProtocolHandler & handler,const ProtocolHandlerList & list)923 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
924 const ProtocolHandlerList& list) {
925 return std::find(list.begin(), list.end(), handler) != list.end();
926 }
927
EraseHandler(const ProtocolHandler & handler,ProtocolHandlerMultiMap * map)928 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
929 ProtocolHandlerMultiMap* map) {
930 EraseHandler(handler, &(*map)[handler.protocol()]);
931 }
932
EraseHandler(const ProtocolHandler & handler,ProtocolHandlerList * list)933 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
934 ProtocolHandlerList* list) {
935 list->erase(std::find(list->begin(), list->end(), handler));
936 }
937
AddPredefinedHandler(const ProtocolHandler & handler)938 void ProtocolHandlerRegistry::AddPredefinedHandler(
939 const ProtocolHandler& handler) {
940 DCHECK(!is_loaded_); // Must be called prior InitProtocolSettings.
941 RegisterProtocolHandler(handler, USER);
942 SetDefault(handler);
943 }
944
945 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
CreateJobInterceptorFactory()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()));
953 }
954