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/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"
25
26using content::BrowserThread;
27using content::ChildProcessSecurityPolicy;
28
29namespace {
30
31const ProtocolHandler& LookupHandler(
32    const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map,
33    const std::string& scheme) {
34  ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p =
35      handler_map.find(scheme);
36
37  if (p != handler_map.end())
38    return p->second;
39
40  return ProtocolHandler::EmptyProtocolHandler();
41}
42
43// If true default protocol handlers will be removed if the OS level
44// registration for a protocol is no longer Chrome.
45bool ShouldRemoveHandlersNotInOS() {
46#if defined(OS_LINUX)
47  // We don't do this on Linux as the OS registration there is not reliable,
48  // and Chrome OS doesn't have any notion of OS registration.
49  // TODO(benwells): When Linux support is more reliable remove this
50  // difference (http://crbug.com/88255).
51  return false;
52#else
53  return ShellIntegration::CanSetAsDefaultProtocolClient() !=
54      ShellIntegration::SET_DEFAULT_NOT_ALLOWED;
55#endif
56}
57
58}  // namespace
59
60// IOThreadDelegate ------------------------------------------------------------
61
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.
65class ProtocolHandlerRegistry::IOThreadDelegate
66    : public base::RefCountedThreadSafe<
67          ProtocolHandlerRegistry::IOThreadDelegate> {
68 public:
69
70  // Creates a new instance. If |enabled| is true the registry is considered
71  // enabled on the IO thread.
72  explicit IOThreadDelegate(bool enabled);
73
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;
77
78  // Clears the default for the provided protocol.
79  // Should be called only from the IO thread.
80  void ClearDefault(const std::string& scheme);
81
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);
85
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;
90
91  // Indicate that the registry has been enabled in the IO thread's
92  // copy of the data.
93  void Enable() { enabled_ = true; }
94
95  // Indicate that the registry has been disabled in the IO thread's copy of
96  // the data.
97  void Disable() { enabled_ = false; }
98
99 private:
100  friend class base::RefCountedThreadSafe<IOThreadDelegate>;
101  virtual ~IOThreadDelegate();
102
103  // Copy of protocol handlers use only on the IO thread.
104  ProtocolHandlerRegistry::ProtocolHandlerMap default_handlers_;
105
106  // Is the registry enabled on the IO thread.
107  bool enabled_;
108
109  DISALLOW_COPY_AND_ASSIGN(IOThreadDelegate);
110};
111
112ProtocolHandlerRegistry::IOThreadDelegate::IOThreadDelegate(bool)
113    : enabled_(true) {}
114ProtocolHandlerRegistry::IOThreadDelegate::~IOThreadDelegate() {}
115
116bool ProtocolHandlerRegistry::IOThreadDelegate::IsHandledProtocol(
117    const std::string& scheme) const {
118  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
119  return enabled_ && !LookupHandler(default_handlers_, scheme).IsEmpty();
120}
121
122void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault(
123    const std::string& scheme) {
124  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
125  default_handlers_.erase(scheme);
126}
127
128void ProtocolHandlerRegistry::IOThreadDelegate::SetDefault(
129    const ProtocolHandler& handler) {
130  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
131  ClearDefault(handler.protocol());
132  default_handlers_.insert(std::make_pair(handler.protocol(), handler));
133}
134
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|.
138net::URLRequestJob* ProtocolHandlerRegistry::IOThreadDelegate::MaybeCreateJob(
139    net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
140  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
141
142  ProtocolHandler handler = LookupHandler(default_handlers_,
143                                          request->url().scheme());
144  if (handler.IsEmpty())
145    return NULL;
146
147  GURL translated_url(handler.TranslateUrl(request->url()));
148  if (!translated_url.is_valid())
149    return NULL;
150
151  return new net::URLRequestRedirectJob(
152      request, network_delegate, translated_url,
153      net::URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT,
154      "Protocol Handler Registry");
155}
156
157// JobInterceptorFactory -------------------------------------------------------
158
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|.
163ProtocolHandlerRegistry::JobInterceptorFactory::JobInterceptorFactory(
164    IOThreadDelegate* io_thread_delegate)
165    : io_thread_delegate_(io_thread_delegate) {
166  DCHECK(io_thread_delegate_.get());
167  DetachFromThread();
168}
169
170ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() {
171}
172
173void ProtocolHandlerRegistry::JobInterceptorFactory::Chain(
174    scoped_ptr<net::URLRequestJobFactory> job_factory) {
175  job_factory_ = job_factory.Pass();
176}
177
178net::URLRequestJob*
179ProtocolHandlerRegistry::JobInterceptorFactory::
180MaybeCreateJobWithProtocolHandler(
181    const std::string& scheme,
182    net::URLRequest* request,
183    net::NetworkDelegate* network_delegate) const {
184  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
185  net::URLRequestJob* job = io_thread_delegate_->MaybeCreateJob(
186      request, network_delegate);
187  if (job)
188    return job;
189  return job_factory_->MaybeCreateJobWithProtocolHandler(
190      scheme, request, network_delegate);
191}
192
193bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledProtocol(
194    const std::string& scheme) const {
195  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
196  return io_thread_delegate_->IsHandledProtocol(scheme) ||
197      job_factory_->IsHandledProtocol(scheme);
198}
199
200bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledURL(
201    const GURL& url) const {
202  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
203  return (url.is_valid() &&
204      io_thread_delegate_->IsHandledProtocol(url.scheme())) ||
205      job_factory_->IsHandledURL(url);
206}
207
208bool ProtocolHandlerRegistry::JobInterceptorFactory::IsSafeRedirectTarget(
209    const GURL& location) const {
210  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
211  return job_factory_->IsSafeRedirectTarget(location);
212}
213
214// DefaultClientObserver ------------------------------------------------------
215
216ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver(
217    ProtocolHandlerRegistry* registry)
218    : worker_(NULL),
219      registry_(registry) {
220  DCHECK(registry_);
221}
222
223ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() {
224  if (worker_)
225    worker_->ObserverDestroyed();
226
227  DefaultClientObserverList::iterator iter = std::find(
228      registry_->default_client_observers_.begin(),
229      registry_->default_client_observers_.end(), this);
230  registry_->default_client_observers_.erase(iter);
231}
232
233void ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState(
234    ShellIntegration::DefaultWebClientUIState state) {
235  if (worker_) {
236    if (ShouldRemoveHandlersNotInOS() &&
237        (state == ShellIntegration::STATE_NOT_DEFAULT)) {
238      registry_->ClearDefault(worker_->protocol());
239    }
240  } else {
241    NOTREACHED();
242  }
243}
244
245bool ProtocolHandlerRegistry::DefaultClientObserver::
246    IsInteractiveSetDefaultPermitted() {
247  return true;
248}
249
250void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker(
251    ShellIntegration::DefaultProtocolClientWorker* worker) {
252  worker_ = worker;
253}
254
255bool ProtocolHandlerRegistry::DefaultClientObserver::IsOwnedByWorker() {
256  return true;
257}
258
259// Delegate --------------------------------------------------------------------
260
261ProtocolHandlerRegistry::Delegate::~Delegate() {}
262
263void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler(
264    const std::string& protocol) {
265  ChildProcessSecurityPolicy* policy =
266    ChildProcessSecurityPolicy::GetInstance();
267  if (!policy->IsWebSafeScheme(protocol)) {
268    policy->RegisterWebSafeScheme(protocol);
269  }
270}
271
272void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
273    const std::string& protocol) {
274}
275
276bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered(
277    const std::string& protocol) {
278  // NOTE(koz): This function is safe to call from any thread, despite living
279  // in ProfileIOData.
280  return ProfileIOData::IsHandledProtocol(protocol);
281}
282
283ShellIntegration::DefaultProtocolClientWorker*
284ProtocolHandlerRegistry::Delegate::CreateShellWorker(
285    ShellIntegration::DefaultWebClientObserver* observer,
286    const std::string& protocol) {
287  return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol);
288}
289
290ProtocolHandlerRegistry::DefaultClientObserver*
291ProtocolHandlerRegistry::Delegate::CreateShellObserver(
292    ProtocolHandlerRegistry* registry) {
293  return new DefaultClientObserver(registry);
294}
295
296void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient(
297    const std::string& protocol, ProtocolHandlerRegistry* registry) {
298  DefaultClientObserver* observer = CreateShellObserver(registry);
299  // The worker pointer is reference counted. While it is running the
300  // message loops of the FILE and UI thread will hold references to it
301  // and it will be automatically freed once all its tasks have finished.
302  scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker;
303  worker = CreateShellWorker(observer, protocol);
304  observer->SetWorker(worker.get());
305  registry->default_client_observers_.push_back(observer);
306  worker->StartSetAsDefault();
307}
308
309// ProtocolHandlerRegistry -----------------------------------------------------
310
311ProtocolHandlerRegistry::ProtocolHandlerRegistry(
312    content::BrowserContext* context, Delegate* delegate)
313    : context_(context),
314      delegate_(delegate),
315      enabled_(true),
316      is_loading_(false),
317      is_loaded_(false),
318      io_thread_delegate_(new IOThreadDelegate(enabled_)){
319}
320
321bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest(
322    const ProtocolHandler& handler) {
323  if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol()))
324    return true;
325
326  if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler))
327    return true;
328
329  if (AttemptReplace(handler))
330    return true;
331
332  return false;
333}
334
335void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler(
336    const ProtocolHandler& handler) {
337  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
338  RegisterProtocolHandler(handler, USER);
339  SetDefault(handler);
340  Save();
341  NotifyChanged();
342}
343
344void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
345    const ProtocolHandler& handler) {
346  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
347  RegisterProtocolHandler(handler, USER);
348  Save();
349  NotifyChanged();
350}
351
352void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
353    const ProtocolHandler& handler) {
354  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
355  IgnoreProtocolHandler(handler, USER);
356  Save();
357  NotifyChanged();
358}
359
360bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) {
361  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
362  ProtocolHandler old_default = GetHandlerFor(handler.protocol());
363  bool make_new_handler_default = handler.IsSameOrigin(old_default);
364  ProtocolHandlerList to_replace(GetReplacedHandlers(handler));
365  if (to_replace.empty())
366    return false;
367  for (ProtocolHandlerList::iterator p = to_replace.begin();
368       p != to_replace.end(); ++p) {
369    RemoveHandler(*p);
370  }
371  if (make_new_handler_default) {
372    OnAcceptRegisterProtocolHandler(handler);
373  } else {
374    InsertHandler(handler);
375    NotifyChanged();
376  }
377  return true;
378}
379
380ProtocolHandlerRegistry::ProtocolHandlerList
381ProtocolHandlerRegistry::GetReplacedHandlers(
382    const ProtocolHandler& handler) const {
383  ProtocolHandlerList replaced_handlers;
384  const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
385  if (!handlers)
386    return replaced_handlers;
387  for (ProtocolHandlerList::const_iterator p = handlers->begin();
388       p != handlers->end(); p++) {
389    if (handler.IsSameOrigin(*p)) {
390      replaced_handlers.push_back(*p);
391    }
392  }
393  return replaced_handlers;
394}
395
396void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) {
397  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
398
399  default_handlers_.erase(scheme);
400  BrowserThread::PostTask(
401      BrowserThread::IO,
402      FROM_HERE,
403      base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_, scheme));
404  Save();
405  NotifyChanged();
406}
407
408bool ProtocolHandlerRegistry::IsDefault(
409    const ProtocolHandler& handler) const {
410  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
411  return GetHandlerFor(handler.protocol()) == handler;
412}
413
414void ProtocolHandlerRegistry::InstallDefaultsForChromeOS() {
415#if defined(OS_CHROMEOS)
416  // Only chromeos has default protocol handlers at this point.
417  AddPredefinedHandler(
418      ProtocolHandler::CreateProtocolHandler(
419          "mailto",
420          GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_MAILTO_HANDLER_URL))));
421  AddPredefinedHandler(
422      ProtocolHandler::CreateProtocolHandler(
423          "webcal",
424          GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL))));
425#else
426  NOTREACHED();  // this method should only ever be called in chromeos.
427#endif
428}
429
430void ProtocolHandlerRegistry::InitProtocolSettings() {
431  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
432
433  // Any further default additions to the table will get rejected from now on.
434  is_loaded_ = true;
435  is_loading_ = true;
436
437  PrefService* prefs = user_prefs::UserPrefs::Get(context_);
438  if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) {
439    if (prefs->GetBoolean(prefs::kCustomHandlersEnabled)) {
440      Enable();
441    } else {
442      Disable();
443    }
444  }
445
446  RegisterProtocolHandlersFromPref(prefs::kPolicyRegisteredProtocolHandlers,
447                                   POLICY);
448  RegisterProtocolHandlersFromPref(prefs::kRegisteredProtocolHandlers, USER);
449  IgnoreProtocolHandlersFromPref(prefs::kPolicyIgnoredProtocolHandlers, POLICY);
450  IgnoreProtocolHandlersFromPref(prefs::kIgnoredProtocolHandlers, USER);
451
452  is_loading_ = false;
453
454  // For each default protocol handler, check that we are still registered
455  // with the OS as the default application.
456  if (ShouldRemoveHandlersNotInOS()) {
457    for (ProtocolHandlerMap::const_iterator p = default_handlers_.begin();
458         p != default_handlers_.end(); ++p) {
459      ProtocolHandler handler = p->second;
460      DefaultClientObserver* observer = delegate_->CreateShellObserver(this);
461      scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker;
462      worker = delegate_->CreateShellWorker(observer, handler.protocol());
463      observer->SetWorker(worker.get());
464      default_client_observers_.push_back(observer);
465      worker->StartCheckIsDefault();
466    }
467  }
468}
469
470int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const {
471  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
472  const ProtocolHandler& handler = GetHandlerFor(scheme);
473  if (handler.IsEmpty())
474    return -1;
475  const ProtocolHandlerList* handlers = GetHandlerList(scheme);
476  if (!handlers)
477    return -1;
478
479  ProtocolHandlerList::const_iterator p;
480  int i;
481  for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) {
482    if (*p == handler)
483      return i;
484  }
485  return -1;
486}
487
488ProtocolHandlerRegistry::ProtocolHandlerList
489ProtocolHandlerRegistry::GetHandlersFor(
490    const std::string& scheme) const {
491  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
492  ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
493  if (p == protocol_handlers_.end()) {
494    return ProtocolHandlerList();
495  }
496  return p->second;
497}
498
499ProtocolHandlerRegistry::ProtocolHandlerList
500ProtocolHandlerRegistry::GetIgnoredHandlers() {
501  return ignored_protocol_handlers_;
502}
503
504void ProtocolHandlerRegistry::GetRegisteredProtocols(
505    std::vector<std::string>* output) const {
506  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
507  ProtocolHandlerMultiMap::const_iterator p;
508  for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) {
509    if (!p->second.empty())
510      output->push_back(p->first);
511  }
512}
513
514bool ProtocolHandlerRegistry::CanSchemeBeOverridden(
515    const std::string& scheme) const {
516  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
517  const ProtocolHandlerList* handlers = GetHandlerList(scheme);
518  // If we already have a handler for this scheme, we can add more.
519  if (handlers != NULL && !handlers->empty())
520    return true;
521  // Don't override a scheme if it already has an external handler.
522  return !delegate_->IsExternalHandlerRegistered(scheme);
523}
524
525bool ProtocolHandlerRegistry::IsRegistered(
526    const ProtocolHandler& handler) const {
527  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
528  const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
529  if (!handlers) {
530    return false;
531  }
532  return std::find(handlers->begin(), handlers->end(), handler) !=
533      handlers->end();
534}
535
536bool ProtocolHandlerRegistry::IsRegisteredByUser(
537    const ProtocolHandler& handler) {
538  return HandlerExists(handler, &user_protocol_handlers_);
539}
540
541bool ProtocolHandlerRegistry::HasPolicyRegisteredHandler(
542    const std::string& scheme) {
543  return (policy_protocol_handlers_.find(scheme) !=
544          policy_protocol_handlers_.end());
545}
546
547bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const {
548  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
549  ProtocolHandlerList::const_iterator i;
550  for (i = ignored_protocol_handlers_.begin();
551       i != ignored_protocol_handlers_.end(); ++i) {
552    if (*i == handler) {
553      return true;
554    }
555  }
556  return false;
557}
558
559bool ProtocolHandlerRegistry::HasRegisteredEquivalent(
560    const ProtocolHandler& handler) const {
561  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
562  const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
563  if (!handlers) {
564    return false;
565  }
566  ProtocolHandlerList::const_iterator i;
567  for (i = handlers->begin(); i != handlers->end(); ++i) {
568    if (handler.IsEquivalent(*i)) {
569      return true;
570    }
571  }
572  return false;
573}
574
575bool ProtocolHandlerRegistry::HasIgnoredEquivalent(
576    const ProtocolHandler& handler) const {
577  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
578  ProtocolHandlerList::const_iterator i;
579  for (i = ignored_protocol_handlers_.begin();
580       i != ignored_protocol_handlers_.end(); ++i) {
581    if (handler.IsEquivalent(*i)) {
582      return true;
583    }
584  }
585  return false;
586}
587
588void ProtocolHandlerRegistry::RemoveIgnoredHandler(
589    const ProtocolHandler& handler) {
590  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
591  bool should_notify = false;
592  if (HandlerExists(handler, ignored_protocol_handlers_) &&
593      HandlerExists(handler, user_ignored_protocol_handlers_)) {
594    EraseHandler(handler, &user_ignored_protocol_handlers_);
595    Save();
596    if (!HandlerExists(handler, policy_ignored_protocol_handlers_)) {
597      EraseHandler(handler, &ignored_protocol_handlers_);
598      should_notify = true;
599    }
600  }
601  if (should_notify)
602    NotifyChanged();
603}
604
605bool ProtocolHandlerRegistry::IsHandledProtocol(
606    const std::string& scheme) const {
607  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
608  return enabled_ && !GetHandlerFor(scheme).IsEmpty();
609}
610
611void ProtocolHandlerRegistry::RemoveHandler(
612    const ProtocolHandler& handler) {
613  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
614  ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()];
615  bool erase_success = false;
616  if (HandlerExists(handler, handlers) &&
617      HandlerExists(handler, &user_protocol_handlers_)) {
618    EraseHandler(handler, &user_protocol_handlers_);
619    erase_success = true;
620    if (!HandlerExists(handler, &policy_protocol_handlers_))
621      EraseHandler(handler, &protocol_handlers_);
622  }
623  ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol());
624  if (erase_success && q != default_handlers_.end() && q->second == handler) {
625    // Make the new top handler in the list the default.
626    if (!handlers.empty()) {
627      // NOTE We pass a copy because SetDefault() modifies handlers.
628      SetDefault(ProtocolHandler(handlers[0]));
629    } else {
630      BrowserThread::PostTask(
631          BrowserThread::IO, FROM_HERE,
632          base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_,
633                     q->second.protocol()));
634
635      default_handlers_.erase(q);
636    }
637  }
638
639  if (erase_success && !IsHandledProtocol(handler.protocol())) {
640    delegate_->DeregisterExternalHandler(handler.protocol());
641  }
642  Save();
643  if (erase_success)
644    NotifyChanged();
645}
646
647void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) {
648  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
649  ProtocolHandler current_default = GetHandlerFor(scheme);
650  if (!current_default.IsEmpty())
651    RemoveHandler(current_default);
652}
653
654const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor(
655    const std::string& scheme) const {
656  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
657  return LookupHandler(default_handlers_, scheme);
658}
659
660void ProtocolHandlerRegistry::Enable() {
661  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
662  if (enabled_) {
663    return;
664  }
665  enabled_ = true;
666  BrowserThread::PostTask(
667      BrowserThread::IO,
668      FROM_HERE,
669      base::Bind(&IOThreadDelegate::Enable, io_thread_delegate_));
670
671  ProtocolHandlerMap::const_iterator p;
672  for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
673    delegate_->RegisterExternalHandler(p->first);
674  }
675  Save();
676  NotifyChanged();
677}
678
679void ProtocolHandlerRegistry::Disable() {
680  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
681  if (!enabled_) {
682    return;
683  }
684  enabled_ = false;
685  BrowserThread::PostTask(
686      BrowserThread::IO,
687      FROM_HERE,
688      base::Bind(&IOThreadDelegate::Disable, io_thread_delegate_));
689
690  ProtocolHandlerMap::const_iterator p;
691  for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
692    delegate_->DeregisterExternalHandler(p->first);
693  }
694  Save();
695  NotifyChanged();
696}
697
698void ProtocolHandlerRegistry::Shutdown() {
699  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
700  delegate_.reset(NULL);
701  // We free these now in case there are any outstanding workers running. If
702  // we didn't free them they could respond to workers and try to update the
703  // protocol handler registry after it was deleted.
704  // Observers remove themselves from this list when they are deleted; so
705  // we delete the last item until none are left in the list.
706  while (!default_client_observers_.empty()) {
707    delete default_client_observers_.back();
708  }
709}
710
711// static
712void ProtocolHandlerRegistry::RegisterProfilePrefs(
713    user_prefs::PrefRegistrySyncable* registry) {
714  registry->RegisterListPref(prefs::kRegisteredProtocolHandlers,
715                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
716  registry->RegisterListPref(prefs::kIgnoredProtocolHandlers,
717                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
718  registry->RegisterListPref(prefs::kPolicyRegisteredProtocolHandlers,
719                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
720  registry->RegisterListPref(prefs::kPolicyIgnoredProtocolHandlers,
721                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
722  registry->RegisterBooleanPref(
723      prefs::kCustomHandlersEnabled,
724      true,
725      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
726}
727
728ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
729  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
730  DCHECK(default_client_observers_.empty());
731}
732
733void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) {
734  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
735  DCHECK(IsRegistered(handler));
736  ProtocolHandlerMultiMap::iterator p =
737      protocol_handlers_.find(handler.protocol());
738  ProtocolHandlerList& list = p->second;
739  list.erase(std::find(list.begin(), list.end(), handler));
740  list.insert(list.begin(), handler);
741}
742
743void ProtocolHandlerRegistry::Save() {
744  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
745  if (is_loading_) {
746    return;
747  }
748  scoped_ptr<base::Value> registered_protocol_handlers(
749      EncodeRegisteredHandlers());
750  scoped_ptr<base::Value> ignored_protocol_handlers(EncodeIgnoredHandlers());
751  PrefService* prefs = user_prefs::UserPrefs::Get(context_);
752
753  prefs->Set(prefs::kRegisteredProtocolHandlers,
754      *registered_protocol_handlers);
755  prefs->Set(prefs::kIgnoredProtocolHandlers,
756      *ignored_protocol_handlers);
757  prefs->SetBoolean(prefs::kCustomHandlersEnabled, enabled_);
758}
759
760const ProtocolHandlerRegistry::ProtocolHandlerList*
761ProtocolHandlerRegistry::GetHandlerList(
762    const std::string& scheme) const {
763  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
764  ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
765  if (p == protocol_handlers_.end()) {
766    return NULL;
767  }
768  return &p->second;
769}
770
771void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) {
772  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
773  ProtocolHandlerMap::const_iterator p = default_handlers_.find(
774      handler.protocol());
775  // If we're not loading, and we are setting a default for a new protocol,
776  // register with the OS.
777  if (!is_loading_ && p == default_handlers_.end())
778      delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this);
779  default_handlers_.erase(handler.protocol());
780  default_handlers_.insert(std::make_pair(handler.protocol(), handler));
781  PromoteHandler(handler);
782  BrowserThread::PostTask(
783      BrowserThread::IO,
784      FROM_HERE,
785      base::Bind(&IOThreadDelegate::SetDefault, io_thread_delegate_, handler));
786}
787
788void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) {
789  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
790  ProtocolHandlerMultiMap::iterator p =
791      protocol_handlers_.find(handler.protocol());
792
793  if (p != protocol_handlers_.end()) {
794    p->second.push_back(handler);
795    return;
796  }
797
798  ProtocolHandlerList new_list;
799  new_list.push_back(handler);
800  protocol_handlers_[handler.protocol()] = new_list;
801}
802
803base::Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() {
804  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
805  base::ListValue* protocol_handlers = new base::ListValue();
806  for (ProtocolHandlerMultiMap::iterator i = user_protocol_handlers_.begin();
807       i != user_protocol_handlers_.end();
808       ++i) {
809    for (ProtocolHandlerList::iterator j = i->second.begin();
810         j != i->second.end(); ++j) {
811      base::DictionaryValue* encoded = j->Encode();
812      if (IsDefault(*j)) {
813        encoded->Set("default", new base::FundamentalValue(true));
814      }
815      protocol_handlers->Append(encoded);
816    }
817  }
818  return protocol_handlers;
819}
820
821base::Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
822  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
823  base::ListValue* handlers = new base::ListValue();
824  for (ProtocolHandlerList::iterator i =
825           user_ignored_protocol_handlers_.begin();
826       i != user_ignored_protocol_handlers_.end();
827       ++i) {
828    handlers->Append(i->Encode());
829  }
830  return handlers;
831}
832
833void ProtocolHandlerRegistry::NotifyChanged() {
834  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
835  content::NotificationService::current()->Notify(
836      chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
837      content::Source<content::BrowserContext>(context_),
838      content::NotificationService::NoDetails());
839}
840
841void ProtocolHandlerRegistry::RegisterProtocolHandler(
842    const ProtocolHandler& handler,
843    const HandlerSource source) {
844  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
845  DCHECK(CanSchemeBeOverridden(handler.protocol()));
846  DCHECK(!handler.IsEmpty());
847  ProtocolHandlerMultiMap& map =
848      (source == POLICY) ? policy_protocol_handlers_ : user_protocol_handlers_;
849  ProtocolHandlerList& list = map[handler.protocol()];
850  if (!HandlerExists(handler, list))
851    list.push_back(handler);
852  if (IsRegistered(handler)) {
853    return;
854  }
855  if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol()))
856    delegate_->RegisterExternalHandler(handler.protocol());
857  InsertHandler(handler);
858}
859
860std::vector<const base::DictionaryValue*>
861ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const {
862  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
863  std::vector<const base::DictionaryValue*> result;
864  PrefService* prefs = user_prefs::UserPrefs::Get(context_);
865  if (!prefs->HasPrefPath(pref_name)) {
866    return result;
867  }
868
869  const base::ListValue* handlers = prefs->GetList(pref_name);
870  if (handlers) {
871    for (size_t i = 0; i < handlers->GetSize(); ++i) {
872      const base::DictionaryValue* dict;
873      if (!handlers->GetDictionary(i, &dict))
874        continue;
875      if (ProtocolHandler::IsValidDict(dict)) {
876        result.push_back(dict);
877      }
878    }
879  }
880  return result;
881}
882
883void ProtocolHandlerRegistry::RegisterProtocolHandlersFromPref(
884    const char* pref_name,
885    const HandlerSource source) {
886  std::vector<const base::DictionaryValue*> registered_handlers =
887      GetHandlersFromPref(pref_name);
888  for (std::vector<const base::DictionaryValue*>::const_iterator p =
889           registered_handlers.begin();
890       p != registered_handlers.end();
891       ++p) {
892    ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p);
893    RegisterProtocolHandler(handler, source);
894    bool is_default = false;
895    if ((*p)->GetBoolean("default", &is_default) && is_default) {
896      SetDefault(handler);
897    }
898  }
899}
900
901void ProtocolHandlerRegistry::IgnoreProtocolHandler(
902    const ProtocolHandler& handler,
903    const HandlerSource source) {
904  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
905  ProtocolHandlerList& list = (source == POLICY)
906                                  ? policy_ignored_protocol_handlers_
907                                  : user_ignored_protocol_handlers_;
908  if (!HandlerExists(handler, list))
909    list.push_back(handler);
910  if (HandlerExists(handler, ignored_protocol_handlers_))
911    return;
912  ignored_protocol_handlers_.push_back(handler);
913}
914
915void ProtocolHandlerRegistry::IgnoreProtocolHandlersFromPref(
916    const char* pref_name,
917    const HandlerSource source) {
918  std::vector<const base::DictionaryValue*> ignored_handlers =
919      GetHandlersFromPref(pref_name);
920  for (std::vector<const base::DictionaryValue*>::const_iterator p =
921           ignored_handlers.begin();
922       p != ignored_handlers.end();
923       ++p) {
924    IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p), source);
925  }
926}
927
928bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
929                                            ProtocolHandlerMultiMap* map) {
930  return HandlerExists(handler, (*map)[handler.protocol()]);
931}
932
933bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
934                                            const ProtocolHandlerList& list) {
935  return std::find(list.begin(), list.end(), handler) != list.end();
936}
937
938void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
939                                           ProtocolHandlerMultiMap* map) {
940  EraseHandler(handler, &(*map)[handler.protocol()]);
941}
942
943void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
944                                           ProtocolHandlerList* list) {
945  list->erase(std::find(list->begin(), list->end(), handler));
946}
947
948void ProtocolHandlerRegistry::AddPredefinedHandler(
949    const ProtocolHandler& handler) {
950  DCHECK(!is_loaded_);  // Must be called prior InitProtocolSettings.
951  RegisterProtocolHandler(handler, USER);
952  SetDefault(handler);
953}
954
955scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
956ProtocolHandlerRegistry::CreateJobInterceptorFactory() {
957  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
958  // this is always created on the UI thread (in profile_io's
959  // InitializeOnUIThread. Any method calls must be done
960  // on the IO thread (this is checked).
961  return scoped_ptr<JobInterceptorFactory>(
962      new JobInterceptorFactory(io_thread_delegate_.get()));
963}
964