summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJüri Valdmann <juri.valdmann@qt.io>2018-01-23 10:33:55 +0100
committerJüri Valdmann <juri.valdmann@qt.io>2018-01-29 08:22:41 +0000
commit3541bcae07fcea351a103d0ccbdef7526683de66 (patch)
treeb01353007520024bdcf13cbed392533efdb8a6b1
parent37034957c104b571a100130ffe7fcd19340ced51 (diff)
downloadqtwebengine-chromium-3541bcae07fcea351a103d0ccbdef7526683de66.tar.gz
Import ProtocolHandlerRegistry and related classes
Import additional files from Chromium 63.0.3239.117. Task-number: QTBUG-62783 Change-Id: I5ddf38675807d189dd056a79004e2d80abb7fe54 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rwxr-xr-xchromium/chrome/browser/custom_handlers/protocol_handler_registry.cc923
-rwxr-xr-xchromium/chrome/browser/custom_handlers/protocol_handler_registry.h370
-rwxr-xr-xchromium/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc70
-rwxr-xr-xchromium/chrome/browser/custom_handlers/protocol_handler_registry_factory.h53
-rwxr-xr-xchromium/chrome/common/custom_handlers/protocol_handler.cc87
-rwxr-xr-xchromium/chrome/common/custom_handlers/protocol_handler.h73
6 files changed, 1576 insertions, 0 deletions
diff --git a/chromium/chrome/browser/custom_handlers/protocol_handler_registry.cc b/chromium/chrome/browser/custom_handlers/protocol_handler_registry.cc
new file mode 100755
index 00000000000..608da379d81
--- /dev/null
+++ b/chromium/chrome/browser/custom_handlers/protocol_handler_registry.cc
@@ -0,0 +1,923 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/stl_util.h"
+#include "build/build_config.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/profiles/profile_io_data.h"
+#include "chrome/common/custom_handlers/protocol_handler.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_service.h"
+#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "net/base/network_delegate.h"
+#include "net/url_request/url_request_redirect_job.h"
+#include "ui/base/l10n/l10n_util.h"
+
+using content::BrowserThread;
+using content::ChildProcessSecurityPolicy;
+
+namespace {
+
+const ProtocolHandler& LookupHandler(
+ const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map,
+ const std::string& scheme) {
+ ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p =
+ handler_map.find(scheme);
+
+ if (p != handler_map.end())
+ return p->second;
+
+ return ProtocolHandler::EmptyProtocolHandler();
+}
+
+// If true default protocol handlers will be removed if the OS level
+// registration for a protocol is no longer Chrome.
+bool ShouldRemoveHandlersNotInOS() {
+#if defined(OS_LINUX)
+ // We don't do this on Linux as the OS registration there is not reliable,
+ // and Chrome OS doesn't have any notion of OS registration.
+ // TODO(benwells): When Linux support is more reliable remove this
+ // difference (http://crbug.com/88255).
+ return false;
+#else
+ return shell_integration::GetDefaultWebClientSetPermission() !=
+ shell_integration::SET_DEFAULT_NOT_ALLOWED;
+#endif
+}
+
+} // namespace
+
+// IOThreadDelegate ------------------------------------------------------------
+
+// IOThreadDelegate is an IO thread specific object. Access to the class should
+// all be done via the IO thread. The registry living on the UI thread makes
+// a best effort to update the IO object after local updates are completed.
+class ProtocolHandlerRegistry::IOThreadDelegate
+ : public base::RefCountedThreadSafe<
+ ProtocolHandlerRegistry::IOThreadDelegate> {
+ public:
+ // Creates a new instance. If |enabled| is true the registry is considered
+ // enabled on the IO thread.
+ explicit IOThreadDelegate(bool enabled);
+
+ // Returns true if the protocol has a default protocol handler.
+ // Should be called only from the IO thread.
+ bool IsHandledProtocol(const std::string& scheme) const;
+
+ // Clears the default for the provided protocol.
+ // Should be called only from the IO thread.
+ void ClearDefault(const std::string& scheme);
+
+ // Makes this ProtocolHandler the default handler for its protocol.
+ // Should be called only from the IO thread.
+ void SetDefault(const ProtocolHandler& handler);
+
+ // Creates a URL request job for the given request if there is a matching
+ // protocol handler, returns NULL otherwise.
+ net::URLRequestJob* MaybeCreateJob(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate) const;
+
+ // Indicate that the registry has been enabled in the IO thread's
+ // copy of the data.
+ void Enable() { enabled_ = true; }
+
+ // Indicate that the registry has been disabled in the IO thread's copy of
+ // the data.
+ void Disable() { enabled_ = false; }
+
+ private:
+ friend class base::RefCountedThreadSafe<IOThreadDelegate>;
+ virtual ~IOThreadDelegate();
+
+ // Copy of protocol handlers use only on the IO thread.
+ ProtocolHandlerRegistry::ProtocolHandlerMap default_handlers_;
+
+ // Is the registry enabled on the IO thread.
+ bool enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(IOThreadDelegate);
+};
+
+ProtocolHandlerRegistry::IOThreadDelegate::IOThreadDelegate(bool)
+ : enabled_(true) {}
+ProtocolHandlerRegistry::IOThreadDelegate::~IOThreadDelegate() {}
+
+bool ProtocolHandlerRegistry::IOThreadDelegate::IsHandledProtocol(
+ const std::string& scheme) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return enabled_ && !LookupHandler(default_handlers_, scheme).IsEmpty();
+}
+
+void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault(
+ const std::string& scheme) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ default_handlers_.erase(scheme);
+}
+
+void ProtocolHandlerRegistry::IOThreadDelegate::SetDefault(
+ const ProtocolHandler& handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ClearDefault(handler.protocol());
+ default_handlers_.insert(std::make_pair(handler.protocol(), handler));
+}
+
+// Create a new job for the supplied |URLRequest| if a default handler
+// is registered and the associated handler is able to interpret
+// the url from |request|.
+net::URLRequestJob* ProtocolHandlerRegistry::IOThreadDelegate::MaybeCreateJob(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ ProtocolHandler handler = LookupHandler(default_handlers_,
+ request->url().scheme());
+ if (handler.IsEmpty())
+ return NULL;
+
+ GURL translated_url(handler.TranslateUrl(request->url()));
+ if (!translated_url.is_valid())
+ return NULL;
+
+ return new net::URLRequestRedirectJob(
+ request, network_delegate, translated_url,
+ net::URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT,
+ "Protocol Handler Registry");
+}
+
+// JobInterceptorFactory -------------------------------------------------------
+
+// Instances of JobInterceptorFactory are produced for ownership by the IO
+// thread where it handler URL requests. We should never hold
+// any pointers on this class, only produce them in response to
+// requests via |ProtocolHandlerRegistry::CreateJobInterceptorFactory|.
+ProtocolHandlerRegistry::JobInterceptorFactory::JobInterceptorFactory(
+ IOThreadDelegate* io_thread_delegate)
+ : io_thread_delegate_(io_thread_delegate) {
+ DCHECK(io_thread_delegate_.get());
+ DETACH_FROM_THREAD(thread_checker_);
+}
+
+ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() {
+}
+
+void ProtocolHandlerRegistry::JobInterceptorFactory::Chain(
+ std::unique_ptr<net::URLRequestJobFactory> job_factory) {
+ job_factory_ = std::move(job_factory);
+}
+
+net::URLRequestJob*
+ProtocolHandlerRegistry::JobInterceptorFactory::
+MaybeCreateJobWithProtocolHandler(
+ const std::string& scheme,
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ net::URLRequestJob* job = io_thread_delegate_->MaybeCreateJob(
+ request, network_delegate);
+ if (job)
+ return job;
+ return job_factory_->MaybeCreateJobWithProtocolHandler(
+ scheme, request, network_delegate);
+}
+
+net::URLRequestJob*
+ProtocolHandlerRegistry::JobInterceptorFactory::MaybeInterceptRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) const {
+ return job_factory_->MaybeInterceptRedirect(
+ request, network_delegate, location);
+}
+
+net::URLRequestJob*
+ProtocolHandlerRegistry::JobInterceptorFactory::MaybeInterceptResponse(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const {
+ return job_factory_->MaybeInterceptResponse(request, network_delegate);
+}
+
+bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledProtocol(
+ const std::string& scheme) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return io_thread_delegate_->IsHandledProtocol(scheme) ||
+ job_factory_->IsHandledProtocol(scheme);
+}
+
+bool ProtocolHandlerRegistry::JobInterceptorFactory::IsSafeRedirectTarget(
+ const GURL& location) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return job_factory_->IsSafeRedirectTarget(location);
+}
+
+// Delegate --------------------------------------------------------------------
+
+ProtocolHandlerRegistry::Delegate::~Delegate() {}
+
+void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler(
+ const std::string& protocol) {
+ ChildProcessSecurityPolicy* policy =
+ ChildProcessSecurityPolicy::GetInstance();
+ if (!policy->IsWebSafeScheme(protocol)) {
+ policy->RegisterWebSafeScheme(protocol);
+ }
+}
+
+void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
+ const std::string& protocol) {
+}
+
+bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered(
+ const std::string& protocol) {
+ // NOTE(koz): This function is safe to call from any thread, despite living
+ // in ProfileIOData.
+ return ProfileIOData::IsHandledProtocol(protocol);
+}
+
+void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient(
+ const std::string& protocol, ProtocolHandlerRegistry* registry) {
+ // The worker pointer is reference counted. While it is running, the
+ // sequence it runs on will hold references it will be automatically freed
+ // once all its tasks have finished.
+ base::MakeRefCounted<shell_integration::DefaultProtocolClientWorker>(
+ registry->GetDefaultWebClientCallback(protocol), protocol)
+ ->StartSetAsDefault();
+}
+
+void ProtocolHandlerRegistry::Delegate::CheckDefaultClientWithOS(
+ const std::string& protocol,
+ ProtocolHandlerRegistry* registry) {
+ // The worker pointer is reference counted. While it is running, the
+ // sequence it runs on will hold references it will be automatically freed
+ // once all its tasks have finished.
+ base::MakeRefCounted<shell_integration::DefaultProtocolClientWorker>(
+ registry->GetDefaultWebClientCallback(protocol), protocol)
+ ->StartCheckIsDefault();
+}
+
+// ProtocolHandlerRegistry -----------------------------------------------------
+
+ProtocolHandlerRegistry::ProtocolHandlerRegistry(
+ content::BrowserContext* context,
+ Delegate* delegate)
+ : context_(context),
+ delegate_(delegate),
+ enabled_(true),
+ is_loading_(false),
+ is_loaded_(false),
+ io_thread_delegate_(new IOThreadDelegate(enabled_)),
+ weak_ptr_factory_(this) {}
+
+bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest(
+ const ProtocolHandler& handler) {
+ if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol()))
+ return true;
+
+ if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler))
+ return true;
+
+ if (AttemptReplace(handler))
+ return true;
+
+ return false;
+}
+
+void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler(
+ const ProtocolHandler& handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RegisterProtocolHandler(handler, USER);
+ SetDefault(handler);
+ Save();
+ NotifyChanged();
+}
+
+void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
+ const ProtocolHandler& handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RegisterProtocolHandler(handler, USER);
+ Save();
+ NotifyChanged();
+}
+
+void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
+ const ProtocolHandler& handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ IgnoreProtocolHandler(handler, USER);
+ Save();
+ NotifyChanged();
+}
+
+bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ProtocolHandler old_default = GetHandlerFor(handler.protocol());
+ bool make_new_handler_default = handler.IsSameOrigin(old_default);
+ ProtocolHandlerList to_replace(GetReplacedHandlers(handler));
+ if (to_replace.empty())
+ return false;
+ for (ProtocolHandlerList::iterator p = to_replace.begin();
+ p != to_replace.end(); ++p) {
+ RemoveHandler(*p);
+ }
+ if (make_new_handler_default) {
+ OnAcceptRegisterProtocolHandler(handler);
+ } else {
+ InsertHandler(handler);
+ NotifyChanged();
+ }
+ return true;
+}
+
+ProtocolHandlerRegistry::ProtocolHandlerList
+ProtocolHandlerRegistry::GetReplacedHandlers(
+ const ProtocolHandler& handler) const {
+ ProtocolHandlerList replaced_handlers;
+ const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
+ if (!handlers)
+ return replaced_handlers;
+ for (ProtocolHandlerList::const_iterator p = handlers->begin();
+ p != handlers->end(); p++) {
+ if (handler.IsSameOrigin(*p)) {
+ replaced_handlers.push_back(*p);
+ }
+ }
+ return replaced_handlers;
+}
+
+void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ default_handlers_.erase(scheme);
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&IOThreadDelegate::ClearDefault,
+ io_thread_delegate_, scheme));
+ Save();
+ NotifyChanged();
+}
+
+bool ProtocolHandlerRegistry::IsDefault(
+ const ProtocolHandler& handler) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ return GetHandlerFor(handler.protocol()) == handler;
+}
+
+void ProtocolHandlerRegistry::InstallDefaultsForChromeOS() {
+#if defined(OS_CHROMEOS)
+ // Only chromeos has default protocol handlers at this point.
+ AddPredefinedHandler(
+ ProtocolHandler::CreateProtocolHandler(
+ "mailto",
+ GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_MAILTO_HANDLER_URL))));
+ AddPredefinedHandler(
+ ProtocolHandler::CreateProtocolHandler(
+ "webcal",
+ GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL))));
+#else
+ NOTREACHED(); // this method should only ever be called in chromeos.
+#endif
+}
+
+void ProtocolHandlerRegistry::InitProtocolSettings() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // Any further default additions to the table will get rejected from now on.
+ is_loaded_ = true;
+ is_loading_ = true;
+
+ PrefService* prefs = user_prefs::UserPrefs::Get(context_);
+ if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) {
+ if (prefs->GetBoolean(prefs::kCustomHandlersEnabled)) {
+ Enable();
+ } else {
+ Disable();
+ }
+ }
+
+ RegisterProtocolHandlersFromPref(prefs::kPolicyRegisteredProtocolHandlers,
+ POLICY);
+ RegisterProtocolHandlersFromPref(prefs::kRegisteredProtocolHandlers, USER);
+ IgnoreProtocolHandlersFromPref(prefs::kPolicyIgnoredProtocolHandlers, POLICY);
+ IgnoreProtocolHandlersFromPref(prefs::kIgnoredProtocolHandlers, USER);
+
+ is_loading_ = false;
+
+ // For each default protocol handler, check that we are still registered
+ // with the OS as the default application.
+ if (ShouldRemoveHandlersNotInOS()) {
+ for (ProtocolHandlerMap::const_iterator p = default_handlers_.begin();
+ p != default_handlers_.end(); ++p) {
+ delegate_->CheckDefaultClientWithOS(p->second.protocol(), this);
+ }
+ }
+}
+
+int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ const ProtocolHandler& handler = GetHandlerFor(scheme);
+ if (handler.IsEmpty())
+ return -1;
+ const ProtocolHandlerList* handlers = GetHandlerList(scheme);
+ if (!handlers)
+ return -1;
+
+ ProtocolHandlerList::const_iterator p;
+ int i;
+ for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) {
+ if (*p == handler)
+ return i;
+ }
+ return -1;
+}
+
+ProtocolHandlerRegistry::ProtocolHandlerList
+ProtocolHandlerRegistry::GetHandlersFor(
+ const std::string& scheme) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
+ if (p == protocol_handlers_.end()) {
+ return ProtocolHandlerList();
+ }
+ return p->second;
+}
+
+ProtocolHandlerRegistry::ProtocolHandlerList
+ProtocolHandlerRegistry::GetIgnoredHandlers() {
+ return ignored_protocol_handlers_;
+}
+
+void ProtocolHandlerRegistry::GetRegisteredProtocols(
+ std::vector<std::string>* output) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ProtocolHandlerMultiMap::const_iterator p;
+ for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) {
+ if (!p->second.empty())
+ output->push_back(p->first);
+ }
+}
+
+bool ProtocolHandlerRegistry::CanSchemeBeOverridden(
+ const std::string& scheme) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ const ProtocolHandlerList* handlers = GetHandlerList(scheme);
+ // If we already have a handler for this scheme, we can add more.
+ if (handlers != NULL && !handlers->empty())
+ return true;
+ // Don't override a scheme if it already has an external handler.
+ return !delegate_->IsExternalHandlerRegistered(scheme);
+}
+
+bool ProtocolHandlerRegistry::IsRegistered(
+ const ProtocolHandler& handler) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
+ if (!handlers) {
+ return false;
+ }
+ return base::ContainsValue(*handlers, handler);
+}
+
+bool ProtocolHandlerRegistry::IsRegisteredByUser(
+ const ProtocolHandler& handler) {
+ return HandlerExists(handler, &user_protocol_handlers_);
+}
+
+bool ProtocolHandlerRegistry::HasPolicyRegisteredHandler(
+ const std::string& scheme) {
+ return (policy_protocol_handlers_.find(scheme) !=
+ policy_protocol_handlers_.end());
+}
+
+bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ProtocolHandlerList::const_iterator i;
+ for (i = ignored_protocol_handlers_.begin();
+ i != ignored_protocol_handlers_.end(); ++i) {
+ if (*i == handler) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ProtocolHandlerRegistry::HasRegisteredEquivalent(
+ const ProtocolHandler& handler) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
+ if (!handlers) {
+ return false;
+ }
+ ProtocolHandlerList::const_iterator i;
+ for (i = handlers->begin(); i != handlers->end(); ++i) {
+ if (handler.IsEquivalent(*i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ProtocolHandlerRegistry::HasIgnoredEquivalent(
+ const ProtocolHandler& handler) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ProtocolHandlerList::const_iterator i;
+ for (i = ignored_protocol_handlers_.begin();
+ i != ignored_protocol_handlers_.end(); ++i) {
+ if (handler.IsEquivalent(*i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ProtocolHandlerRegistry::RemoveIgnoredHandler(
+ const ProtocolHandler& handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ bool should_notify = false;
+ if (HandlerExists(handler, ignored_protocol_handlers_) &&
+ HandlerExists(handler, user_ignored_protocol_handlers_)) {
+ EraseHandler(handler, &user_ignored_protocol_handlers_);
+ Save();
+ if (!HandlerExists(handler, policy_ignored_protocol_handlers_)) {
+ EraseHandler(handler, &ignored_protocol_handlers_);
+ should_notify = true;
+ }
+ }
+ if (should_notify)
+ NotifyChanged();
+}
+
+bool ProtocolHandlerRegistry::IsHandledProtocol(
+ const std::string& scheme) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ return enabled_ && !GetHandlerFor(scheme).IsEmpty();
+}
+
+void ProtocolHandlerRegistry::RemoveHandler(
+ const ProtocolHandler& handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()];
+ bool erase_success = false;
+ if (HandlerExists(handler, handlers) &&
+ HandlerExists(handler, &user_protocol_handlers_)) {
+ EraseHandler(handler, &user_protocol_handlers_);
+ erase_success = true;
+ if (!HandlerExists(handler, &policy_protocol_handlers_))
+ EraseHandler(handler, &protocol_handlers_);
+ }
+ ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol());
+ if (erase_success && q != default_handlers_.end() && q->second == handler) {
+ // Make the new top handler in the list the default.
+ if (!handlers.empty()) {
+ // NOTE We pass a copy because SetDefault() modifies handlers.
+ SetDefault(ProtocolHandler(handlers[0]));
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&IOThreadDelegate::ClearDefault, io_thread_delegate_,
+ q->second.protocol()));
+
+ default_handlers_.erase(q);
+ }
+ }
+
+ if (erase_success && !IsHandledProtocol(handler.protocol())) {
+ delegate_->DeregisterExternalHandler(handler.protocol());
+ }
+ Save();
+ if (erase_success)
+ NotifyChanged();
+}
+
+void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ProtocolHandler current_default = GetHandlerFor(scheme);
+ if (!current_default.IsEmpty())
+ RemoveHandler(current_default);
+}
+
+const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor(
+ const std::string& scheme) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ return LookupHandler(default_handlers_, scheme);
+}
+
+void ProtocolHandlerRegistry::Enable() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (enabled_) {
+ return;
+ }
+ enabled_ = true;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&IOThreadDelegate::Enable, io_thread_delegate_));
+
+ ProtocolHandlerMap::const_iterator p;
+ for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
+ delegate_->RegisterExternalHandler(p->first);
+ }
+ Save();
+ NotifyChanged();
+}
+
+void ProtocolHandlerRegistry::Disable() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!enabled_) {
+ return;
+ }
+ enabled_ = false;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&IOThreadDelegate::Disable, io_thread_delegate_));
+
+ ProtocolHandlerMap::const_iterator p;
+ for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) {
+ delegate_->DeregisterExternalHandler(p->first);
+ }
+ Save();
+ NotifyChanged();
+}
+
+void ProtocolHandlerRegistry::Shutdown() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ delegate_.reset(NULL);
+
+ weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
+// static
+void ProtocolHandlerRegistry::RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) {
+ registry->RegisterListPref(prefs::kRegisteredProtocolHandlers);
+ registry->RegisterListPref(prefs::kIgnoredProtocolHandlers);
+ registry->RegisterListPref(prefs::kPolicyRegisteredProtocolHandlers);
+ registry->RegisterListPref(prefs::kPolicyIgnoredProtocolHandlers);
+ registry->RegisterBooleanPref(prefs::kCustomHandlersEnabled, true);
+}
+
+ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(IsRegistered(handler));
+ ProtocolHandlerMultiMap::iterator p =
+ protocol_handlers_.find(handler.protocol());
+ ProtocolHandlerList& list = p->second;
+ list.erase(std::find(list.begin(), list.end(), handler));
+ list.insert(list.begin(), handler);
+}
+
+void ProtocolHandlerRegistry::Save() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (is_loading_) {
+ return;
+ }
+ std::unique_ptr<base::Value> registered_protocol_handlers(
+ EncodeRegisteredHandlers());
+ std::unique_ptr<base::Value> ignored_protocol_handlers(
+ EncodeIgnoredHandlers());
+ PrefService* prefs = user_prefs::UserPrefs::Get(context_);
+
+ prefs->Set(prefs::kRegisteredProtocolHandlers,
+ *registered_protocol_handlers);
+ prefs->Set(prefs::kIgnoredProtocolHandlers,
+ *ignored_protocol_handlers);
+ prefs->SetBoolean(prefs::kCustomHandlersEnabled, enabled_);
+}
+
+const ProtocolHandlerRegistry::ProtocolHandlerList*
+ProtocolHandlerRegistry::GetHandlerList(
+ const std::string& scheme) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
+ if (p == protocol_handlers_.end()) {
+ return NULL;
+ }
+ return &p->second;
+}
+
+void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ProtocolHandlerMap::const_iterator p = default_handlers_.find(
+ handler.protocol());
+ // If we're not loading, and we are setting a default for a new protocol,
+ // register with the OS.
+ if (!is_loading_ && p == default_handlers_.end())
+ delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this);
+ default_handlers_.erase(handler.protocol());
+ default_handlers_.insert(std::make_pair(handler.protocol(), handler));
+ PromoteHandler(handler);
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&IOThreadDelegate::SetDefault,
+ io_thread_delegate_, handler));
+}
+
+void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ProtocolHandlerMultiMap::iterator p =
+ protocol_handlers_.find(handler.protocol());
+
+ if (p != protocol_handlers_.end()) {
+ p->second.push_back(handler);
+ return;
+ }
+
+ ProtocolHandlerList new_list;
+ new_list.push_back(handler);
+ protocol_handlers_[handler.protocol()] = new_list;
+}
+
+base::Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ base::ListValue* protocol_handlers = new base::ListValue();
+ for (ProtocolHandlerMultiMap::iterator i = user_protocol_handlers_.begin();
+ i != user_protocol_handlers_.end();
+ ++i) {
+ for (ProtocolHandlerList::iterator j = i->second.begin();
+ j != i->second.end(); ++j) {
+ std::unique_ptr<base::DictionaryValue> encoded = j->Encode();
+ if (IsDefault(*j)) {
+ encoded->Set("default", base::MakeUnique<base::Value>(true));
+ }
+ protocol_handlers->Append(std::move(encoded));
+ }
+ }
+ return protocol_handlers;
+}
+
+base::Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ base::ListValue* handlers = new base::ListValue();
+ for (ProtocolHandlerList::iterator i =
+ user_ignored_protocol_handlers_.begin();
+ i != user_ignored_protocol_handlers_.end();
+ ++i) {
+ handlers->Append(i->Encode());
+ }
+ return handlers;
+}
+
+void ProtocolHandlerRegistry::NotifyChanged() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
+ content::Source<content::BrowserContext>(context_),
+ content::NotificationService::NoDetails());
+}
+
+void ProtocolHandlerRegistry::RegisterProtocolHandler(
+ const ProtocolHandler& handler,
+ const HandlerSource source) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(CanSchemeBeOverridden(handler.protocol()));
+ DCHECK(!handler.IsEmpty());
+ ProtocolHandlerMultiMap& map =
+ (source == POLICY) ? policy_protocol_handlers_ : user_protocol_handlers_;
+ ProtocolHandlerList& list = map[handler.protocol()];
+ if (!HandlerExists(handler, list))
+ list.push_back(handler);
+ if (IsRegistered(handler)) {
+ return;
+ }
+ if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol()))
+ delegate_->RegisterExternalHandler(handler.protocol());
+ InsertHandler(handler);
+}
+
+std::vector<const base::DictionaryValue*>
+ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ std::vector<const base::DictionaryValue*> result;
+ PrefService* prefs = user_prefs::UserPrefs::Get(context_);
+ if (!prefs->HasPrefPath(pref_name)) {
+ return result;
+ }
+
+ const base::ListValue* handlers = prefs->GetList(pref_name);
+ if (handlers) {
+ for (size_t i = 0; i < handlers->GetSize(); ++i) {
+ const base::DictionaryValue* dict;
+ if (!handlers->GetDictionary(i, &dict))
+ continue;
+ if (ProtocolHandler::IsValidDict(dict)) {
+ result.push_back(dict);
+ }
+ }
+ }
+ return result;
+}
+
+void ProtocolHandlerRegistry::RegisterProtocolHandlersFromPref(
+ const char* pref_name,
+ const HandlerSource source) {
+ std::vector<const base::DictionaryValue*> registered_handlers =
+ GetHandlersFromPref(pref_name);
+ for (std::vector<const base::DictionaryValue*>::const_iterator p =
+ registered_handlers.begin();
+ p != registered_handlers.end();
+ ++p) {
+ ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p);
+ RegisterProtocolHandler(handler, source);
+ bool is_default = false;
+ if ((*p)->GetBoolean("default", &is_default) && is_default) {
+ SetDefault(handler);
+ }
+ }
+}
+
+void ProtocolHandlerRegistry::IgnoreProtocolHandler(
+ const ProtocolHandler& handler,
+ const HandlerSource source) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ ProtocolHandlerList& list = (source == POLICY)
+ ? policy_ignored_protocol_handlers_
+ : user_ignored_protocol_handlers_;
+ if (!HandlerExists(handler, list))
+ list.push_back(handler);
+ if (HandlerExists(handler, ignored_protocol_handlers_))
+ return;
+ ignored_protocol_handlers_.push_back(handler);
+}
+
+void ProtocolHandlerRegistry::IgnoreProtocolHandlersFromPref(
+ const char* pref_name,
+ const HandlerSource source) {
+ std::vector<const base::DictionaryValue*> ignored_handlers =
+ GetHandlersFromPref(pref_name);
+ for (std::vector<const base::DictionaryValue*>::const_iterator p =
+ ignored_handlers.begin();
+ p != ignored_handlers.end();
+ ++p) {
+ IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p), source);
+ }
+}
+
+bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
+ ProtocolHandlerMultiMap* map) {
+ return HandlerExists(handler, (*map)[handler.protocol()]);
+}
+
+bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler,
+ const ProtocolHandlerList& list) {
+ return base::ContainsValue(list, handler);
+}
+
+void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
+ ProtocolHandlerMultiMap* map) {
+ EraseHandler(handler, &(*map)[handler.protocol()]);
+}
+
+void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler,
+ ProtocolHandlerList* list) {
+ list->erase(std::find(list->begin(), list->end(), handler));
+}
+
+void ProtocolHandlerRegistry::OnSetAsDefaultProtocolClientFinished(
+ const std::string& protocol,
+ shell_integration::DefaultWebClientState state) {
+ // Clear if the default protocol client isn't this installation.
+ if (ShouldRemoveHandlersNotInOS() &&
+ (state == shell_integration::NOT_DEFAULT ||
+ state == shell_integration::OTHER_MODE_IS_DEFAULT)) {
+ ClearDefault(protocol);
+ }
+}
+
+void ProtocolHandlerRegistry::AddPredefinedHandler(
+ const ProtocolHandler& handler) {
+ DCHECK(!is_loaded_); // Must be called prior InitProtocolSettings.
+ RegisterProtocolHandler(handler, USER);
+ SetDefault(handler);
+}
+
+shell_integration::DefaultWebClientWorkerCallback
+ProtocolHandlerRegistry::GetDefaultWebClientCallback(
+ const std::string& protocol) {
+ return base::Bind(
+ &ProtocolHandlerRegistry::OnSetAsDefaultProtocolClientFinished,
+ weak_ptr_factory_.GetWeakPtr(), protocol);
+}
+
+std::unique_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
+ProtocolHandlerRegistry::CreateJobInterceptorFactory() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // this is always created on the UI thread (in profile_io's
+ // InitializeOnUIThread. Any method calls must be done
+ // on the IO thread (this is checked).
+ return std::unique_ptr<JobInterceptorFactory>(
+ new JobInterceptorFactory(io_thread_delegate_.get()));
+}
diff --git a/chromium/chrome/browser/custom_handlers/protocol_handler_registry.h b/chromium/chrome/browser/custom_handlers/protocol_handler_registry.h
new file mode 100755
index 00000000000..92608305bab
--- /dev/null
+++ b/chromium/chrome/browser/custom_handlers/protocol_handler_registry.h
@@ -0,0 +1,370 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_H_
+#define CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner_helpers.h"
+#include "base/values.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/shell_integration.h"
+#include "chrome/common/custom_handlers/protocol_handler.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_job.h"
+#include "net/url_request/url_request_job_factory.h"
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+// This is where handlers for protocols registered with
+// navigator.registerProtocolHandler() are registered. Each Profile owns an
+// instance of this class, which is initialized on browser start through
+// Profile::InitRegisteredProtocolHandlers(), and they should be the only
+// instances of this class.
+class ProtocolHandlerRegistry : public KeyedService {
+ public:
+ enum HandlerSource {
+ USER, // The handler was installed by user
+ POLICY, // The handler was installed by policy
+ };
+
+ // |Delegate| provides an interface for interacting asynchronously
+ // with the underlying OS for the purposes of registering Chrome
+ // as the default handler for specific protocols.
+ class Delegate {
+ public:
+ virtual ~Delegate();
+ virtual void RegisterExternalHandler(const std::string& protocol);
+ virtual void DeregisterExternalHandler(const std::string& protocol);
+ virtual bool IsExternalHandlerRegistered(const std::string& protocol);
+ virtual void RegisterWithOSAsDefaultClient(
+ const std::string& protocol,
+ ProtocolHandlerRegistry* registry);
+ virtual void CheckDefaultClientWithOS(const std::string& protocol,
+ ProtocolHandlerRegistry* registry);
+ };
+
+ // Forward declaration of the internal implementation class.
+ class IOThreadDelegate;
+
+ // JobInterceptorFactory intercepts URLRequestJob creation for URLRequests the
+ // ProtocolHandlerRegistry is registered to handle. When no handler is
+ // registered, the URLRequest is passed along to the chained
+ // URLRequestJobFactory (set with |JobInterceptorFactory::Chain|).
+ // JobInterceptorFactory's are created via
+ // |ProtocolHandlerRegistry::CreateJobInterceptorFactory|.
+ class JobInterceptorFactory : public net::URLRequestJobFactory {
+ public:
+ // |io_thread_delegate| is used to perform actual job creation work.
+ explicit JobInterceptorFactory(IOThreadDelegate* io_thread_delegate);
+ ~JobInterceptorFactory() override;
+
+ // |job_factory| is set as the URLRequestJobFactory where requests are
+ // forwarded if JobInterceptorFactory decides to pass on them.
+ void Chain(std::unique_ptr<net::URLRequestJobFactory> job_factory);
+
+ // URLRequestJobFactory implementation.
+ net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
+ const std::string& scheme,
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override;
+
+ net::URLRequestJob* MaybeInterceptRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) const override;
+
+ net::URLRequestJob* MaybeInterceptResponse(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override;
+
+ bool IsHandledProtocol(const std::string& scheme) const override;
+ bool IsSafeRedirectTarget(const GURL& location) const override;
+
+ private:
+ // When JobInterceptorFactory decides to pass on particular requests,
+ // they're forwarded to the chained URLRequestJobFactory, |job_factory_|.
+ std::unique_ptr<URLRequestJobFactory> job_factory_;
+ // |io_thread_delegate_| performs the actual job creation decisions by
+ // mirroring the ProtocolHandlerRegistry on the IO thread.
+ scoped_refptr<IOThreadDelegate> io_thread_delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(JobInterceptorFactory);
+ };
+
+ typedef std::map<std::string, ProtocolHandler> ProtocolHandlerMap;
+ typedef std::vector<ProtocolHandler> ProtocolHandlerList;
+ typedef std::map<std::string, ProtocolHandlerList> ProtocolHandlerMultiMap;
+
+ // Creates a new instance. Assumes ownership of |delegate|.
+ ProtocolHandlerRegistry(content::BrowserContext* context, Delegate* delegate);
+ ~ProtocolHandlerRegistry() override;
+
+ // Returns a net::URLRequestJobFactory suitable for use on the IO thread, but
+ // is initialized on the UI thread.
+ std::unique_ptr<JobInterceptorFactory> CreateJobInterceptorFactory();
+
+ // Called when a site tries to register as a protocol handler. If the request
+ // can be handled silently by the registry - either to ignore the request
+ // or to update an existing handler - the request will succeed. If this
+ // function returns false the user needs to be prompted for confirmation.
+ bool SilentlyHandleRegisterHandlerRequest(const ProtocolHandler& handler);
+
+ // Called when the user accepts the registration of a given protocol handler.
+ void OnAcceptRegisterProtocolHandler(const ProtocolHandler& handler);
+
+ // Called when the user denies the registration of a given protocol handler.
+ void OnDenyRegisterProtocolHandler(const ProtocolHandler& handler);
+
+ // Called when the user indicates that they don't want to be asked about the
+ // given protocol handler again.
+ void OnIgnoreRegisterProtocolHandler(const ProtocolHandler& handler);
+
+ // Removes all handlers that have the same origin and protocol as the given
+ // one and installs the given handler. Returns true if any protocol handlers
+ // were replaced.
+ bool AttemptReplace(const ProtocolHandler& handler);
+
+ // Returns a list of protocol handlers that can be replaced by the given
+ // handler.
+ ProtocolHandlerList GetReplacedHandlers(const ProtocolHandler& handler) const;
+
+ // Clears the default for the provided protocol.
+ void ClearDefault(const std::string& scheme);
+
+ // Returns true if this handler is the default handler for its protocol.
+ bool IsDefault(const ProtocolHandler& handler) const;
+
+ // Initializes default protocol settings and loads them from prefs.
+ // This method must be called to complete initialization of the
+ // registry after creation, and prior to use.
+ void InitProtocolSettings();
+
+ // Returns the offset in the list of handlers for a protocol of the default
+ // handler for that protocol.
+ int GetHandlerIndex(const std::string& scheme) const;
+
+ // Get the list of protocol handlers for the given scheme.
+ ProtocolHandlerList GetHandlersFor(const std::string& scheme) const;
+
+ // Get the list of ignored protocol handlers.
+ ProtocolHandlerList GetIgnoredHandlers();
+
+ // Yields a list of the protocols that have handlers registered in this
+ // registry.
+ void GetRegisteredProtocols(std::vector<std::string>* output) const;
+
+ // Returns true if we allow websites to register handlers for the given
+ // scheme.
+ bool CanSchemeBeOverridden(const std::string& scheme) const;
+
+ // Returns true if an identical protocol handler has already been registered.
+ bool IsRegistered(const ProtocolHandler& handler) const;
+
+ // Returns true if an identical protocol handler has already been registered
+ // by the user.
+ bool IsRegisteredByUser(const ProtocolHandler& handler);
+
+ // Returns true if the scheme has at least one handler that is registered by
+ // policy.
+ bool HasPolicyRegisteredHandler(const std::string& scheme);
+
+ // Returns true if an identical protocol handler is being ignored.
+ bool IsIgnored(const ProtocolHandler& handler) const;
+
+ // Returns true if an equivalent protocol handler has already been registered.
+ bool HasRegisteredEquivalent(const ProtocolHandler& handler) const;
+
+ // Returns true if an equivalent protocol handler is being ignored.
+ bool HasIgnoredEquivalent(const ProtocolHandler& handler) const;
+
+ // Causes the given protocol handler to not be ignored anymore.
+ void RemoveIgnoredHandler(const ProtocolHandler& handler);
+
+ // Returns true if the protocol has a default protocol handler.
+ bool IsHandledProtocol(const std::string& scheme) const;
+
+ // Removes the given protocol handler from the registry.
+ void RemoveHandler(const ProtocolHandler& handler);
+
+ // Remove the default handler for the given protocol.
+ void RemoveDefaultHandler(const std::string& scheme);
+
+ // Returns the default handler for this protocol, or an empty handler if none
+ // exists.
+ const ProtocolHandler& GetHandlerFor(const std::string& scheme) const;
+
+ // Puts this registry in the enabled state - registered protocol handlers
+ // will handle requests.
+ void Enable();
+
+ // Puts this registry in the disabled state - registered protocol handlers
+ // will not handle requests.
+ void Disable();
+
+ // This is called by the UI thread when the system is shutting down. This
+ // does finalization which must be done on the UI thread.
+ void Shutdown() override;
+
+ // Registers the preferences that we store registered protocol handlers in.
+ static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+ bool enabled() const { return enabled_; }
+
+ // Add a predefined protocol handler. This has to be called before the first
+ // load command was issued, otherwise the command will be ignored.
+ void AddPredefinedHandler(const ProtocolHandler& handler);
+
+ // Gets the callback for DefaultProtocolClientWorker. Allows the Delegate to
+ // create the worker on behalf of ProtocolHandlerRegistry.
+ shell_integration::DefaultWebClientWorkerCallback GetDefaultWebClientCallback(
+ const std::string& protocol);
+
+ private:
+ friend class base::DeleteHelper<ProtocolHandlerRegistry>;
+ friend struct content::BrowserThread::DeleteOnThread<
+ content::BrowserThread::IO>;
+
+ // for access to InstallDefaultsForChromeOS
+ friend class ProtocolHandlerRegistryFactory;
+
+ friend class ProtocolHandlerRegistryTest;
+ friend class RegisterProtocolHandlerBrowserTest;
+
+ // Puts the given handler at the top of the list of handlers for its
+ // protocol.
+ void PromoteHandler(const ProtocolHandler& handler);
+
+ // Saves a user's registered protocol handlers.
+ void Save();
+
+ // Returns a pointer to the list of handlers registered for the given scheme,
+ // or NULL if there are none.
+ const ProtocolHandlerList* GetHandlerList(const std::string& scheme) const;
+
+ // Install default protocol handlers for chromeos which must be done
+ // prior to calling InitProtocolSettings.
+ void InstallDefaultsForChromeOS();
+
+ // Makes this ProtocolHandler the default handler for its protocol.
+ void SetDefault(const ProtocolHandler& handler);
+
+ // Insert the given ProtocolHandler into the registry.
+ void InsertHandler(const ProtocolHandler& handler);
+
+ // Returns a JSON list of protocol handlers. The caller is responsible for
+ // deleting this Value.
+ base::Value* EncodeRegisteredHandlers();
+
+ // Returns a JSON list of ignored protocol handlers. The caller is
+ // responsible for deleting this Value.
+ base::Value* EncodeIgnoredHandlers();
+
+ // Sends a notification of the given type to the NotificationService.
+ void NotifyChanged();
+
+ // Registers a new protocol handler.
+ void RegisterProtocolHandler(const ProtocolHandler& handler,
+ const HandlerSource source);
+
+ // Registers protocol handlers from the preference.
+ void RegisterProtocolHandlersFromPref(const char* pref_name,
+ const HandlerSource source);
+
+ // Get the DictionaryValues stored under the given pref name that are valid
+ // ProtocolHandler values.
+ std::vector<const base::DictionaryValue*> GetHandlersFromPref(
+ const char* pref_name) const;
+
+ // Ignores future requests to register the given protocol handler.
+ void IgnoreProtocolHandler(const ProtocolHandler& handler,
+ const HandlerSource source);
+
+ // Ignores protocol handlers from the preference.
+ void IgnoreProtocolHandlersFromPref(const char* pref_name,
+ const HandlerSource source);
+
+ // Verifies if the handler exists in the map.
+ bool HandlerExists(const ProtocolHandler& handler,
+ ProtocolHandlerMultiMap* map);
+
+ // Verifies if the handler exists in the list.
+ bool HandlerExists(const ProtocolHandler& handler,
+ const ProtocolHandlerList& list);
+
+ // Erases the handler that is guaranteed to exist from the map.
+ void EraseHandler(const ProtocolHandler& handler,
+ ProtocolHandlerMultiMap* map);
+
+ // Erases the handler that is guaranteed to exist from the list.
+ void EraseHandler(const ProtocolHandler& handler, ProtocolHandlerList* list);
+
+ // Called with the default state when the default protocol client worker is
+ // done.
+ void OnSetAsDefaultProtocolClientFinished(
+ const std::string& protocol,
+ shell_integration::DefaultWebClientState state);
+
+ // Map from protocols (strings) to protocol handlers.
+ ProtocolHandlerMultiMap protocol_handlers_;
+
+ // Protocol handlers that the user has told us to ignore.
+ ProtocolHandlerList ignored_protocol_handlers_;
+
+ // These maps track the source of protocol handler registrations for the
+ // purposes of disallowing the removal of handlers that are registered by
+ // policy. Every entry in protocol_handlers_ should exist in at least one of
+ // the user or policy maps.
+ ProtocolHandlerMultiMap user_protocol_handlers_;
+ ProtocolHandlerMultiMap policy_protocol_handlers_;
+
+ // These lists track the source of protocol handlers that were ignored, for
+ // the purposes of disallowing the removal of handlers that are ignored by
+ // policy. Every entry in ignored_protocol_handlers_ should exist in at least
+ // one of the user or policy lists.
+ ProtocolHandlerList user_ignored_protocol_handlers_;
+ ProtocolHandlerList policy_ignored_protocol_handlers_;
+
+ // Protocol handlers that are the defaults for a given protocol.
+ ProtocolHandlerMap default_handlers_;
+
+ // The browser context that owns this ProtocolHandlerRegistry.
+ content::BrowserContext* context_;
+
+ // The Delegate that registers / deregisters external handlers on our behalf.
+ std::unique_ptr<Delegate> delegate_;
+
+ // If false then registered protocol handlers will not be used to handle
+ // requests.
+ bool enabled_;
+
+ // Whether or not we are loading.
+ bool is_loading_;
+
+ // When the table gets loaded this flag will be set and any further calls to
+ // AddPredefinedHandler will be rejected.
+ bool is_loaded_;
+
+ // Copy of registry data for use on the IO thread. Changes to the registry
+ // are posted to the IO thread where updates are applied to this object.
+ scoped_refptr<IOThreadDelegate> io_thread_delegate_;
+
+ // Makes it possible to invalidate the callback for the
+ // DefaultProtocolClientWorker.
+ base::WeakPtrFactory<ProtocolHandlerRegistry> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProtocolHandlerRegistry);
+};
+#endif // CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_H_
diff --git a/chromium/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc b/chromium/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc
new file mode 100755
index 00000000000..4f725d2c254
--- /dev/null
+++ b/chromium/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
+
+#include "base/memory/singleton.h"
+#include "build/build_config.h"
+#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+// static
+ProtocolHandlerRegistryFactory* ProtocolHandlerRegistryFactory::GetInstance() {
+ return base::Singleton<ProtocolHandlerRegistryFactory>::get();
+}
+
+// static
+ProtocolHandlerRegistry* ProtocolHandlerRegistryFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<ProtocolHandlerRegistry*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+ProtocolHandlerRegistryFactory::ProtocolHandlerRegistryFactory()
+ : BrowserContextKeyedServiceFactory(
+ "ProtocolHandlerRegistry",
+ BrowserContextDependencyManager::GetInstance()) {
+}
+
+ProtocolHandlerRegistryFactory::~ProtocolHandlerRegistryFactory() {
+}
+
+// Will be created when initializing profile_io_data, so we might
+// as well have the framework create this along with other
+// PKSs to preserve orderly civic conduct :)
+bool
+ProtocolHandlerRegistryFactory::ServiceIsCreatedWithBrowserContext() const {
+ return true;
+}
+
+// Allows the produced registry to be used in incognito mode.
+content::BrowserContext* ProtocolHandlerRegistryFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+// Do not create this service for tests. MANY tests will fail
+// due to the threading requirements of this service. ALSO,
+// not creating this increases test isolation (which is GOOD!)
+bool ProtocolHandlerRegistryFactory::ServiceIsNULLWhileTesting() const {
+ return true;
+}
+
+KeyedService* ProtocolHandlerRegistryFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ ProtocolHandlerRegistry* registry = new ProtocolHandlerRegistry(
+ context, new ProtocolHandlerRegistry::Delegate());
+
+#if defined(OS_CHROMEOS)
+ // If installing defaults, they must be installed prior calling
+ // InitProtocolSettings
+ registry->InstallDefaultsForChromeOS();
+#endif
+
+ // Must be called as a part of the creation process.
+ registry->InitProtocolSettings();
+
+ return registry;
+}
diff --git a/chromium/chrome/browser/custom_handlers/protocol_handler_registry_factory.h b/chromium/chrome/browser/custom_handlers/protocol_handler_registry_factory.h
new file mode 100755
index 00000000000..ad03addb325
--- /dev/null
+++ b/chromium/chrome/browser/custom_handlers/protocol_handler_registry_factory.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_FACTORY_H_
+#define CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_FACTORY_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class Profile;
+class ProtocolHandlerRegistry;
+
+namespace base {
+template <typename T> struct DefaultSingletonTraits;
+}
+
+// Singleton that owns all ProtocolHandlerRegistrys and associates them with
+// Profiles. Listens for the Profile's destruction notification and cleans up
+// the associated ProtocolHandlerRegistry.
+class ProtocolHandlerRegistryFactory
+ : public BrowserContextKeyedServiceFactory {
+ public:
+ // Returns the singleton instance of the ProtocolHandlerRegistryFactory.
+ static ProtocolHandlerRegistryFactory* GetInstance();
+
+ // Returns the ProtocolHandlerRegistry that provides intent registration for
+ // |context|. Ownership stays with this factory object.
+ static ProtocolHandlerRegistry* GetForBrowserContext(
+ content::BrowserContext* context);
+
+ protected:
+ // BrowserContextKeyedServiceFactory implementation.
+ bool ServiceIsCreatedWithBrowserContext() const override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+ bool ServiceIsNULLWhileTesting() const override;
+
+ private:
+ friend struct base::DefaultSingletonTraits<ProtocolHandlerRegistryFactory>;
+
+ ProtocolHandlerRegistryFactory();
+ ~ProtocolHandlerRegistryFactory() override;
+
+ // BrowserContextKeyedServiceFactory implementation.
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* profile) const override;
+
+ DISALLOW_COPY_AND_ASSIGN(ProtocolHandlerRegistryFactory);
+};
+
+#endif // CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_FACTORY_H_
diff --git a/chromium/chrome/common/custom_handlers/protocol_handler.cc b/chromium/chrome/common/custom_handlers/protocol_handler.cc
new file mode 100755
index 00000000000..85749b3ff2d
--- /dev/null
+++ b/chromium/chrome/common/custom_handlers/protocol_handler.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/custom_handlers/protocol_handler.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "net/base/escape.h"
+
+
+ProtocolHandler::ProtocolHandler(const std::string& protocol,
+ const GURL& url)
+ : protocol_(protocol),
+ url_(url) {
+}
+
+ProtocolHandler ProtocolHandler::CreateProtocolHandler(
+ const std::string& protocol,
+ const GURL& url) {
+ std::string lower_protocol = base::ToLowerASCII(protocol);
+ return ProtocolHandler(lower_protocol, url);
+}
+
+ProtocolHandler::ProtocolHandler() {
+}
+
+bool ProtocolHandler::IsValidDict(const base::DictionaryValue* value) {
+ // Note that "title" parameter is ignored.
+ return value->HasKey("protocol") && value->HasKey("url");
+}
+
+bool ProtocolHandler::IsSameOrigin(
+ const ProtocolHandler& handler) const {
+ return handler.url().GetOrigin() == url_.GetOrigin();
+}
+
+const ProtocolHandler& ProtocolHandler::EmptyProtocolHandler() {
+ static const ProtocolHandler* const kEmpty = new ProtocolHandler();
+ return *kEmpty;
+}
+
+ProtocolHandler ProtocolHandler::CreateProtocolHandler(
+ const base::DictionaryValue* value) {
+ if (!IsValidDict(value)) {
+ return EmptyProtocolHandler();
+ }
+ std::string protocol, url;
+ value->GetString("protocol", &protocol);
+ value->GetString("url", &url);
+ return ProtocolHandler::CreateProtocolHandler(protocol, GURL(url));
+}
+
+GURL ProtocolHandler::TranslateUrl(const GURL& url) const {
+ std::string translatedUrlSpec(url_.spec());
+ base::ReplaceSubstringsAfterOffset(&translatedUrlSpec, 0, "%s",
+ net::EscapeQueryParamValue(url.spec(), true));
+ return GURL(translatedUrlSpec);
+}
+
+std::unique_ptr<base::DictionaryValue> ProtocolHandler::Encode() const {
+ auto d = base::MakeUnique<base::DictionaryValue>();
+ d->SetString("protocol", protocol_);
+ d->SetString("url", url_.spec());
+ return d;
+}
+
+#if !defined(NDEBUG)
+std::string ProtocolHandler::ToString() const {
+ return "{ protocol=" + protocol_ +
+ ", url=" + url_.spec() +
+ " }";
+}
+#endif
+
+bool ProtocolHandler::operator==(const ProtocolHandler& other) const {
+ return protocol_ == other.protocol_ && url_ == other.url_;
+}
+
+bool ProtocolHandler::IsEquivalent(const ProtocolHandler& other) const {
+ return protocol_ == other.protocol_ && url_ == other.url_;
+}
+
+bool ProtocolHandler::operator<(const ProtocolHandler& other) const {
+ return url_ < other.url_;
+}
diff --git a/chromium/chrome/common/custom_handlers/protocol_handler.h b/chromium/chrome/common/custom_handlers/protocol_handler.h
new file mode 100755
index 00000000000..69c195c7c56
--- /dev/null
+++ b/chromium/chrome/common/custom_handlers/protocol_handler.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_CUSTOM_HANDLERS_PROTOCOL_HANDLER_H_
+#define CHROME_COMMON_CUSTOM_HANDLERS_PROTOCOL_HANDLER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/values.h"
+#include "url/gurl.h"
+
+// A single tuple of (protocol, url) that indicates how URLs of the
+// given protocol should be rewritten to be handled.
+
+class ProtocolHandler {
+ public:
+ static ProtocolHandler CreateProtocolHandler(const std::string& protocol,
+ const GURL& url);
+
+ // Creates a ProtocolHandler with fields from the dictionary. Returns an
+ // empty ProtocolHandler if the input is invalid.
+ static ProtocolHandler CreateProtocolHandler(
+ const base::DictionaryValue* value);
+
+ // Returns true if the dictionary value has all the necessary fields to
+ // define a ProtocolHandler.
+ static bool IsValidDict(const base::DictionaryValue* value);
+
+ // Returns true if this handler's url has the same origin as the given one.
+ bool IsSameOrigin(const ProtocolHandler& handler) const;
+
+ // Canonical empty ProtocolHandler.
+ static const ProtocolHandler& EmptyProtocolHandler();
+
+ // Interpolates the given URL into the URL template of this handler.
+ GURL TranslateUrl(const GURL& url) const;
+
+ // Returns true if the handlers are considered equivalent when determining
+ // if both handlers can be registered, or if a handler has previously been
+ // ignored.
+ bool IsEquivalent(const ProtocolHandler& other) const;
+
+ // Encodes this protocol handler as a DictionaryValue.
+ std::unique_ptr<base::DictionaryValue> Encode() const;
+
+ const std::string& protocol() const { return protocol_; }
+ const GURL& url() const { return url_;}
+
+ bool IsEmpty() const {
+ return protocol_.empty();
+ }
+
+#if !defined(NDEBUG)
+ // Returns a string representation suitable for use in debugging.
+ std::string ToString() const;
+#endif
+
+
+ bool operator==(const ProtocolHandler& other) const;
+ bool operator<(const ProtocolHandler& other) const;
+
+ private:
+ ProtocolHandler(const std::string& protocol,
+ const GURL& url);
+ ProtocolHandler();
+
+ std::string protocol_;
+ GURL url_;
+};
+
+#endif // CHROME_COMMON_CUSTOM_HANDLERS_PROTOCOL_HANDLER_H_