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/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 
     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       "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|.
    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 
    171 ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() {
    172 }
    173 
    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::
    181 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 
    194 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 
    201 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 
    209 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 
    217 ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver(
    218     ProtocolHandlerRegistry* registry)
    219     : worker_(NULL),
    220       registry_(registry) {
    221   DCHECK(registry_);
    222 }
    223 
    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 
    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::
    247     IsInteractiveSetDefaultPermitted() {
    248   return true;
    249 }
    250 
    251 void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker(
    252     ShellIntegration::DefaultProtocolClientWorker* worker) {
    253   worker_ = worker;
    254 }
    255 
    256 bool ProtocolHandlerRegistry::DefaultClientObserver::IsOwnedByWorker() {
    257   return true;
    258 }
    259 
    260 // Delegate --------------------------------------------------------------------
    261 
    262 ProtocolHandlerRegistry::Delegate::~Delegate() {}
    263 
    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 
    273 void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
    274     const std::string& protocol) {
    275 }
    276 
    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*
    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*
    292 ProtocolHandlerRegistry::Delegate::CreateShellObserver(
    293     ProtocolHandlerRegistry* registry) {
    294   return new DefaultClientObserver(registry);
    295 }
    296 
    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 
    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 
    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 
    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 
    345 void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
    346     const ProtocolHandler& handler) {
    347   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    348   RegisterProtocolHandler(handler, USER);
    349   Save();
    350   NotifyChanged();
    351 }
    352 
    353 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
    354     const ProtocolHandler& handler) {
    355   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    356   IgnoreProtocolHandler(handler, USER);
    357   Save();
    358   NotifyChanged();
    359 }
    360 
    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
    382 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 
    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 
    409 bool ProtocolHandlerRegistry::IsDefault(
    410     const ProtocolHandler& handler) const {
    411   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    412   return GetHandlerFor(handler.protocol()) == handler;
    413 }
    414 
    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 
    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 
    471 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
    490 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
    501 ProtocolHandlerRegistry::GetIgnoredHandlers() {
    502   return ignored_protocol_handlers_;
    503 }
    504 
    505 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 
    515 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 
    526 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 
    537 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 
    549 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 
    565 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 
    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 
    595 bool ProtocolHandlerRegistry::IsHandledProtocol(
    596     const std::string& scheme) const {
    597   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    598   return enabled_ && !GetHandlerFor(scheme).IsEmpty();
    599 }
    600 
    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 
    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 
    645 const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor(
    646     const std::string& scheme) const {
    647   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    648   return LookupHandler(default_handlers_, scheme);
    649 }
    650 
    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 
    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 
    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
    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 
    719 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
    720   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    721   DCHECK(default_client_observers_.empty());
    722 }
    723 
    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 
    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*
    751 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 
    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 
    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 
    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 
    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 
    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 
    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*>
    851 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 
    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 
    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 
    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 
    918 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
    919                                             ProtocolHandlerMultiMap* map) {
    920   return HandlerExists(handler, (*map)[handler.protocol()]);
    921 }
    922 
    923 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
    924                                             const ProtocolHandlerList& list) {
    925   return std::find(list.begin(), list.end(), handler) != list.end();
    926 }
    927 
    928 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
    929                                            ProtocolHandlerMultiMap* map) {
    930   EraseHandler(handler, &(*map)[handler.protocol()]);
    931 }
    932 
    933 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
    934                                            ProtocolHandlerList* list) {
    935   list->erase(std::find(list->begin(), list->end(), handler));
    936 }
    937 
    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>
    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