Home | History | Annotate | Download | only in custom_handlers
      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 }
    964