Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / custom_handlers / protocol_handler_registry.cc
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
26 using content::BrowserThread;
27 using content::ChildProcessSecurityPolicy;
28
29 namespace {
30
31 const ProtocolHandler& LookupHandler(
32     const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map,
33     const std::string& scheme) {
34   ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p =
35       handler_map.find(scheme);
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.
45 bool ShouldRemoveHandlersNotInOS() {
46 #if defined(OS_LINUX)
47   // We don't do this on Linux as the OS registration there is not reliable,
48   // and Chrome OS doesn't have any notion of OS registration.
49   // TODO(benwells): When Linux support is more reliable remove this
50   // difference (http://crbug.com/88255).
51   return false;
52 #else
53   return ShellIntegration::CanSetAsDefaultProtocolClient() !=
54       ShellIntegration::SET_DEFAULT_NOT_ALLOWED;
55 #endif
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.
65 class 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
112 ProtocolHandlerRegistry::IOThreadDelegate::IOThreadDelegate(bool)
113     : enabled_(true) {}
114 ProtocolHandlerRegistry::IOThreadDelegate::~IOThreadDelegate() {}
115
116 bool ProtocolHandlerRegistry::IOThreadDelegate::IsHandledProtocol(
117     const std::string& scheme) const {
118   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
119   return enabled_ && !LookupHandler(default_handlers_, scheme).IsEmpty();
120 }
121
122 void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault(
123     const std::string& scheme) {
124   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
125   default_handlers_.erase(scheme);
126 }
127
128 void ProtocolHandlerRegistry::IOThreadDelegate::SetDefault(
129     const ProtocolHandler& handler) {
130   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
131   ClearDefault(handler.protocol());
132   default_handlers_.insert(std::make_pair(handler.protocol(), handler));
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|.
138 net::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|.
163 ProtocolHandlerRegistry::JobInterceptorFactory::JobInterceptorFactory(
164     IOThreadDelegate* io_thread_delegate)
165     : io_thread_delegate_(io_thread_delegate) {
166   DCHECK(io_thread_delegate_.get());
167   DetachFromThread();
168 }
169
170 ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() {
171 }
172
173 void ProtocolHandlerRegistry::JobInterceptorFactory::Chain(
174     scoped_ptr<net::URLRequestJobFactory> job_factory) {
175   job_factory_ = job_factory.Pass();
176 }
177
178 net::URLRequestJob*
179 ProtocolHandlerRegistry::JobInterceptorFactory::
180 MaybeCreateJobWithProtocolHandler(
181     const std::string& scheme,
182     net::URLRequest* request,
183     net::NetworkDelegate* network_delegate) const {
184   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
185   net::URLRequestJob* job = io_thread_delegate_->MaybeCreateJob(
186       request, network_delegate);
187   if (job)
188     return job;
189   return job_factory_->MaybeCreateJobWithProtocolHandler(
190       scheme, request, network_delegate);
191 }
192
193 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledProtocol(
194     const std::string& scheme) const {
195   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
196   return io_thread_delegate_->IsHandledProtocol(scheme) ||
197       job_factory_->IsHandledProtocol(scheme);
198 }
199
200 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledURL(
201     const GURL& url) const {
202   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
203   return (url.is_valid() &&
204       io_thread_delegate_->IsHandledProtocol(url.scheme())) ||
205       job_factory_->IsHandledURL(url);
206 }
207
208 bool 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
216 ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver(
217     ProtocolHandlerRegistry* registry)
218     : worker_(NULL),
219       registry_(registry) {
220   DCHECK(registry_);
221 }
222
223 ProtocolHandlerRegistry::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
233 void ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState(
234     ShellIntegration::DefaultWebClientUIState state) {
235   if (worker_) {
236     if (ShouldRemoveHandlersNotInOS() &&
237         (state == ShellIntegration::STATE_NOT_DEFAULT)) {
238       registry_->ClearDefault(worker_->protocol());
239     }
240   } else {
241     NOTREACHED();
242   }
243 }
244
245 bool ProtocolHandlerRegistry::DefaultClientObserver::
246     IsInteractiveSetDefaultPermitted() {
247   return true;
248 }
249
250 void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker(
251     ShellIntegration::DefaultProtocolClientWorker* worker) {
252   worker_ = worker;
253 }
254
255 bool ProtocolHandlerRegistry::DefaultClientObserver::IsOwnedByWorker() {
256   return true;
257 }
258
259 // Delegate --------------------------------------------------------------------
260
261 ProtocolHandlerRegistry::Delegate::~Delegate() {}
262
263 void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler(
264     const std::string& protocol) {
265   ChildProcessSecurityPolicy* policy =
266     ChildProcessSecurityPolicy::GetInstance();
267   if (!policy->IsWebSafeScheme(protocol)) {
268     policy->RegisterWebSafeScheme(protocol);
269   }
270 }
271
272 void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
273     const std::string& protocol) {
274 }
275
276 bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered(
277     const std::string& protocol) {
278   // NOTE(koz): This function is safe to call from any thread, despite living
279   // in ProfileIOData.
280   return ProfileIOData::IsHandledProtocol(protocol);
281 }
282
283 ShellIntegration::DefaultProtocolClientWorker*
284 ProtocolHandlerRegistry::Delegate::CreateShellWorker(
285     ShellIntegration::DefaultWebClientObserver* observer,
286     const std::string& protocol) {
287   return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol);
288 }
289
290 ProtocolHandlerRegistry::DefaultClientObserver*
291 ProtocolHandlerRegistry::Delegate::CreateShellObserver(
292     ProtocolHandlerRegistry* registry) {
293   return new DefaultClientObserver(registry);
294 }
295
296 void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient(
297     const std::string& protocol, ProtocolHandlerRegistry* registry) {
298   DefaultClientObserver* observer = CreateShellObserver(registry);
299   // The worker pointer is reference counted. While it is running the
300   // message loops of the FILE and UI thread will hold references to it
301   // and it will be automatically freed once all its tasks have finished.
302   scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker;
303   worker = CreateShellWorker(observer, protocol);
304   observer->SetWorker(worker.get());
305   registry->default_client_observers_.push_back(observer);
306   worker->StartSetAsDefault();
307 }
308
309 // ProtocolHandlerRegistry -----------------------------------------------------
310
311 ProtocolHandlerRegistry::ProtocolHandlerRegistry(
312     content::BrowserContext* context, Delegate* delegate)
313     : context_(context),
314       delegate_(delegate),
315       enabled_(true),
316       is_loading_(false),
317       is_loaded_(false),
318       io_thread_delegate_(new IOThreadDelegate(enabled_)){
319 }
320
321 bool 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
335 void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler(
336     const ProtocolHandler& handler) {
337   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
338   RegisterProtocolHandler(handler, USER);
339   SetDefault(handler);
340   Save();
341   NotifyChanged();
342 }
343
344 void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
345     const ProtocolHandler& handler) {
346   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
347   RegisterProtocolHandler(handler, USER);
348   Save();
349   NotifyChanged();
350 }
351
352 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
353     const ProtocolHandler& handler) {
354   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
355   IgnoreProtocolHandler(handler, USER);
356   Save();
357   NotifyChanged();
358 }
359
360 bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) {
361   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
362   ProtocolHandler old_default = GetHandlerFor(handler.protocol());
363   bool make_new_handler_default = handler.IsSameOrigin(old_default);
364   ProtocolHandlerList to_replace(GetReplacedHandlers(handler));
365   if (to_replace.empty())
366     return false;
367   for (ProtocolHandlerList::iterator p = to_replace.begin();
368        p != to_replace.end(); ++p) {
369     RemoveHandler(*p);
370   }
371   if (make_new_handler_default) {
372     OnAcceptRegisterProtocolHandler(handler);
373   } else {
374     InsertHandler(handler);
375     NotifyChanged();
376   }
377   return true;
378 }
379
380 ProtocolHandlerRegistry::ProtocolHandlerList
381 ProtocolHandlerRegistry::GetReplacedHandlers(
382     const ProtocolHandler& handler) const {
383   ProtocolHandlerList replaced_handlers;
384   const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
385   if (!handlers)
386     return replaced_handlers;
387   for (ProtocolHandlerList::const_iterator p = handlers->begin();
388        p != handlers->end(); p++) {
389     if (handler.IsSameOrigin(*p)) {
390       replaced_handlers.push_back(*p);
391     }
392   }
393   return replaced_handlers;
394 }
395
396 void 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
408 bool ProtocolHandlerRegistry::IsDefault(
409     const ProtocolHandler& handler) const {
410   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
411   return GetHandlerFor(handler.protocol()) == handler;
412 }
413
414 void ProtocolHandlerRegistry::InstallDefaultsForChromeOS() {
415 #if defined(OS_CHROMEOS)
416   // Only chromeos has default protocol handlers at this point.
417   AddPredefinedHandler(
418       ProtocolHandler::CreateProtocolHandler(
419           "mailto",
420           GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_MAILTO_HANDLER_URL))));
421   AddPredefinedHandler(
422       ProtocolHandler::CreateProtocolHandler(
423           "webcal",
424           GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL))));
425 #else
426   NOTREACHED();  // this method should only ever be called in chromeos.
427 #endif
428 }
429
430 void 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
470 int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const {
471   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
472   const ProtocolHandler& handler = GetHandlerFor(scheme);
473   if (handler.IsEmpty())
474     return -1;
475   const ProtocolHandlerList* handlers = GetHandlerList(scheme);
476   if (!handlers)
477     return -1;
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
488 ProtocolHandlerRegistry::ProtocolHandlerList
489 ProtocolHandlerRegistry::GetHandlersFor(
490     const std::string& scheme) const {
491   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
492   ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
493   if (p == protocol_handlers_.end()) {
494     return ProtocolHandlerList();
495   }
496   return p->second;
497 }
498
499 ProtocolHandlerRegistry::ProtocolHandlerList
500 ProtocolHandlerRegistry::GetIgnoredHandlers() {
501   return ignored_protocol_handlers_;
502 }
503
504 void ProtocolHandlerRegistry::GetRegisteredProtocols(
505     std::vector<std::string>* output) const {
506   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
507   ProtocolHandlerMultiMap::const_iterator p;
508   for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) {
509     if (!p->second.empty())
510       output->push_back(p->first);
511   }
512 }
513
514 bool ProtocolHandlerRegistry::CanSchemeBeOverridden(
515     const std::string& scheme) const {
516   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
517   const ProtocolHandlerList* handlers = GetHandlerList(scheme);
518   // If we already have a handler for this scheme, we can add more.
519   if (handlers != NULL && !handlers->empty())
520     return true;
521   // Don't override a scheme if it already has an external handler.
522   return !delegate_->IsExternalHandlerRegistered(scheme);
523 }
524
525 bool ProtocolHandlerRegistry::IsRegistered(
526     const ProtocolHandler& handler) const {
527   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
528   const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
529   if (!handlers) {
530     return false;
531   }
532   return std::find(handlers->begin(), handlers->end(), handler) !=
533       handlers->end();
534 }
535
536 bool ProtocolHandlerRegistry::IsRegisteredByUser(
537     const ProtocolHandler& handler) {
538   return HandlerExists(handler, &user_protocol_handlers_);
539 }
540
541 bool ProtocolHandlerRegistry::HasPolicyRegisteredHandler(
542     const std::string& scheme) {
543   return (policy_protocol_handlers_.find(scheme) !=
544           policy_protocol_handlers_.end());
545 }
546
547 bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const {
548   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
549   ProtocolHandlerList::const_iterator i;
550   for (i = ignored_protocol_handlers_.begin();
551        i != ignored_protocol_handlers_.end(); ++i) {
552     if (*i == handler) {
553       return true;
554     }
555   }
556   return false;
557 }
558
559 bool ProtocolHandlerRegistry::HasRegisteredEquivalent(
560     const ProtocolHandler& handler) const {
561   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
562   const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
563   if (!handlers) {
564     return false;
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
575 bool ProtocolHandlerRegistry::HasIgnoredEquivalent(
576     const ProtocolHandler& handler) const {
577   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
578   ProtocolHandlerList::const_iterator i;
579   for (i = ignored_protocol_handlers_.begin();
580        i != ignored_protocol_handlers_.end(); ++i) {
581     if (handler.IsEquivalent(*i)) {
582       return true;
583     }
584   }
585   return false;
586 }
587
588 void ProtocolHandlerRegistry::RemoveIgnoredHandler(
589     const ProtocolHandler& handler) {
590   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
591   bool should_notify = false;
592   if (HandlerExists(handler, ignored_protocol_handlers_) &&
593       HandlerExists(handler, user_ignored_protocol_handlers_)) {
594     EraseHandler(handler, &user_ignored_protocol_handlers_);
595     Save();
596     if (!HandlerExists(handler, policy_ignored_protocol_handlers_)) {
597       EraseHandler(handler, &ignored_protocol_handlers_);
598       should_notify = true;
599     }
600   }
601   if (should_notify)
602     NotifyChanged();
603 }
604
605 bool ProtocolHandlerRegistry::IsHandledProtocol(
606     const std::string& scheme) const {
607   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
608   return enabled_ && !GetHandlerFor(scheme).IsEmpty();
609 }
610
611 void ProtocolHandlerRegistry::RemoveHandler(
612     const ProtocolHandler& handler) {
613   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
614   ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()];
615   bool erase_success = false;
616   if (HandlerExists(handler, handlers) &&
617       HandlerExists(handler, &user_protocol_handlers_)) {
618     EraseHandler(handler, &user_protocol_handlers_);
619     erase_success = true;
620     if (!HandlerExists(handler, &policy_protocol_handlers_))
621       EraseHandler(handler, &protocol_handlers_);
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
647 void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) {
648   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
649   ProtocolHandler current_default = GetHandlerFor(scheme);
650   if (!current_default.IsEmpty())
651     RemoveHandler(current_default);
652 }
653
654 const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor(
655     const std::string& scheme) const {
656   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
657   return LookupHandler(default_handlers_, scheme);
658 }
659
660 void 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
679 void 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
698 void ProtocolHandlerRegistry::Shutdown() {
699   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
700   delegate_.reset(NULL);
701   // We free these now in case there are any outstanding workers running. If
702   // we didn't free them they could respond to workers and try to update the
703   // protocol handler registry after it was deleted.
704   // Observers remove themselves from this list when they are deleted; so
705   // we delete the last item until none are left in the list.
706   while (!default_client_observers_.empty()) {
707     delete default_client_observers_.back();
708   }
709 }
710
711 // static
712 void ProtocolHandlerRegistry::RegisterProfilePrefs(
713     user_prefs::PrefRegistrySyncable* registry) {
714   registry->RegisterListPref(prefs::kRegisteredProtocolHandlers,
715                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
716   registry->RegisterListPref(prefs::kIgnoredProtocolHandlers,
717                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
718   registry->RegisterListPref(prefs::kPolicyRegisteredProtocolHandlers,
719                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
720   registry->RegisterListPref(prefs::kPolicyIgnoredProtocolHandlers,
721                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
722   registry->RegisterBooleanPref(
723       prefs::kCustomHandlersEnabled,
724       true,
725       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
726 }
727
728 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
729   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
730   DCHECK(default_client_observers_.empty());
731 }
732
733 void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) {
734   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
735   DCHECK(IsRegistered(handler));
736   ProtocolHandlerMultiMap::iterator p =
737       protocol_handlers_.find(handler.protocol());
738   ProtocolHandlerList& list = p->second;
739   list.erase(std::find(list.begin(), list.end(), handler));
740   list.insert(list.begin(), handler);
741 }
742
743 void 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
760 const ProtocolHandlerRegistry::ProtocolHandlerList*
761 ProtocolHandlerRegistry::GetHandlerList(
762     const std::string& scheme) const {
763   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
764   ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
765   if (p == protocol_handlers_.end()) {
766     return NULL;
767   }
768   return &p->second;
769 }
770
771 void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) {
772   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
773   ProtocolHandlerMap::const_iterator p = default_handlers_.find(
774       handler.protocol());
775   // If we're not loading, and we are setting a default for a new protocol,
776   // register with the OS.
777   if (!is_loading_ && p == default_handlers_.end())
778       delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this);
779   default_handlers_.erase(handler.protocol());
780   default_handlers_.insert(std::make_pair(handler.protocol(), handler));
781   PromoteHandler(handler);
782   BrowserThread::PostTask(
783       BrowserThread::IO,
784       FROM_HERE,
785       base::Bind(&IOThreadDelegate::SetDefault, io_thread_delegate_, handler));
786 }
787
788 void 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
803 base::Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() {
804   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
805   base::ListValue* protocol_handlers = new base::ListValue();
806   for (ProtocolHandlerMultiMap::iterator i = user_protocol_handlers_.begin();
807        i != user_protocol_handlers_.end();
808        ++i) {
809     for (ProtocolHandlerList::iterator j = i->second.begin();
810          j != i->second.end(); ++j) {
811       base::DictionaryValue* encoded = j->Encode();
812       if (IsDefault(*j)) {
813         encoded->Set("default", new base::FundamentalValue(true));
814       }
815       protocol_handlers->Append(encoded);
816     }
817   }
818   return protocol_handlers;
819 }
820
821 base::Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
822   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
823   base::ListValue* handlers = new base::ListValue();
824   for (ProtocolHandlerList::iterator i =
825            user_ignored_protocol_handlers_.begin();
826        i != user_ignored_protocol_handlers_.end();
827        ++i) {
828     handlers->Append(i->Encode());
829   }
830   return handlers;
831 }
832
833 void ProtocolHandlerRegistry::NotifyChanged() {
834   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
835   content::NotificationService::current()->Notify(
836       chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
837       content::Source<content::BrowserContext>(context_),
838       content::NotificationService::NoDetails());
839 }
840
841 void ProtocolHandlerRegistry::RegisterProtocolHandler(
842     const ProtocolHandler& handler,
843     const HandlerSource source) {
844   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
845   DCHECK(CanSchemeBeOverridden(handler.protocol()));
846   DCHECK(!handler.IsEmpty());
847   ProtocolHandlerMultiMap& map =
848       (source == POLICY) ? policy_protocol_handlers_ : user_protocol_handlers_;
849   ProtocolHandlerList& list = map[handler.protocol()];
850   if (!HandlerExists(handler, list))
851     list.push_back(handler);
852   if (IsRegistered(handler)) {
853     return;
854   }
855   if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol()))
856     delegate_->RegisterExternalHandler(handler.protocol());
857   InsertHandler(handler);
858 }
859
860 std::vector<const base::DictionaryValue*>
861 ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const {
862   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
863   std::vector<const base::DictionaryValue*> result;
864   PrefService* prefs = user_prefs::UserPrefs::Get(context_);
865   if (!prefs->HasPrefPath(pref_name)) {
866     return result;
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
883 void ProtocolHandlerRegistry::RegisterProtocolHandlersFromPref(
884     const char* pref_name,
885     const HandlerSource source) {
886   std::vector<const base::DictionaryValue*> registered_handlers =
887       GetHandlersFromPref(pref_name);
888   for (std::vector<const base::DictionaryValue*>::const_iterator p =
889            registered_handlers.begin();
890        p != registered_handlers.end();
891        ++p) {
892     ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p);
893     RegisterProtocolHandler(handler, source);
894     bool is_default = false;
895     if ((*p)->GetBoolean("default", &is_default) && is_default) {
896       SetDefault(handler);
897     }
898   }
899 }
900
901 void ProtocolHandlerRegistry::IgnoreProtocolHandler(
902     const ProtocolHandler& handler,
903     const HandlerSource source) {
904   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
905   ProtocolHandlerList& list = (source == POLICY)
906                                   ? policy_ignored_protocol_handlers_
907                                   : user_ignored_protocol_handlers_;
908   if (!HandlerExists(handler, list))
909     list.push_back(handler);
910   if (HandlerExists(handler, ignored_protocol_handlers_))
911     return;
912   ignored_protocol_handlers_.push_back(handler);
913 }
914
915 void ProtocolHandlerRegistry::IgnoreProtocolHandlersFromPref(
916     const char* pref_name,
917     const HandlerSource source) {
918   std::vector<const base::DictionaryValue*> ignored_handlers =
919       GetHandlersFromPref(pref_name);
920   for (std::vector<const base::DictionaryValue*>::const_iterator p =
921            ignored_handlers.begin();
922        p != ignored_handlers.end();
923        ++p) {
924     IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p), source);
925   }
926 }
927
928 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
929                                             ProtocolHandlerMultiMap* map) {
930   return HandlerExists(handler, (*map)[handler.protocol()]);
931 }
932
933 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
934                                             const ProtocolHandlerList& list) {
935   return std::find(list.begin(), list.end(), handler) != list.end();
936 }
937
938 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
939                                            ProtocolHandlerMultiMap* map) {
940   EraseHandler(handler, &(*map)[handler.protocol()]);
941 }
942
943 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
944                                            ProtocolHandlerList* list) {
945   list->erase(std::find(list->begin(), list->end(), handler));
946 }
947
948 void ProtocolHandlerRegistry::AddPredefinedHandler(
949     const ProtocolHandler& handler) {
950   DCHECK(!is_loaded_);  // Must be called prior InitProtocolSettings.
951   RegisterProtocolHandler(handler, USER);
952   SetDefault(handler);
953 }
954
955 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
956 ProtocolHandlerRegistry::CreateJobInterceptorFactory() {
957   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
958   // this is always created on the UI thread (in profile_io's
959   // InitializeOnUIThread. Any method calls must be done
960   // on the IO thread (this is checked).
961   return scoped_ptr<JobInterceptorFactory>(
962       new JobInterceptorFactory(io_thread_delegate_.get()));
963 }