15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile_io_data.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/custom_handlers/protocol_handler.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
1803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/grit/generated_resources.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h"
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/user_prefs/user_prefs.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/child_process_security_policy.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/network_delegate.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_redirect_job.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::ChildProcessSecurityPolicy;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const ProtocolHandler& LookupHandler(
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map,
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& scheme) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p =
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handler_map.find(scheme);
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (p != handler_map.end())
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return p->second;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ProtocolHandler::EmptyProtocolHandler();
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If true default protocol handlers will be removed if the OS level
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// registration for a protocol is no longer Chrome.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShouldRemoveHandlersNotInOS() {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't do this on Linux as the OS registration there is not reliable,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and Chrome OS doesn't have any notion of OS registration.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(benwells): When Linux support is more reliable remove this
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // difference (http://crbug.com/88255).
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ShellIntegration::CanSetAsDefaultProtocolClient() !=
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ShellIntegration::SET_DEFAULT_NOT_ALLOWED;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// IOThreadDelegate ------------------------------------------------------------
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// IOThreadDelegate is an IO thread specific object. Access to the class should
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// all be done via the IO thread. The registry living on the UI thread makes
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a best effort to update the IO object after local updates are completed.
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ProtocolHandlerRegistry::IOThreadDelegate
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : public base::RefCountedThreadSafe<
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          ProtocolHandlerRegistry::IOThreadDelegate> {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates a new instance. If |enabled| is true the registry is considered
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // enabled on the IO thread.
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  explicit IOThreadDelegate(bool enabled);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if the protocol has a default protocol handler.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Should be called only from the IO thread.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool IsHandledProtocol(const std::string& scheme) const;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clears the default for the provided protocol.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Should be called only from the IO thread.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ClearDefault(const std::string& scheme);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Makes this ProtocolHandler the default handler for its protocol.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Should be called only from the IO thread.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetDefault(const ProtocolHandler& handler);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates a URL request job for the given request if there is a matching
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // protocol handler, returns NULL otherwise.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::URLRequestJob* MaybeCreateJob(
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net::URLRequest* request, net::NetworkDelegate* network_delegate) const;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicate that the registry has been enabled in the IO thread's
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // copy of the data.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Enable() { enabled_ = true; }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicate that the registry has been disabled in the IO thread's copy of
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the data.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Disable() { enabled_ = false; }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  friend class base::RefCountedThreadSafe<IOThreadDelegate>;
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~IOThreadDelegate();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy of protocol handlers use only on the IO thread.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerRegistry::ProtocolHandlerMap default_handlers_;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Is the registry enabled on the IO thread.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool enabled_;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(IOThreadDelegate);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProtocolHandlerRegistry::IOThreadDelegate::IOThreadDelegate(bool)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : enabled_(true) {}
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProtocolHandlerRegistry::IOThreadDelegate::~IOThreadDelegate() {}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ProtocolHandlerRegistry::IOThreadDelegate::IsHandledProtocol(
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& scheme) const {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return enabled_ && !LookupHandler(default_handlers_, scheme).IsEmpty();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault(
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& scheme) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default_handlers_.erase(scheme);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ProtocolHandlerRegistry::IOThreadDelegate::SetDefault(
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ProtocolHandler& handler) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClearDefault(handler.protocol());
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default_handlers_.insert(std::make_pair(handler.protocol(), handler));
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Create a new job for the supplied |URLRequest| if a default handler
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is registered and the associated handler is able to interpret
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the url from |request|.
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)net::URLRequestJob* ProtocolHandlerRegistry::IOThreadDelegate::MaybeCreateJob(
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandler handler = LookupHandler(default_handlers_,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          request->url().scheme());
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handler.IsEmpty())
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL translated_url(handler.TranslateUrl(request->url()));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!translated_url.is_valid())
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new net::URLRequestRedirectJob(
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      request, network_delegate, translated_url,
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      net::URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT,
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Protocol Handler Registry");
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// JobInterceptorFactory -------------------------------------------------------
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Instances of JobInterceptorFactory are produced for ownership by the IO
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread where it handler URL requests. We should never hold
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// any pointers on this class, only produce them in response to
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// requests via |ProtocolHandlerRegistry::CreateJobInterceptorFactory|.
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProtocolHandlerRegistry::JobInterceptorFactory::JobInterceptorFactory(
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IOThreadDelegate* io_thread_delegate)
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : io_thread_delegate_(io_thread_delegate) {
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(io_thread_delegate_.get());
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DetachFromThread();
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ProtocolHandlerRegistry::JobInterceptorFactory::Chain(
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<net::URLRequestJobFactory> job_factory) {
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  job_factory_ = job_factory.Pass();
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)net::URLRequestJob*
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProtocolHandlerRegistry::JobInterceptorFactory::
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MaybeCreateJobWithProtocolHandler(
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& scheme,
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLRequest* request,
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::NetworkDelegate* network_delegate) const {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::URLRequestJob* job = io_thread_delegate_->MaybeCreateJob(
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      request, network_delegate);
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (job)
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return job;
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return job_factory_->MaybeCreateJobWithProtocolHandler(
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scheme, request, network_delegate);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledProtocol(
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& scheme) const {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return io_thread_delegate_->IsHandledProtocol(scheme) ||
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      job_factory_->IsHandledProtocol(scheme);
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledURL(
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& url) const {
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (url.is_valid() &&
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      io_thread_delegate_->IsHandledProtocol(url.scheme())) ||
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      job_factory_->IsHandledURL(url);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
208b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool ProtocolHandlerRegistry::JobInterceptorFactory::IsSafeRedirectTarget(
209b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    const GURL& location) const {
210b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
211b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return job_factory_->IsSafeRedirectTarget(location);
212b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
213b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DefaultClientObserver ------------------------------------------------------
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver(
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProtocolHandlerRegistry* registry)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : worker_(NULL),
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      registry_(registry) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(registry_);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (worker_)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    worker_->ObserverDestroyed();
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DefaultClientObserverList::iterator iter = std::find(
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      registry_->default_client_observers_.begin(),
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      registry_->default_client_observers_.end(), this);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registry_->default_client_observers_.erase(iter);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState(
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ShellIntegration::DefaultWebClientUIState state) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (worker_) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ShouldRemoveHandlersNotInOS() &&
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (state == ShellIntegration::STATE_NOT_DEFAULT)) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      registry_->ClearDefault(worker_->protocol());
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProtocolHandlerRegistry::DefaultClientObserver::
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IsInteractiveSetDefaultPermitted() {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker(
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ShellIntegration::DefaultProtocolClientWorker* worker) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  worker_ = worker;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProtocolHandlerRegistry::DefaultClientObserver::IsOwnedByWorker() {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Delegate --------------------------------------------------------------------
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::Delegate::~Delegate() {}
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler(
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& protocol) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ChildProcessSecurityPolicy* policy =
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ChildProcessSecurityPolicy::GetInstance();
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!policy->IsWebSafeScheme(protocol)) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    policy->RegisterWebSafeScheme(protocol);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& protocol) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered(
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& protocol) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE(koz): This function is safe to call from any thread, despite living
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in ProfileIOData.
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ProfileIOData::IsHandledProtocol(protocol);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellIntegration::DefaultProtocolClientWorker*
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::Delegate::CreateShellWorker(
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ShellIntegration::DefaultWebClientObserver* observer,
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& protocol) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::DefaultClientObserver*
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::Delegate::CreateShellObserver(
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProtocolHandlerRegistry* registry) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new DefaultClientObserver(registry);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient(
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& protocol, ProtocolHandlerRegistry* registry) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DefaultClientObserver* observer = CreateShellObserver(registry);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The worker pointer is reference counted. While it is running the
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // message loops of the FILE and UI thread will hold references to it
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and it will be automatically freed once all its tasks have finished.
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  worker = CreateShellWorker(observer, protocol);
304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  observer->SetWorker(worker.get());
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registry->default_client_observers_.push_back(observer);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  worker->StartSetAsDefault();
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ProtocolHandlerRegistry -----------------------------------------------------
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ProtocolHandlerRegistry::ProtocolHandlerRegistry(
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    content::BrowserContext* context, Delegate* delegate)
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : context_(context),
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_(delegate),
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      enabled_(true),
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_loading_(false),
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_loaded_(false),
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      io_thread_delegate_(new IOThreadDelegate(enabled_)){
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest(
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandler& handler) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol()))
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler))
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AttemptReplace(handler))
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler(
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandler& handler) {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
33846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RegisterProtocolHandler(handler, USER);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetDefault(handler);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Save();
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyChanged();
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandler& handler) {
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
34746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RegisterProtocolHandler(handler, USER);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Save();
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyChanged();
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandler& handler) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
35546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  IgnoreProtocolHandler(handler, USER);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Save();
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyChanged();
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandler old_default = GetHandlerFor(handler.protocol());
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool make_new_handler_default = handler.IsSameOrigin(old_default);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerList to_replace(GetReplacedHandlers(handler));
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (to_replace.empty())
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ProtocolHandlerList::iterator p = to_replace.begin();
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       p != to_replace.end(); ++p) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RemoveHandler(*p);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (make_new_handler_default) {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnAcceptRegisterProtocolHandler(handler);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InsertHandler(handler);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyChanged();
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::ProtocolHandlerList
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::GetReplacedHandlers(
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandler& handler) const {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerList replaced_handlers;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!handlers)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return replaced_handlers;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ProtocolHandlerList::const_iterator p = handlers->begin();
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       p != handlers->end(); p++) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (handler.IsSameOrigin(*p)) {
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      replaced_handlers.push_back(*p);
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return replaced_handlers;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) {
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default_handlers_.erase(scheme);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO,
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_, scheme));
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Save();
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyChanged();
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProtocolHandlerRegistry::IsDefault(
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandler& handler) const {
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetHandlerFor(handler.protocol()) == handler;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::InstallDefaultsForChromeOS() {
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only chromeos has default protocol handlers at this point.
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddPredefinedHandler(
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProtocolHandler::CreateProtocolHandler(
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "mailto",
420cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_MAILTO_HANDLER_URL))));
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddPredefinedHandler(
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProtocolHandler::CreateProtocolHandler(
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "webcal",
424cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL))));
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();  // this method should only ever be called in chromeos.
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::InitProtocolSettings() {
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Any further default additions to the table will get rejected from now on.
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_loaded_ = true;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_loading_ = true;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  PrefService* prefs = user_prefs::UserPrefs::Get(context_);
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) {
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (prefs->GetBoolean(prefs::kCustomHandlersEnabled)) {
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Enable();
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Disable();
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
44546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
44646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RegisterProtocolHandlersFromPref(prefs::kPolicyRegisteredProtocolHandlers,
44746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   POLICY);
44846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RegisterProtocolHandlersFromPref(prefs::kRegisteredProtocolHandlers, USER);
44946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  IgnoreProtocolHandlersFromPref(prefs::kPolicyIgnoredProtocolHandlers, POLICY);
45046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  IgnoreProtocolHandlersFromPref(prefs::kIgnoredProtocolHandlers, USER);
45146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_loading_ = false;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For each default protocol handler, check that we are still registered
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with the OS as the default application.
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ShouldRemoveHandlersNotInOS()) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (ProtocolHandlerMap::const_iterator p = default_handlers_.begin();
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         p != default_handlers_.end(); ++p) {
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProtocolHandler handler = p->second;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DefaultClientObserver* observer = delegate_->CreateShellObserver(this);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      worker = delegate_->CreateShellWorker(observer, handler.protocol());
463868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      observer->SetWorker(worker.get());
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default_client_observers_.push_back(observer);
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      worker->StartCheckIsDefault();
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const {
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ProtocolHandler& handler = GetHandlerFor(scheme);
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handler.IsEmpty())
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ProtocolHandlerList* handlers = GetHandlerList(scheme);
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!handlers)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerList::const_iterator p;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) {
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (*p == handler)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i;
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::ProtocolHandlerList
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::GetHandlersFor(
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& scheme) const {
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (p == protocol_handlers_.end()) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ProtocolHandlerList();
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return p->second;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::ProtocolHandlerList
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::GetIgnoredHandlers() {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ignored_protocol_handlers_;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::GetRegisteredProtocols(
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string>* output) const {
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerMultiMap::const_iterator p;
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!p->second.empty())
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      output->push_back(p->first);
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProtocolHandlerRegistry::CanSchemeBeOverridden(
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& scheme) const {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ProtocolHandlerList* handlers = GetHandlerList(scheme);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we already have a handler for this scheme, we can add more.
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handlers != NULL && !handlers->empty())
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't override a scheme if it already has an external handler.
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !delegate_->IsExternalHandlerRegistered(scheme);
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProtocolHandlerRegistry::IsRegistered(
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandler& handler) const {
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!handlers) {
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::find(handlers->begin(), handlers->end(), handler) !=
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handlers->end();
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ProtocolHandlerRegistry::IsRegisteredByUser(
5371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const ProtocolHandler& handler) {
5381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return HandlerExists(handler, &user_protocol_handlers_);
5391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
5401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ProtocolHandlerRegistry::HasPolicyRegisteredHandler(
5421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& scheme) {
5431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return (policy_protocol_handlers_.find(scheme) !=
5441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          policy_protocol_handlers_.end());
5451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
5461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const {
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerList::const_iterator i;
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = ignored_protocol_handlers_.begin();
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != ignored_protocol_handlers_.end(); ++i) {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (*i == handler) {
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProtocolHandlerRegistry::HasRegisteredEquivalent(
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandler& handler) const {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!handlers) {
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerList::const_iterator i;
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = handlers->begin(); i != handlers->end(); ++i) {
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (handler.IsEquivalent(*i)) {
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProtocolHandlerRegistry::HasIgnoredEquivalent(
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandler& handler) const {
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerList::const_iterator i;
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = ignored_protocol_handlers_.begin();
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != ignored_protocol_handlers_.end(); ++i) {
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (handler.IsEquivalent(*i)) {
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::RemoveIgnoredHandler(
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandler& handler) {
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool should_notify = false;
59246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (HandlerExists(handler, ignored_protocol_handlers_) &&
59346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      HandlerExists(handler, user_ignored_protocol_handlers_)) {
59446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    EraseHandler(handler, &user_ignored_protocol_handlers_);
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Save();
59646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!HandlerExists(handler, policy_ignored_protocol_handlers_)) {
59746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      EraseHandler(handler, &ignored_protocol_handlers_);
59846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      should_notify = true;
59946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (should_notify)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyChanged();
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProtocolHandlerRegistry::IsHandledProtocol(
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& scheme) const {
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return enabled_ && !GetHandlerFor(scheme).IsEmpty();
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::RemoveHandler(
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandler& handler) {
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()];
61546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  bool erase_success = false;
61646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (HandlerExists(handler, handlers) &&
61746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      HandlerExists(handler, &user_protocol_handlers_)) {
61846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    EraseHandler(handler, &user_protocol_handlers_);
6191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    erase_success = true;
6201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!HandlerExists(handler, &policy_protocol_handlers_))
62146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      EraseHandler(handler, &protocol_handlers_);
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol());
62446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (erase_success && q != default_handlers_.end() && q->second == handler) {
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make the new top handler in the list the default.
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!handlers.empty()) {
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // NOTE We pass a copy because SetDefault() modifies handlers.
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetDefault(ProtocolHandler(handlers[0]));
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::PostTask(
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          BrowserThread::IO, FROM_HERE,
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_,
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     q->second.protocol()));
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default_handlers_.erase(q);
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
63946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (erase_success && !IsHandledProtocol(handler.protocol())) {
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->DeregisterExternalHandler(handler.protocol());
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Save();
64346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (erase_success)
64446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    NotifyChanged();
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) {
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandler current_default = GetHandlerFor(scheme);
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!current_default.IsEmpty())
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RemoveHandler(current_default);
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor(
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& scheme) const {
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return LookupHandler(default_handlers_, scheme);
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::Enable() {
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (enabled_) {
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enabled_ = true;
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO,
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&IOThreadDelegate::Enable, io_thread_delegate_));
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerMap::const_iterator p;
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->RegisterExternalHandler(p->first);
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Save();
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyChanged();
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::Disable() {
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!enabled_) {
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enabled_ = false;
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO,
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&IOThreadDelegate::Disable, io_thread_delegate_));
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerMap::const_iterator p;
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->DeregisterExternalHandler(p->first);
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Save();
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyChanged();
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::Shutdown() {
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_.reset(NULL);
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We free these now in case there are any outstanding workers running. If
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we didn't free them they could respond to workers and try to update the
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // protocol handler registry after it was deleted.
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Observers remove themselves from this list when they are deleted; so
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we delete the last item until none are left in the list.
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!default_client_observers_.empty()) {
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete default_client_observers_.back();
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
7127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ProtocolHandlerRegistry::RegisterProfilePrefs(
713c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    user_prefs::PrefRegistrySyncable* registry) {
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registry->RegisterListPref(prefs::kRegisteredProtocolHandlers,
715c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registry->RegisterListPref(prefs::kIgnoredProtocolHandlers,
717c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
71846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  registry->RegisterListPref(prefs::kPolicyRegisteredProtocolHandlers,
71946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
72046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  registry->RegisterListPref(prefs::kPolicyIgnoredProtocolHandlers,
72146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
722c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  registry->RegisterBooleanPref(
723c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      prefs::kCustomHandlersEnabled,
724c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      true,
725c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(default_client_observers_.empty());
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) {
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsRegistered(handler));
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerMultiMap::iterator p =
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      protocol_handlers_.find(handler.protocol());
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerList& list = p->second;
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  list.erase(std::find(list.begin(), list.end(), handler));
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  list.insert(list.begin(), handler);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::Save() {
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_loading_) {
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::Value> registered_protocol_handlers(
7495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      EncodeRegisteredHandlers());
7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::Value> ignored_protocol_handlers(EncodeIgnoredHandlers());
7515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  PrefService* prefs = user_prefs::UserPrefs::Get(context_);
7525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  prefs->Set(prefs::kRegisteredProtocolHandlers,
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *registered_protocol_handlers);
7555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  prefs->Set(prefs::kIgnoredProtocolHandlers,
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *ignored_protocol_handlers);
7575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  prefs->SetBoolean(prefs::kCustomHandlersEnabled, enabled_);
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const ProtocolHandlerRegistry::ProtocolHandlerList*
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::GetHandlerList(
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& scheme) const {
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (p == protocol_handlers_.end()) {
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &p->second;
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) {
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerMap::const_iterator p = default_handlers_.find(
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handler.protocol());
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're not loading, and we are setting a default for a new protocol,
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // register with the OS.
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_loading_ && p == default_handlers_.end())
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this);
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default_handlers_.erase(handler.protocol());
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default_handlers_.insert(std::make_pair(handler.protocol(), handler));
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PromoteHandler(handler);
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO,
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
7852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&IOThreadDelegate::SetDefault, io_thread_delegate_, handler));
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) {
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerMultiMap::iterator p =
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      protocol_handlers_.find(handler.protocol());
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (p != protocol_handlers_.end()) {
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->second.push_back(handler);
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProtocolHandlerList new_list;
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_list.push_back(handler);
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  protocol_handlers_[handler.protocol()] = new_list;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() {
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ListValue* protocol_handlers = new base::ListValue();
80646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (ProtocolHandlerMultiMap::iterator i = user_protocol_handlers_.begin();
80746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       i != user_protocol_handlers_.end();
80846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       ++i) {
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (ProtocolHandlerList::iterator j = i->second.begin();
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         j != i->second.end(); ++j) {
8115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::DictionaryValue* encoded = j->Encode();
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (IsDefault(*j)) {
813116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        encoded->Set("default", new base::FundamentalValue(true));
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      protocol_handlers->Append(encoded);
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return protocol_handlers;
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ListValue* handlers = new base::ListValue();
82446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (ProtocolHandlerList::iterator i =
82546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)           user_ignored_protocol_handlers_.begin();
82646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       i != user_ignored_protocol_handlers_.end();
82746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       ++i) {
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handlers->Append(i->Encode());
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handlers;
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::NotifyChanged() {
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationService::current()->Notify(
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
8375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      content::Source<content::BrowserContext>(context_),
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::NotificationService::NoDetails());
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::RegisterProtocolHandler(
84246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const ProtocolHandler& handler,
84346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const HandlerSource source) {
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CanSchemeBeOverridden(handler.protocol()));
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!handler.IsEmpty());
84746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ProtocolHandlerMultiMap& map =
84846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      (source == POLICY) ? policy_protocol_handlers_ : user_protocol_handlers_;
84946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ProtocolHandlerList& list = map[handler.protocol()];
85046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!HandlerExists(handler, list))
85146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    list.push_back(handler);
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsRegistered(handler)) {
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol()))
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->RegisterExternalHandler(handler.protocol());
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InsertHandler(handler);
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::vector<const base::DictionaryValue*>
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const {
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<const base::DictionaryValue*> result;
8645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  PrefService* prefs = user_prefs::UserPrefs::Get(context_);
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!prefs->HasPrefPath(pref_name)) {
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::ListValue* handlers = prefs->GetList(pref_name);
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handlers) {
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < handlers->GetSize(); ++i) {
8725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::DictionaryValue* dict;
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!handlers->GetDictionary(i, &dict))
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (ProtocolHandler::IsValidDict(dict)) {
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result.push_back(dict);
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
88346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ProtocolHandlerRegistry::RegisterProtocolHandlersFromPref(
88446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const char* pref_name,
88546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const HandlerSource source) {
88646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::vector<const base::DictionaryValue*> registered_handlers =
88746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      GetHandlersFromPref(pref_name);
88846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (std::vector<const base::DictionaryValue*>::const_iterator p =
88946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)           registered_handlers.begin();
89046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       p != registered_handlers.end();
89146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       ++p) {
89246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p);
89346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    RegisterProtocolHandler(handler, source);
89446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    bool is_default = false;
89546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if ((*p)->GetBoolean("default", &is_default) && is_default) {
89646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      SetDefault(handler);
89746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
89846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
89946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
90046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::IgnoreProtocolHandler(
90246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const ProtocolHandler& handler,
90346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const HandlerSource source) {
90446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ProtocolHandlerList& list = (source == POLICY)
90646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                  ? policy_ignored_protocol_handlers_
90746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                  : user_ignored_protocol_handlers_;
90846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!HandlerExists(handler, list))
90946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    list.push_back(handler);
91046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (HandlerExists(handler, ignored_protocol_handlers_))
91146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ignored_protocol_handlers_.push_back(handler);
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
91546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ProtocolHandlerRegistry::IgnoreProtocolHandlersFromPref(
91646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const char* pref_name,
91746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const HandlerSource source) {
91846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::vector<const base::DictionaryValue*> ignored_handlers =
91946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      GetHandlersFromPref(pref_name);
92046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (std::vector<const base::DictionaryValue*>::const_iterator p =
92146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)           ignored_handlers.begin();
92246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       p != ignored_handlers.end();
92346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       ++p) {
92446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p), source);
92546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
92646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
92746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
92846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
92946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                            ProtocolHandlerMultiMap* map) {
93046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return HandlerExists(handler, (*map)[handler.protocol()]);
93146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
93246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
93346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
93446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                            const ProtocolHandlerList& list) {
93546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return std::find(list.begin(), list.end(), handler) != list.end();
93646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
93746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
93846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
93946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                           ProtocolHandlerMultiMap* map) {
94046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EraseHandler(handler, &(*map)[handler.protocol()]);
94146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
94246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
94346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
94446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                           ProtocolHandlerList* list) {
94546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  list->erase(std::find(list->begin(), list->end(), handler));
94646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
94746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProtocolHandlerRegistry::AddPredefinedHandler(
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProtocolHandler& handler) {
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!is_loaded_);  // Must be called prior InitProtocolSettings.
95146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RegisterProtocolHandler(handler, USER);
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetDefault(handler);
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
9562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProtocolHandlerRegistry::CreateJobInterceptorFactory() {
957