• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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