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/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/user_prefs/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 
     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.
     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.
     94   void Enable() { enabled_ = true; }
     95 
     96   // Indicate that the registry has been disabled in the IO thread's copy of
     97   // the data.
     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 
    113 ProtocolHandlerRegistry::IOThreadDelegate::IOThreadDelegate(bool)
    114     : enabled_(true) {}
    115 ProtocolHandlerRegistry::IOThreadDelegate::~IOThreadDelegate() {}
    116 
    117 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 
    123 void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault(
    124     const std::string& scheme) {
    125   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    126   default_handlers_.erase(scheme);
    127 }
    128 
    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|.
    139 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 }
    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(Profile* profile,
    312     Delegate* delegate)
    313     : profile_(profile),
    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);
    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);
    348   Save();
    349   NotifyChanged();
    350 }
    351 
    352 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
    353     const ProtocolHandler& handler) {
    354   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    355   IgnoreProtocolHandler(handler);
    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           l10n_util::GetStringUTF16(IDS_GOOGLE_MAILTO_HANDLER_NAME)));
    422   AddPredefinedHandler(
    423       ProtocolHandler::CreateProtocolHandler(
    424           "webcal",
    425           GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL)),
    426           l10n_util::GetStringUTF16(IDS_GOOGLE_WEBCAL_HANDLER_NAME)));
    427 #else
    428   NOTREACHED();  // this method should only ever be called in chromeos.
    429 #endif
    430 }
    431 
    432 void ProtocolHandlerRegistry::InitProtocolSettings() {
    433   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    434 
    435   // Any further default additions to the table will get rejected from now on.
    436   is_loaded_ = true;
    437   is_loading_ = true;
    438 
    439   PrefService* prefs = profile_->GetPrefs();
    440   if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) {
    441     if (prefs->GetBoolean(prefs::kCustomHandlersEnabled)) {
    442       Enable();
    443     } else {
    444       Disable();
    445     }
    446   }
    447   std::vector<const DictionaryValue*> registered_handlers =
    448       GetHandlersFromPref(prefs::kRegisteredProtocolHandlers);
    449   for (std::vector<const DictionaryValue*>::const_iterator p =
    450        registered_handlers.begin();
    451        p != registered_handlers.end(); ++p) {
    452     ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p);
    453     RegisterProtocolHandler(handler);
    454     bool is_default = false;
    455     if ((*p)->GetBoolean("default", &is_default) && is_default) {
    456       SetDefault(handler);
    457     }
    458   }
    459   std::vector<const DictionaryValue*> ignored_handlers =
    460     GetHandlersFromPref(prefs::kIgnoredProtocolHandlers);
    461   for (std::vector<const DictionaryValue*>::const_iterator p =
    462        ignored_handlers.begin();
    463        p != ignored_handlers.end(); ++p) {
    464     IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p));
    465   }
    466   is_loading_ = false;
    467 
    468   // For each default protocol handler, check that we are still registered
    469   // with the OS as the default application.
    470   if (ShouldRemoveHandlersNotInOS()) {
    471     for (ProtocolHandlerMap::const_iterator p = default_handlers_.begin();
    472          p != default_handlers_.end(); ++p) {
    473       ProtocolHandler handler = p->second;
    474       DefaultClientObserver* observer = delegate_->CreateShellObserver(this);
    475       scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker;
    476       worker = delegate_->CreateShellWorker(observer, handler.protocol());
    477       observer->SetWorker(worker.get());
    478       default_client_observers_.push_back(observer);
    479       worker->StartCheckIsDefault();
    480     }
    481   }
    482 }
    483 
    484 int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const {
    485   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    486   const ProtocolHandler& handler = GetHandlerFor(scheme);
    487   if (handler.IsEmpty())
    488     return -1;
    489   const ProtocolHandlerList* handlers = GetHandlerList(scheme);
    490   if (!handlers)
    491     return -1;
    492 
    493   ProtocolHandlerList::const_iterator p;
    494   int i;
    495   for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) {
    496     if (*p == handler)
    497       return i;
    498   }
    499   return -1;
    500 }
    501 
    502 ProtocolHandlerRegistry::ProtocolHandlerList
    503 ProtocolHandlerRegistry::GetHandlersFor(
    504     const std::string& scheme) const {
    505   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    506   ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
    507   if (p == protocol_handlers_.end()) {
    508     return ProtocolHandlerList();
    509   }
    510   return p->second;
    511 }
    512 
    513 ProtocolHandlerRegistry::ProtocolHandlerList
    514 ProtocolHandlerRegistry::GetIgnoredHandlers() {
    515   return ignored_protocol_handlers_;
    516 }
    517 
    518 void ProtocolHandlerRegistry::GetRegisteredProtocols(
    519     std::vector<std::string>* output) const {
    520   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    521   ProtocolHandlerMultiMap::const_iterator p;
    522   for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) {
    523     if (!p->second.empty())
    524       output->push_back(p->first);
    525   }
    526 }
    527 
    528 bool ProtocolHandlerRegistry::CanSchemeBeOverridden(
    529     const std::string& scheme) const {
    530   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    531   const ProtocolHandlerList* handlers = GetHandlerList(scheme);
    532   // If we already have a handler for this scheme, we can add more.
    533   if (handlers != NULL && !handlers->empty())
    534     return true;
    535   // Don't override a scheme if it already has an external handler.
    536   return !delegate_->IsExternalHandlerRegistered(scheme);
    537 }
    538 
    539 bool ProtocolHandlerRegistry::IsRegistered(
    540     const ProtocolHandler& handler) const {
    541   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    542   const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
    543   if (!handlers) {
    544     return false;
    545   }
    546   return std::find(handlers->begin(), handlers->end(), handler) !=
    547       handlers->end();
    548 }
    549 
    550 bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const {
    551   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    552   ProtocolHandlerList::const_iterator i;
    553   for (i = ignored_protocol_handlers_.begin();
    554        i != ignored_protocol_handlers_.end(); ++i) {
    555     if (*i == handler) {
    556       return true;
    557     }
    558   }
    559   return false;
    560 }
    561 
    562 bool ProtocolHandlerRegistry::HasRegisteredEquivalent(
    563     const ProtocolHandler& handler) const {
    564   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    565   const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
    566   if (!handlers) {
    567     return false;
    568   }
    569   ProtocolHandlerList::const_iterator i;
    570   for (i = handlers->begin(); i != handlers->end(); ++i) {
    571     if (handler.IsEquivalent(*i)) {
    572       return true;
    573     }
    574   }
    575   return false;
    576 }
    577 
    578 bool ProtocolHandlerRegistry::HasIgnoredEquivalent(
    579     const ProtocolHandler& handler) const {
    580   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    581   ProtocolHandlerList::const_iterator i;
    582   for (i = ignored_protocol_handlers_.begin();
    583        i != ignored_protocol_handlers_.end(); ++i) {
    584     if (handler.IsEquivalent(*i)) {
    585       return true;
    586     }
    587   }
    588   return false;
    589 }
    590 
    591 void ProtocolHandlerRegistry::RemoveIgnoredHandler(
    592     const ProtocolHandler& handler) {
    593   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    594   bool should_notify = false;
    595   ProtocolHandlerList::iterator p = std::find(
    596       ignored_protocol_handlers_.begin(), ignored_protocol_handlers_.end(),
    597       handler);
    598   if (p != ignored_protocol_handlers_.end()) {
    599     ignored_protocol_handlers_.erase(p);
    600     Save();
    601     should_notify = true;
    602   }
    603   if (should_notify)
    604     NotifyChanged();
    605 }
    606 
    607 bool ProtocolHandlerRegistry::IsHandledProtocol(
    608     const std::string& scheme) const {
    609   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    610   return enabled_ && !GetHandlerFor(scheme).IsEmpty();
    611 }
    612 
    613 void ProtocolHandlerRegistry::RemoveHandler(
    614     const ProtocolHandler& handler) {
    615   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    616   ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()];
    617   ProtocolHandlerList::iterator p =
    618       std::find(handlers.begin(), handlers.end(), handler);
    619   if (p != handlers.end()) {
    620     handlers.erase(p);
    621   }
    622   ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol());
    623   if (q != default_handlers_.end() && q->second == handler) {
    624     // Make the new top handler in the list the default.
    625     if (!handlers.empty()) {
    626       // NOTE We pass a copy because SetDefault() modifies handlers.
    627       SetDefault(ProtocolHandler(handlers[0]));
    628     } else {
    629       BrowserThread::PostTask(
    630           BrowserThread::IO, FROM_HERE,
    631           base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_,
    632                      q->second.protocol()));
    633 
    634       default_handlers_.erase(q);
    635     }
    636   }
    637 
    638   if (!IsHandledProtocol(handler.protocol())) {
    639     delegate_->DeregisterExternalHandler(handler.protocol());
    640   }
    641   Save();
    642   NotifyChanged();
    643 }
    644 
    645 void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) {
    646   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    647   ProtocolHandler current_default = GetHandlerFor(scheme);
    648   if (!current_default.IsEmpty())
    649     RemoveHandler(current_default);
    650 }
    651 
    652 const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor(
    653     const std::string& scheme) const {
    654   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    655   return LookupHandler(default_handlers_, scheme);
    656 }
    657 
    658 void ProtocolHandlerRegistry::Enable() {
    659   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    660   if (enabled_) {
    661     return;
    662   }
    663   enabled_ = true;
    664   BrowserThread::PostTask(
    665       BrowserThread::IO,
    666       FROM_HERE,
    667       base::Bind(&IOThreadDelegate::Enable, io_thread_delegate_));
    668 
    669   ProtocolHandlerMap::const_iterator p;
    670   for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
    671     delegate_->RegisterExternalHandler(p->first);
    672   }
    673   Save();
    674   NotifyChanged();
    675 }
    676 
    677 void ProtocolHandlerRegistry::Disable() {
    678   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    679   if (!enabled_) {
    680     return;
    681   }
    682   enabled_ = false;
    683   BrowserThread::PostTask(
    684       BrowserThread::IO,
    685       FROM_HERE,
    686       base::Bind(&IOThreadDelegate::Disable, io_thread_delegate_));
    687 
    688   ProtocolHandlerMap::const_iterator p;
    689   for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
    690     delegate_->DeregisterExternalHandler(p->first);
    691   }
    692   Save();
    693   NotifyChanged();
    694 }
    695 
    696 void ProtocolHandlerRegistry::Shutdown() {
    697   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    698   delegate_.reset(NULL);
    699   // We free these now in case there are any outstanding workers running. If
    700   // we didn't free them they could respond to workers and try to update the
    701   // protocol handler registry after it was deleted.
    702   // Observers remove themselves from this list when they are deleted; so
    703   // we delete the last item until none are left in the list.
    704   while (!default_client_observers_.empty()) {
    705     delete default_client_observers_.back();
    706   }
    707 }
    708 
    709 // static
    710 void ProtocolHandlerRegistry::RegisterProfilePrefs(
    711     user_prefs::PrefRegistrySyncable* registry) {
    712   registry->RegisterListPref(prefs::kRegisteredProtocolHandlers,
    713                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    714   registry->RegisterListPref(prefs::kIgnoredProtocolHandlers,
    715                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    716   registry->RegisterBooleanPref(
    717       prefs::kCustomHandlersEnabled,
    718       true,
    719       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    720 }
    721 
    722 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
    723   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    724   DCHECK(default_client_observers_.empty());
    725 }
    726 
    727 void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) {
    728   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    729   DCHECK(IsRegistered(handler));
    730   ProtocolHandlerMultiMap::iterator p =
    731       protocol_handlers_.find(handler.protocol());
    732   ProtocolHandlerList& list = p->second;
    733   list.erase(std::find(list.begin(), list.end(), handler));
    734   list.insert(list.begin(), handler);
    735 }
    736 
    737 void ProtocolHandlerRegistry::Save() {
    738   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    739   if (is_loading_) {
    740     return;
    741   }
    742   scoped_ptr<Value> registered_protocol_handlers(EncodeRegisteredHandlers());
    743   scoped_ptr<Value> ignored_protocol_handlers(EncodeIgnoredHandlers());
    744   scoped_ptr<Value> enabled(Value::CreateBooleanValue(enabled_));
    745   profile_->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers,
    746       *registered_protocol_handlers);
    747   profile_->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers,
    748       *ignored_protocol_handlers);
    749   profile_->GetPrefs()->Set(prefs::kCustomHandlersEnabled, *enabled);
    750 }
    751 
    752 const ProtocolHandlerRegistry::ProtocolHandlerList*
    753 ProtocolHandlerRegistry::GetHandlerList(
    754     const std::string& scheme) const {
    755   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    756   ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
    757   if (p == protocol_handlers_.end()) {
    758     return NULL;
    759   }
    760   return &p->second;
    761 }
    762 
    763 void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) {
    764   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    765   ProtocolHandlerMap::const_iterator p = default_handlers_.find(
    766       handler.protocol());
    767   // If we're not loading, and we are setting a default for a new protocol,
    768   // register with the OS.
    769   if (!is_loading_ && p == default_handlers_.end())
    770       delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this);
    771   default_handlers_.erase(handler.protocol());
    772   default_handlers_.insert(std::make_pair(handler.protocol(), handler));
    773   PromoteHandler(handler);
    774   BrowserThread::PostTask(
    775       BrowserThread::IO,
    776       FROM_HERE,
    777       base::Bind(&IOThreadDelegate::SetDefault, io_thread_delegate_, handler));
    778 }
    779 
    780 void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) {
    781   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    782   ProtocolHandlerMultiMap::iterator p =
    783       protocol_handlers_.find(handler.protocol());
    784 
    785   if (p != protocol_handlers_.end()) {
    786     p->second.push_back(handler);
    787     return;
    788   }
    789 
    790   ProtocolHandlerList new_list;
    791   new_list.push_back(handler);
    792   protocol_handlers_[handler.protocol()] = new_list;
    793 }
    794 
    795 Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() {
    796   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    797   ListValue* protocol_handlers = new ListValue();
    798   for (ProtocolHandlerMultiMap::iterator i = protocol_handlers_.begin();
    799        i != protocol_handlers_.end(); ++i) {
    800     for (ProtocolHandlerList::iterator j = i->second.begin();
    801          j != i->second.end(); ++j) {
    802       DictionaryValue* encoded = j->Encode();
    803       if (IsDefault(*j)) {
    804         encoded->Set("default", Value::CreateBooleanValue(true));
    805       }
    806       protocol_handlers->Append(encoded);
    807     }
    808   }
    809   return protocol_handlers;
    810 }
    811 
    812 Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
    813   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    814   ListValue* handlers = new ListValue();
    815   for (ProtocolHandlerList::iterator i = ignored_protocol_handlers_.begin();
    816        i != ignored_protocol_handlers_.end(); ++i) {
    817     handlers->Append(i->Encode());
    818   }
    819   return handlers;
    820 }
    821 
    822 void ProtocolHandlerRegistry::NotifyChanged() {
    823   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    824   content::NotificationService::current()->Notify(
    825       chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
    826       content::Source<Profile>(profile_),
    827       content::NotificationService::NoDetails());
    828 }
    829 
    830 void ProtocolHandlerRegistry::RegisterProtocolHandler(
    831     const ProtocolHandler& handler) {
    832   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    833   DCHECK(CanSchemeBeOverridden(handler.protocol()));
    834   DCHECK(!handler.IsEmpty());
    835   if (IsRegistered(handler)) {
    836     return;
    837   }
    838   if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol()))
    839     delegate_->RegisterExternalHandler(handler.protocol());
    840   InsertHandler(handler);
    841 }
    842 
    843 std::vector<const DictionaryValue*>
    844 ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const {
    845   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    846   std::vector<const DictionaryValue*> result;
    847   PrefService* prefs = profile_->GetPrefs();
    848   if (!prefs->HasPrefPath(pref_name)) {
    849     return result;
    850   }
    851 
    852   const ListValue* handlers = prefs->GetList(pref_name);
    853   if (handlers) {
    854     for (size_t i = 0; i < handlers->GetSize(); ++i) {
    855       const DictionaryValue* dict;
    856       if (!handlers->GetDictionary(i, &dict))
    857         continue;
    858       if (ProtocolHandler::IsValidDict(dict)) {
    859         result.push_back(dict);
    860       }
    861     }
    862   }
    863   return result;
    864 }
    865 
    866 void ProtocolHandlerRegistry::IgnoreProtocolHandler(
    867     const ProtocolHandler& handler) {
    868   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    869   ignored_protocol_handlers_.push_back(handler);
    870 }
    871 
    872 void ProtocolHandlerRegistry::AddPredefinedHandler(
    873     const ProtocolHandler& handler) {
    874   DCHECK(!is_loaded_);  // Must be called prior InitProtocolSettings.
    875   RegisterProtocolHandler(handler);
    876   SetDefault(handler);
    877 }
    878 
    879 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
    880 ProtocolHandlerRegistry::CreateJobInterceptorFactory() {
    881   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    882   // this is always created on the UI thread (in profile_io's
    883   // InitializeOnUIThread. Any method calls must be done
    884   // on the IO thread (this is checked).
    885   return scoped_ptr<JobInterceptorFactory>(
    886       new JobInterceptorFactory(io_thread_delegate_.get()));
    887 }
    888