protocol_handler_registry.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <utility>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/command_line.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/logging.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/pref_service.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/chrome_notification_types.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/net/chrome_url_request_context.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/profiles/profile_io_data.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/custom_handlers/protocol_handler.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/pref_names.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/child_process_security_policy.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "grit/generated_resources.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/base/network_delegate.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/url_request/url_request_redirect_job.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using content::BrowserThread;
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using content::ChildProcessSecurityPolicy;
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const ProtocolHandler& LookupHandler(
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map,
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& scheme) {
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p =
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      handler_map.find(scheme);
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (p != handler_map.end())
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return p->second;
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ProtocolHandler::EmptyProtocolHandler();
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// If true default protocol handlers will be removed if the OS level
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// registration for a protocol is no longer Chrome.
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShouldRemoveHandlersNotInOS() {
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_LINUX)
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // We don't do this on Linux as the OS registration there is not reliable,
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // and Chrome OS doesn't have any notion of OS registration.
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(benwells): When Linux support is more reliable remove this
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // difference (http://crbug.com/88255).
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ShellIntegration::CanSetAsDefaultProtocolClient() !=
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ShellIntegration::SET_DEFAULT_NOT_ALLOWED;
566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#endif
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// IOThreadDelegate ------------------------------------------------------------
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// IOThreadDelegate is an IO thread specific object. Access to the class should
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// all be done via the IO thread. The registry living on the UI thread makes
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// a best effort to update the IO object after local updates are completed.
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class ProtocolHandlerRegistry::IOThreadDelegate
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : public base::RefCountedThreadSafe<
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          ProtocolHandlerRegistry::IOThreadDelegate> {
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Creates a new instance. If |enabled| is true the registry is considered
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // enabled on the IO thread.
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  explicit IOThreadDelegate(bool enabled);
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Returns true if the protocol has a default protocol handler.
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Should be called only from the IO thread.
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool IsHandledProtocol(const std::string& scheme) const;
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Clears the default for the provided protocol.
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Should be called only from the IO thread.
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void ClearDefault(const std::string& scheme);
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Makes this ProtocolHandler the default handler for its protocol.
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Should be called only from the IO thread.
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void SetDefault(const ProtocolHandler& handler);
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Creates a URL request job for the given request if there is a matching
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // protocol handler, returns NULL otherwise.
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  net::URLRequestJob* MaybeCreateJob(
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      net::URLRequest* request, net::NetworkDelegate* network_delegate) const;
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Indicate that the registry has been enabled in the IO thread's
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // copy of the data.
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Enable() { enabled_ = true; }
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Indicate that the registry has been disabled in the IO thread's copy of
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the data.
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Disable() { enabled_ = false; }
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  friend class base::RefCountedThreadSafe<IOThreadDelegate>;
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~IOThreadDelegate();
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Copy of protocol handlers use only on the IO thread.
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProtocolHandlerRegistry::ProtocolHandlerMap default_handlers_;
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Is the registry enabled on the IO thread.
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool enabled_;
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(IOThreadDelegate);
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::IOThreadDelegate::IOThreadDelegate(bool)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : enabled_(true) {}
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::IOThreadDelegate::~IOThreadDelegate() {}
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ProtocolHandlerRegistry::IOThreadDelegate::IsHandledProtocol(
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& scheme) const {
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return enabled_ && !LookupHandler(default_handlers_, scheme).IsEmpty();
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault(
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& scheme) {
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  default_handlers_.erase(scheme);
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ProtocolHandlerRegistry::IOThreadDelegate::SetDefault(
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ProtocolHandler& handler) {
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ClearDefault(handler.protocol());
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  default_handlers_.insert(std::make_pair(handler.protocol(), handler));
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Create a new job for the supplied |URLRequest| if a default handler
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// is registered and the associated handler is able to interpret
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the url from |request|.
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)net::URLRequestJob* ProtocolHandlerRegistry::IOThreadDelegate::MaybeCreateJob(
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProtocolHandler handler = LookupHandler(default_handlers_,
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          request->url().scheme());
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (handler.IsEmpty())
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NULL;
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GURL translated_url(handler.TranslateUrl(request->url()));
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!translated_url.is_valid())
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NULL;
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return new net::URLRequestRedirectJob(
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      request, network_delegate, translated_url,
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      net::URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT,
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Protocol Handler Registry");
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// JobInterceptorFactory -------------------------------------------------------
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Instances of JobInterceptorFactory are produced for ownership by the IO
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// thread where it handler URL requests. We should never hold
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// any pointers on this class, only produce them in response to
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// requests via |ProtocolHandlerRegistry::CreateJobInterceptorFactory|.
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::JobInterceptorFactory::JobInterceptorFactory(
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IOThreadDelegate* io_thread_delegate)
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : io_thread_delegate_(io_thread_delegate) {
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(io_thread_delegate_.get());
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DetachFromThread();
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() {
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ProtocolHandlerRegistry::JobInterceptorFactory::Chain(
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<net::URLRequestJobFactory> job_factory) {
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  job_factory_ = job_factory.Pass();
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)net::URLRequestJob*
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::JobInterceptorFactory::
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MaybeCreateJobWithProtocolHandler(
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& scheme,
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    net::URLRequest* request,
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    net::NetworkDelegate* network_delegate) const {
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  net::URLRequestJob* job = io_thread_delegate_->MaybeCreateJob(
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      request, network_delegate);
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (job)
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return job;
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return job_factory_->MaybeCreateJobWithProtocolHandler(
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scheme, request, network_delegate);
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledProtocol(
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& scheme) const {
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return io_thread_delegate_->IsHandledProtocol(scheme) ||
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      job_factory_->IsHandledProtocol(scheme);
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledURL(
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const GURL& url) const {
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return (url.is_valid() &&
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      io_thread_delegate_->IsHandledProtocol(url.scheme())) ||
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      job_factory_->IsHandledURL(url);
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ProtocolHandlerRegistry::JobInterceptorFactory::IsSafeRedirectTarget(
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const GURL& location) const {
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return job_factory_->IsSafeRedirectTarget(location);
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// DefaultClientObserver ------------------------------------------------------
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver(
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ProtocolHandlerRegistry* registry)
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : worker_(NULL),
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      registry_(registry) {
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(registry_);
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() {
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (worker_)
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    worker_->ObserverDestroyed();
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DefaultClientObserverList::iterator iter = std::find(
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      registry_->default_client_observers_.begin(),
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      registry_->default_client_observers_.end(), this);
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registry_->default_client_observers_.erase(iter);
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState(
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShellIntegration::DefaultWebClientUIState state) {
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (worker_) {
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (ShouldRemoveHandlersNotInOS() &&
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        (state == ShellIntegration::STATE_NOT_DEFAULT)) {
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      registry_->ClearDefault(worker_->protocol());
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    NOTREACHED();
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ProtocolHandlerRegistry::DefaultClientObserver::
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IsInteractiveSetDefaultPermitted() {
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker(
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShellIntegration::DefaultProtocolClientWorker* worker) {
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  worker_ = worker;
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ProtocolHandlerRegistry::DefaultClientObserver::IsOwnedByWorker() {
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Delegate --------------------------------------------------------------------
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::Delegate::~Delegate() {}
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler(
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& protocol) {
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ChildProcessSecurityPolicy* policy =
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ChildProcessSecurityPolicy::GetInstance();
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!policy->IsWebSafeScheme(protocol)) {
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    policy->RegisterWebSafeScheme(protocol);
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& protocol) {
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered(
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& protocol) {
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // NOTE(koz): This function is safe to call from any thread, despite living
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // in ProfileIOData.
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ProfileIOData::IsHandledProtocol(protocol);
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ShellIntegration::DefaultProtocolClientWorker*
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::Delegate::CreateShellWorker(
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShellIntegration::DefaultWebClientObserver* observer,
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& protocol) {
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol);
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::DefaultClientObserver*
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::Delegate::CreateShellObserver(
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ProtocolHandlerRegistry* registry) {
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return new DefaultClientObserver(registry);
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient(
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& protocol, ProtocolHandlerRegistry* registry) {
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DefaultClientObserver* observer = CreateShellObserver(registry);
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The worker pointer is reference counted. While it is running the
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // message loops of the FILE and UI thread will hold references to it
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // and it will be automatically freed once all its tasks have finished.
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker;
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  worker = CreateShellWorker(observer, protocol);
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  observer->SetWorker(worker.get());
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registry->default_client_observers_.push_back(observer);
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  worker->StartSetAsDefault();
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// ProtocolHandlerRegistry -----------------------------------------------------
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile,
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Delegate* delegate)
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : profile_(profile),
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delegate_(delegate),
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      enabled_(true),
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      is_loading_(false),
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      is_loaded_(false),
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      io_thread_delegate_(new IOThreadDelegate(enabled_)){
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest(
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ProtocolHandler& handler) {
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol()))
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler))
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (AttemptReplace(handler))
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler(
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ProtocolHandler& handler) {
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RegisterProtocolHandler(handler, USER);
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetDefault(handler);
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Save();
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NotifyChanged();
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ProtocolHandler& handler) {
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RegisterProtocolHandler(handler, USER);
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Save();
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NotifyChanged();
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ProtocolHandler& handler) {
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IgnoreProtocolHandler(handler, USER);
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Save();
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NotifyChanged();
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) {
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProtocolHandler old_default = GetHandlerFor(handler.protocol());
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool make_new_handler_default = handler.IsSameOrigin(old_default);
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProtocolHandlerList to_replace(GetReplacedHandlers(handler));
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (to_replace.empty())
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (ProtocolHandlerList::iterator p = to_replace.begin();
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       p != to_replace.end(); ++p) {
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RemoveHandler(*p);
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (make_new_handler_default) {
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnAcceptRegisterProtocolHandler(handler);
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    InsertHandler(handler);
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    NotifyChanged();
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ProtocolHandlerRegistry::ProtocolHandlerList
382ProtocolHandlerRegistry::GetReplacedHandlers(
383    const ProtocolHandler& handler) const {
384  ProtocolHandlerList replaced_handlers;
385  const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
386  if (!handlers)
387    return replaced_handlers;
388  for (ProtocolHandlerList::const_iterator p = handlers->begin();
389       p != handlers->end(); p++) {
390    if (handler.IsSameOrigin(*p)) {
391      replaced_handlers.push_back(*p);
392    }
393  }
394  return replaced_handlers;
395}
396
397void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) {
398  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
399
400  default_handlers_.erase(scheme);
401  BrowserThread::PostTask(
402      BrowserThread::IO,
403      FROM_HERE,
404      base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_, scheme));
405  Save();
406  NotifyChanged();
407}
408
409bool ProtocolHandlerRegistry::IsDefault(
410    const ProtocolHandler& handler) const {
411  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
412  return GetHandlerFor(handler.protocol()) == handler;
413}
414
415void ProtocolHandlerRegistry::InstallDefaultsForChromeOS() {
416#if defined(OS_CHROMEOS)
417  // Only chromeos has default protocol handlers at this point.
418  AddPredefinedHandler(
419      ProtocolHandler::CreateProtocolHandler(
420          "mailto",
421          GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_MAILTO_HANDLER_URL))));
422  AddPredefinedHandler(
423      ProtocolHandler::CreateProtocolHandler(
424          "webcal",
425          GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL))));
426#else
427  NOTREACHED();  // this method should only ever be called in chromeos.
428#endif
429}
430
431void ProtocolHandlerRegistry::InitProtocolSettings() {
432  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
433
434  // Any further default additions to the table will get rejected from now on.
435  is_loaded_ = true;
436  is_loading_ = true;
437
438  PrefService* prefs = profile_->GetPrefs();
439  if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) {
440    if (prefs->GetBoolean(prefs::kCustomHandlersEnabled)) {
441      Enable();
442    } else {
443      Disable();
444    }
445  }
446
447  RegisterProtocolHandlersFromPref(prefs::kPolicyRegisteredProtocolHandlers,
448                                   POLICY);
449  RegisterProtocolHandlersFromPref(prefs::kRegisteredProtocolHandlers, USER);
450  IgnoreProtocolHandlersFromPref(prefs::kPolicyIgnoredProtocolHandlers, POLICY);
451  IgnoreProtocolHandlersFromPref(prefs::kIgnoredProtocolHandlers, USER);
452
453  is_loading_ = false;
454
455  // For each default protocol handler, check that we are still registered
456  // with the OS as the default application.
457  if (ShouldRemoveHandlersNotInOS()) {
458    for (ProtocolHandlerMap::const_iterator p = default_handlers_.begin();
459         p != default_handlers_.end(); ++p) {
460      ProtocolHandler handler = p->second;
461      DefaultClientObserver* observer = delegate_->CreateShellObserver(this);
462      scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker;
463      worker = delegate_->CreateShellWorker(observer, handler.protocol());
464      observer->SetWorker(worker.get());
465      default_client_observers_.push_back(observer);
466      worker->StartCheckIsDefault();
467    }
468  }
469}
470
471int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const {
472  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
473  const ProtocolHandler& handler = GetHandlerFor(scheme);
474  if (handler.IsEmpty())
475    return -1;
476  const ProtocolHandlerList* handlers = GetHandlerList(scheme);
477  if (!handlers)
478    return -1;
479
480  ProtocolHandlerList::const_iterator p;
481  int i;
482  for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) {
483    if (*p == handler)
484      return i;
485  }
486  return -1;
487}
488
489ProtocolHandlerRegistry::ProtocolHandlerList
490ProtocolHandlerRegistry::GetHandlersFor(
491    const std::string& scheme) const {
492  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
493  ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
494  if (p == protocol_handlers_.end()) {
495    return ProtocolHandlerList();
496  }
497  return p->second;
498}
499
500ProtocolHandlerRegistry::ProtocolHandlerList
501ProtocolHandlerRegistry::GetIgnoredHandlers() {
502  return ignored_protocol_handlers_;
503}
504
505void ProtocolHandlerRegistry::GetRegisteredProtocols(
506    std::vector<std::string>* output) const {
507  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
508  ProtocolHandlerMultiMap::const_iterator p;
509  for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) {
510    if (!p->second.empty())
511      output->push_back(p->first);
512  }
513}
514
515bool ProtocolHandlerRegistry::CanSchemeBeOverridden(
516    const std::string& scheme) const {
517  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
518  const ProtocolHandlerList* handlers = GetHandlerList(scheme);
519  // If we already have a handler for this scheme, we can add more.
520  if (handlers != NULL && !handlers->empty())
521    return true;
522  // Don't override a scheme if it already has an external handler.
523  return !delegate_->IsExternalHandlerRegistered(scheme);
524}
525
526bool ProtocolHandlerRegistry::IsRegistered(
527    const ProtocolHandler& handler) const {
528  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
529  const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
530  if (!handlers) {
531    return false;
532  }
533  return std::find(handlers->begin(), handlers->end(), handler) !=
534      handlers->end();
535}
536
537bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const {
538  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
539  ProtocolHandlerList::const_iterator i;
540  for (i = ignored_protocol_handlers_.begin();
541       i != ignored_protocol_handlers_.end(); ++i) {
542    if (*i == handler) {
543      return true;
544    }
545  }
546  return false;
547}
548
549bool ProtocolHandlerRegistry::HasRegisteredEquivalent(
550    const ProtocolHandler& handler) const {
551  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
552  const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
553  if (!handlers) {
554    return false;
555  }
556  ProtocolHandlerList::const_iterator i;
557  for (i = handlers->begin(); i != handlers->end(); ++i) {
558    if (handler.IsEquivalent(*i)) {
559      return true;
560    }
561  }
562  return false;
563}
564
565bool ProtocolHandlerRegistry::HasIgnoredEquivalent(
566    const ProtocolHandler& handler) const {
567  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
568  ProtocolHandlerList::const_iterator i;
569  for (i = ignored_protocol_handlers_.begin();
570       i != ignored_protocol_handlers_.end(); ++i) {
571    if (handler.IsEquivalent(*i)) {
572      return true;
573    }
574  }
575  return false;
576}
577
578void ProtocolHandlerRegistry::RemoveIgnoredHandler(
579    const ProtocolHandler& handler) {
580  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
581  bool should_notify = false;
582  if (HandlerExists(handler, ignored_protocol_handlers_) &&
583      HandlerExists(handler, user_ignored_protocol_handlers_)) {
584    EraseHandler(handler, &user_ignored_protocol_handlers_);
585    Save();
586    if (!HandlerExists(handler, policy_ignored_protocol_handlers_)) {
587      EraseHandler(handler, &ignored_protocol_handlers_);
588      should_notify = true;
589    }
590  }
591  if (should_notify)
592    NotifyChanged();
593}
594
595bool ProtocolHandlerRegistry::IsHandledProtocol(
596    const std::string& scheme) const {
597  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
598  return enabled_ && !GetHandlerFor(scheme).IsEmpty();
599}
600
601void ProtocolHandlerRegistry::RemoveHandler(
602    const ProtocolHandler& handler) {
603  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
604  ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()];
605  bool erase_success = false;
606  if (HandlerExists(handler, handlers) &&
607      HandlerExists(handler, &user_protocol_handlers_)) {
608    EraseHandler(handler, &user_protocol_handlers_);
609    if (!HandlerExists(handler, &policy_protocol_handlers_)) {
610      erase_success = true;
611      EraseHandler(handler, &protocol_handlers_);
612    }
613  }
614  ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol());
615  if (erase_success && q != default_handlers_.end() && q->second == handler) {
616    // Make the new top handler in the list the default.
617    if (!handlers.empty()) {
618      // NOTE We pass a copy because SetDefault() modifies handlers.
619      SetDefault(ProtocolHandler(handlers[0]));
620    } else {
621      BrowserThread::PostTask(
622          BrowserThread::IO, FROM_HERE,
623          base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_,
624                     q->second.protocol()));
625
626      default_handlers_.erase(q);
627    }
628  }
629
630  if (erase_success && !IsHandledProtocol(handler.protocol())) {
631    delegate_->DeregisterExternalHandler(handler.protocol());
632  }
633  Save();
634  if (erase_success)
635    NotifyChanged();
636}
637
638void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) {
639  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
640  ProtocolHandler current_default = GetHandlerFor(scheme);
641  if (!current_default.IsEmpty())
642    RemoveHandler(current_default);
643}
644
645const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor(
646    const std::string& scheme) const {
647  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
648  return LookupHandler(default_handlers_, scheme);
649}
650
651void ProtocolHandlerRegistry::Enable() {
652  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
653  if (enabled_) {
654    return;
655  }
656  enabled_ = true;
657  BrowserThread::PostTask(
658      BrowserThread::IO,
659      FROM_HERE,
660      base::Bind(&IOThreadDelegate::Enable, io_thread_delegate_));
661
662  ProtocolHandlerMap::const_iterator p;
663  for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
664    delegate_->RegisterExternalHandler(p->first);
665  }
666  Save();
667  NotifyChanged();
668}
669
670void ProtocolHandlerRegistry::Disable() {
671  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
672  if (!enabled_) {
673    return;
674  }
675  enabled_ = false;
676  BrowserThread::PostTask(
677      BrowserThread::IO,
678      FROM_HERE,
679      base::Bind(&IOThreadDelegate::Disable, io_thread_delegate_));
680
681  ProtocolHandlerMap::const_iterator p;
682  for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
683    delegate_->DeregisterExternalHandler(p->first);
684  }
685  Save();
686  NotifyChanged();
687}
688
689void ProtocolHandlerRegistry::Shutdown() {
690  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
691  delegate_.reset(NULL);
692  // We free these now in case there are any outstanding workers running. If
693  // we didn't free them they could respond to workers and try to update the
694  // protocol handler registry after it was deleted.
695  // Observers remove themselves from this list when they are deleted; so
696  // we delete the last item until none are left in the list.
697  while (!default_client_observers_.empty()) {
698    delete default_client_observers_.back();
699  }
700}
701
702// static
703void ProtocolHandlerRegistry::RegisterProfilePrefs(
704    user_prefs::PrefRegistrySyncable* registry) {
705  registry->RegisterListPref(prefs::kRegisteredProtocolHandlers,
706                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
707  registry->RegisterListPref(prefs::kIgnoredProtocolHandlers,
708                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
709  registry->RegisterListPref(prefs::kPolicyRegisteredProtocolHandlers,
710                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
711  registry->RegisterListPref(prefs::kPolicyIgnoredProtocolHandlers,
712                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
713  registry->RegisterBooleanPref(
714      prefs::kCustomHandlersEnabled,
715      true,
716      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
717}
718
719ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
720  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
721  DCHECK(default_client_observers_.empty());
722}
723
724void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) {
725  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
726  DCHECK(IsRegistered(handler));
727  ProtocolHandlerMultiMap::iterator p =
728      protocol_handlers_.find(handler.protocol());
729  ProtocolHandlerList& list = p->second;
730  list.erase(std::find(list.begin(), list.end(), handler));
731  list.insert(list.begin(), handler);
732}
733
734void ProtocolHandlerRegistry::Save() {
735  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
736  if (is_loading_) {
737    return;
738  }
739  scoped_ptr<base::Value> registered_protocol_handlers(
740      EncodeRegisteredHandlers());
741  scoped_ptr<base::Value> ignored_protocol_handlers(EncodeIgnoredHandlers());
742  scoped_ptr<base::Value> enabled(base::Value::CreateBooleanValue(enabled_));
743  profile_->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers,
744      *registered_protocol_handlers);
745  profile_->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers,
746      *ignored_protocol_handlers);
747  profile_->GetPrefs()->Set(prefs::kCustomHandlersEnabled, *enabled);
748}
749
750const ProtocolHandlerRegistry::ProtocolHandlerList*
751ProtocolHandlerRegistry::GetHandlerList(
752    const std::string& scheme) const {
753  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
754  ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
755  if (p == protocol_handlers_.end()) {
756    return NULL;
757  }
758  return &p->second;
759}
760
761void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) {
762  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
763  ProtocolHandlerMap::const_iterator p = default_handlers_.find(
764      handler.protocol());
765  // If we're not loading, and we are setting a default for a new protocol,
766  // register with the OS.
767  if (!is_loading_ && p == default_handlers_.end())
768      delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this);
769  default_handlers_.erase(handler.protocol());
770  default_handlers_.insert(std::make_pair(handler.protocol(), handler));
771  PromoteHandler(handler);
772  BrowserThread::PostTask(
773      BrowserThread::IO,
774      FROM_HERE,
775      base::Bind(&IOThreadDelegate::SetDefault, io_thread_delegate_, handler));
776}
777
778void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) {
779  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
780  ProtocolHandlerMultiMap::iterator p =
781      protocol_handlers_.find(handler.protocol());
782
783  if (p != protocol_handlers_.end()) {
784    p->second.push_back(handler);
785    return;
786  }
787
788  ProtocolHandlerList new_list;
789  new_list.push_back(handler);
790  protocol_handlers_[handler.protocol()] = new_list;
791}
792
793base::Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() {
794  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
795  base::ListValue* protocol_handlers = new base::ListValue();
796  for (ProtocolHandlerMultiMap::iterator i = user_protocol_handlers_.begin();
797       i != user_protocol_handlers_.end();
798       ++i) {
799    for (ProtocolHandlerList::iterator j = i->second.begin();
800         j != i->second.end(); ++j) {
801      base::DictionaryValue* encoded = j->Encode();
802      if (IsDefault(*j)) {
803        encoded->Set("default", base::Value::CreateBooleanValue(true));
804      }
805      protocol_handlers->Append(encoded);
806    }
807  }
808  return protocol_handlers;
809}
810
811base::Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
812  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
813  base::ListValue* handlers = new base::ListValue();
814  for (ProtocolHandlerList::iterator i =
815           user_ignored_protocol_handlers_.begin();
816       i != user_ignored_protocol_handlers_.end();
817       ++i) {
818    handlers->Append(i->Encode());
819  }
820  return handlers;
821}
822
823void ProtocolHandlerRegistry::NotifyChanged() {
824  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
825  content::NotificationService::current()->Notify(
826      chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
827      content::Source<Profile>(profile_),
828      content::NotificationService::NoDetails());
829}
830
831void ProtocolHandlerRegistry::RegisterProtocolHandler(
832    const ProtocolHandler& handler,
833    const HandlerSource source) {
834  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
835  DCHECK(CanSchemeBeOverridden(handler.protocol()));
836  DCHECK(!handler.IsEmpty());
837  ProtocolHandlerMultiMap& map =
838      (source == POLICY) ? policy_protocol_handlers_ : user_protocol_handlers_;
839  ProtocolHandlerList& list = map[handler.protocol()];
840  if (!HandlerExists(handler, list))
841    list.push_back(handler);
842  if (IsRegistered(handler)) {
843    return;
844  }
845  if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol()))
846    delegate_->RegisterExternalHandler(handler.protocol());
847  InsertHandler(handler);
848}
849
850std::vector<const base::DictionaryValue*>
851ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const {
852  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
853  std::vector<const base::DictionaryValue*> result;
854  PrefService* prefs = profile_->GetPrefs();
855  if (!prefs->HasPrefPath(pref_name)) {
856    return result;
857  }
858
859  const base::ListValue* handlers = prefs->GetList(pref_name);
860  if (handlers) {
861    for (size_t i = 0; i < handlers->GetSize(); ++i) {
862      const base::DictionaryValue* dict;
863      if (!handlers->GetDictionary(i, &dict))
864        continue;
865      if (ProtocolHandler::IsValidDict(dict)) {
866        result.push_back(dict);
867      }
868    }
869  }
870  return result;
871}
872
873void ProtocolHandlerRegistry::RegisterProtocolHandlersFromPref(
874    const char* pref_name,
875    const HandlerSource source) {
876  std::vector<const base::DictionaryValue*> registered_handlers =
877      GetHandlersFromPref(pref_name);
878  for (std::vector<const base::DictionaryValue*>::const_iterator p =
879           registered_handlers.begin();
880       p != registered_handlers.end();
881       ++p) {
882    ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p);
883    RegisterProtocolHandler(handler, source);
884    bool is_default = false;
885    if ((*p)->GetBoolean("default", &is_default) && is_default) {
886      SetDefault(handler);
887    }
888  }
889}
890
891void ProtocolHandlerRegistry::IgnoreProtocolHandler(
892    const ProtocolHandler& handler,
893    const HandlerSource source) {
894  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
895  ProtocolHandlerList& list = (source == POLICY)
896                                  ? policy_ignored_protocol_handlers_
897                                  : user_ignored_protocol_handlers_;
898  if (!HandlerExists(handler, list))
899    list.push_back(handler);
900  if (HandlerExists(handler, ignored_protocol_handlers_))
901    return;
902  ignored_protocol_handlers_.push_back(handler);
903}
904
905void ProtocolHandlerRegistry::IgnoreProtocolHandlersFromPref(
906    const char* pref_name,
907    const HandlerSource source) {
908  std::vector<const base::DictionaryValue*> ignored_handlers =
909      GetHandlersFromPref(pref_name);
910  for (std::vector<const base::DictionaryValue*>::const_iterator p =
911           ignored_handlers.begin();
912       p != ignored_handlers.end();
913       ++p) {
914    IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p), source);
915  }
916}
917
918bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
919                                            ProtocolHandlerMultiMap* map) {
920  return HandlerExists(handler, (*map)[handler.protocol()]);
921}
922
923bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
924                                            const ProtocolHandlerList& list) {
925  return std::find(list.begin(), list.end(), handler) != list.end();
926}
927
928void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
929                                           ProtocolHandlerMultiMap* map) {
930  EraseHandler(handler, &(*map)[handler.protocol()]);
931}
932
933void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
934                                           ProtocolHandlerList* list) {
935  list->erase(std::find(list->begin(), list->end(), handler));
936}
937
938void ProtocolHandlerRegistry::AddPredefinedHandler(
939    const ProtocolHandler& handler) {
940  DCHECK(!is_loaded_);  // Must be called prior InitProtocolSettings.
941  RegisterProtocolHandler(handler, USER);
942  SetDefault(handler);
943}
944
945scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
946ProtocolHandlerRegistry::CreateJobInterceptorFactory() {
947  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
948  // this is always created on the UI thread (in profile_io's
949  // InitializeOnUIThread. Any method calls must be done
950  // on the IO thread (this is checked).
951  return scoped_ptr<JobInterceptorFactory>(
952      new JobInterceptorFactory(io_thread_delegate_.get()));
953}
954