This source file includes following definitions.
- LookupHandler
- ShouldRemoveHandlersNotInOS
- Enable
- Disable
- IsHandledProtocol
- ClearDefault
- SetDefault
- MaybeCreateJob
- Chain
- MaybeCreateJobWithProtocolHandler
- IsHandledProtocol
- IsHandledURL
- IsSafeRedirectTarget
- registry_
- SetDefaultWebClientUIState
- IsInteractiveSetDefaultPermitted
- SetWorker
- IsOwnedByWorker
- RegisterExternalHandler
- DeregisterExternalHandler
- IsExternalHandlerRegistered
- CreateShellWorker
- CreateShellObserver
- RegisterWithOSAsDefaultClient
- io_thread_delegate_
- SilentlyHandleRegisterHandlerRequest
- OnAcceptRegisterProtocolHandler
- OnDenyRegisterProtocolHandler
- OnIgnoreRegisterProtocolHandler
- AttemptReplace
- GetReplacedHandlers
- ClearDefault
- IsDefault
- InstallDefaultsForChromeOS
- InitProtocolSettings
- GetHandlerIndex
- GetHandlersFor
- GetIgnoredHandlers
- GetRegisteredProtocols
- CanSchemeBeOverridden
- IsRegistered
- IsIgnored
- HasRegisteredEquivalent
- HasIgnoredEquivalent
- RemoveIgnoredHandler
- IsHandledProtocol
- RemoveHandler
- RemoveDefaultHandler
- GetHandlerFor
- Enable
- Disable
- Shutdown
- RegisterProfilePrefs
- PromoteHandler
- Save
- GetHandlerList
- SetDefault
- InsertHandler
- EncodeRegisteredHandlers
- EncodeIgnoredHandlers
- NotifyChanged
- RegisterProtocolHandler
- GetHandlersFromPref
- IgnoreProtocolHandler
- AddPredefinedHandler
- CreateJobInterceptorFactory
#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
#include <utility>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/profiles/profile_io_data.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/custom_handlers/protocol_handler.h"
#include "chrome/common/pref_names.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "content/public/browser/child_process_security_policy.h"
#include "grit/generated_resources.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();
}
bool ShouldRemoveHandlersNotInOS() {
#if defined(OS_LINUX)
return false;
#else
return ShellIntegration::CanSetAsDefaultProtocolClient() !=
ShellIntegration::SET_DEFAULT_NOT_ALLOWED;
#endif
}
}
class ProtocolHandlerRegistry::IOThreadDelegate
: public base::RefCountedThreadSafe<
ProtocolHandlerRegistry::IOThreadDelegate> {
public:
explicit IOThreadDelegate(bool enabled);
bool IsHandledProtocol(const std::string& scheme) const;
void ClearDefault(const std::string& scheme);
void SetDefault(const ProtocolHandler& handler);
net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request, net::NetworkDelegate* network_delegate) const;
void Enable() { enabled_ = true; }
void Disable() { enabled_ = false; }
private:
friend class base::RefCountedThreadSafe<IOThreadDelegate>;
virtual ~IOThreadDelegate();
ProtocolHandlerRegistry::ProtocolHandlerMap default_handlers_;
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(BrowserThread::CurrentlyOn(BrowserThread::IO));
return enabled_ && !LookupHandler(default_handlers_, scheme).IsEmpty();
}
void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault(
const std::string& scheme) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
default_handlers_.erase(scheme);
}
void ProtocolHandlerRegistry::IOThreadDelegate::SetDefault(
const ProtocolHandler& handler) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
ClearDefault(handler.protocol());
default_handlers_.insert(std::make_pair(handler.protocol(), handler));
}
net::URLRequestJob* ProtocolHandlerRegistry::IOThreadDelegate::MaybeCreateJob(
net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
DCHECK(BrowserThread::CurrentlyOn(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");
}
ProtocolHandlerRegistry::JobInterceptorFactory::JobInterceptorFactory(
IOThreadDelegate* io_thread_delegate)
: io_thread_delegate_(io_thread_delegate) {
DCHECK(io_thread_delegate_.get());
DetachFromThread();
}
ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() {
}
void ProtocolHandlerRegistry::JobInterceptorFactory::Chain(
scoped_ptr<net::URLRequestJobFactory> job_factory) {
job_factory_ = job_factory.Pass();
}
net::URLRequestJob*
ProtocolHandlerRegistry::JobInterceptorFactory::
MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
net::URLRequestJob* job = io_thread_delegate_->MaybeCreateJob(
request, network_delegate);
if (job)
return job;
return job_factory_->MaybeCreateJobWithProtocolHandler(
scheme, request, network_delegate);
}
bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledProtocol(
const std::string& scheme) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
return io_thread_delegate_->IsHandledProtocol(scheme) ||
job_factory_->IsHandledProtocol(scheme);
}
bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledURL(
const GURL& url) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
return (url.is_valid() &&
io_thread_delegate_->IsHandledProtocol(url.scheme())) ||
job_factory_->IsHandledURL(url);
}
bool ProtocolHandlerRegistry::JobInterceptorFactory::IsSafeRedirectTarget(
const GURL& location) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
return job_factory_->IsSafeRedirectTarget(location);
}
ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver(
ProtocolHandlerRegistry* registry)
: worker_(NULL),
registry_(registry) {
DCHECK(registry_);
}
ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() {
if (worker_)
worker_->ObserverDestroyed();
DefaultClientObserverList::iterator iter = std::find(
registry_->default_client_observers_.begin(),
registry_->default_client_observers_.end(), this);
registry_->default_client_observers_.erase(iter);
}
void ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState(
ShellIntegration::DefaultWebClientUIState state) {
if (worker_) {
if (ShouldRemoveHandlersNotInOS() &&
(state == ShellIntegration::STATE_NOT_DEFAULT)) {
registry_->ClearDefault(worker_->protocol());
}
} else {
NOTREACHED();
}
}
bool ProtocolHandlerRegistry::DefaultClientObserver::
IsInteractiveSetDefaultPermitted() {
return true;
}
void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker(
ShellIntegration::DefaultProtocolClientWorker* worker) {
worker_ = worker;
}
bool ProtocolHandlerRegistry::DefaultClientObserver::IsOwnedByWorker() {
return true;
}
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) {
return ProfileIOData::IsHandledProtocol(protocol);
}
ShellIntegration::DefaultProtocolClientWorker*
ProtocolHandlerRegistry::Delegate::CreateShellWorker(
ShellIntegration::DefaultWebClientObserver* observer,
const std::string& protocol) {
return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol);
}
ProtocolHandlerRegistry::DefaultClientObserver*
ProtocolHandlerRegistry::Delegate::CreateShellObserver(
ProtocolHandlerRegistry* registry) {
return new DefaultClientObserver(registry);
}
void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient(
const std::string& protocol, ProtocolHandlerRegistry* registry) {
DefaultClientObserver* observer = CreateShellObserver(registry);
scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker;
worker = CreateShellWorker(observer, protocol);
observer->SetWorker(worker.get());
registry->default_client_observers_.push_back(observer);
worker->StartSetAsDefault();
}
ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile,
Delegate* delegate)
: profile_(profile),
delegate_(delegate),
enabled_(true),
is_loading_(false),
is_loaded_(false),
io_thread_delegate_(new IOThreadDelegate(enabled_)){
}
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(BrowserThread::CurrentlyOn(BrowserThread::UI));
RegisterProtocolHandler(handler);
SetDefault(handler);
Save();
NotifyChanged();
}
void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
const ProtocolHandler& handler) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
RegisterProtocolHandler(handler);
Save();
NotifyChanged();
}
void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
const ProtocolHandler& handler) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
IgnoreProtocolHandler(handler);
Save();
NotifyChanged();
}
bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) {
DCHECK(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::UI));
default_handlers_.erase(scheme);
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_, scheme));
Save();
NotifyChanged();
}
bool ProtocolHandlerRegistry::IsDefault(
const ProtocolHandler& handler) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return GetHandlerFor(handler.protocol()) == handler;
}
void ProtocolHandlerRegistry::InstallDefaultsForChromeOS() {
#if defined(OS_CHROMEOS)
AddPredefinedHandler(
ProtocolHandler::CreateProtocolHandler(
"mailto",
GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_MAILTO_HANDLER_URL)),
l10n_util::GetStringUTF16(IDS_GOOGLE_MAILTO_HANDLER_NAME)));
AddPredefinedHandler(
ProtocolHandler::CreateProtocolHandler(
"webcal",
GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL)),
l10n_util::GetStringUTF16(IDS_GOOGLE_WEBCAL_HANDLER_NAME)));
#else
NOTREACHED();
#endif
}
void ProtocolHandlerRegistry::InitProtocolSettings() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
is_loaded_ = true;
is_loading_ = true;
PrefService* prefs = profile_->GetPrefs();
if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) {
if (prefs->GetBoolean(prefs::kCustomHandlersEnabled)) {
Enable();
} else {
Disable();
}
}
std::vector<const base::DictionaryValue*> registered_handlers =
GetHandlersFromPref(prefs::kRegisteredProtocolHandlers);
for (std::vector<const base::DictionaryValue*>::const_iterator p =
registered_handlers.begin();
p != registered_handlers.end(); ++p) {
ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p);
RegisterProtocolHandler(handler);
bool is_default = false;
if ((*p)->GetBoolean("default", &is_default) && is_default) {
SetDefault(handler);
}
}
std::vector<const base::DictionaryValue*> ignored_handlers =
GetHandlersFromPref(prefs::kIgnoredProtocolHandlers);
for (std::vector<const base::DictionaryValue*>::const_iterator p =
ignored_handlers.begin();
p != ignored_handlers.end(); ++p) {
IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p));
}
is_loading_ = false;
if (ShouldRemoveHandlersNotInOS()) {
for (ProtocolHandlerMap::const_iterator p = default_handlers_.begin();
p != default_handlers_.end(); ++p) {
ProtocolHandler handler = p->second;
DefaultClientObserver* observer = delegate_->CreateShellObserver(this);
scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker;
worker = delegate_->CreateShellWorker(observer, handler.protocol());
observer->SetWorker(worker.get());
default_client_observers_.push_back(observer);
worker->StartCheckIsDefault();
}
}
}
int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const {
DCHECK(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::UI));
const ProtocolHandlerList* handlers = GetHandlerList(scheme);
if (handlers != NULL && !handlers->empty())
return true;
return !delegate_->IsExternalHandlerRegistered(scheme);
}
bool ProtocolHandlerRegistry::IsRegistered(
const ProtocolHandler& handler) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
if (!handlers) {
return false;
}
return std::find(handlers->begin(), handlers->end(), handler) !=
handlers->end();
}
bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const {
DCHECK(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::UI));
bool should_notify = false;
ProtocolHandlerList::iterator p = std::find(
ignored_protocol_handlers_.begin(), ignored_protocol_handlers_.end(),
handler);
if (p != ignored_protocol_handlers_.end()) {
ignored_protocol_handlers_.erase(p);
Save();
should_notify = true;
}
if (should_notify)
NotifyChanged();
}
bool ProtocolHandlerRegistry::IsHandledProtocol(
const std::string& scheme) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return enabled_ && !GetHandlerFor(scheme).IsEmpty();
}
void ProtocolHandlerRegistry::RemoveHandler(
const ProtocolHandler& handler) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()];
ProtocolHandlerList::iterator p =
std::find(handlers.begin(), handlers.end(), handler);
if (p != handlers.end()) {
handlers.erase(p);
}
ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol());
if (q != default_handlers_.end() && q->second == handler) {
if (!handlers.empty()) {
SetDefault(ProtocolHandler(handlers[0]));
} else {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_,
q->second.protocol()));
default_handlers_.erase(q);
}
}
if (!IsHandledProtocol(handler.protocol())) {
delegate_->DeregisterExternalHandler(handler.protocol());
}
Save();
NotifyChanged();
}
void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
ProtocolHandler current_default = GetHandlerFor(scheme);
if (!current_default.IsEmpty())
RemoveHandler(current_default);
}
const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor(
const std::string& scheme) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return LookupHandler(default_handlers_, scheme);
}
void ProtocolHandlerRegistry::Enable() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (enabled_) {
return;
}
enabled_ = true;
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&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(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!enabled_) {
return;
}
enabled_ = false;
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&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(BrowserThread::CurrentlyOn(BrowserThread::UI));
delegate_.reset(NULL);
while (!default_client_observers_.empty()) {
delete default_client_observers_.back();
}
}
void ProtocolHandlerRegistry::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterListPref(prefs::kRegisteredProtocolHandlers,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
registry->RegisterListPref(prefs::kIgnoredProtocolHandlers,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
registry->RegisterBooleanPref(
prefs::kCustomHandlersEnabled,
true,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}
ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(default_client_observers_.empty());
}
void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) {
DCHECK(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (is_loading_) {
return;
}
scoped_ptr<base::Value> registered_protocol_handlers(
EncodeRegisteredHandlers());
scoped_ptr<base::Value> ignored_protocol_handlers(EncodeIgnoredHandlers());
scoped_ptr<base::Value> enabled(base::Value::CreateBooleanValue(enabled_));
profile_->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers,
*registered_protocol_handlers);
profile_->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers,
*ignored_protocol_handlers);
profile_->GetPrefs()->Set(prefs::kCustomHandlersEnabled, *enabled);
}
const ProtocolHandlerRegistry::ProtocolHandlerList*
ProtocolHandlerRegistry::GetHandlerList(
const std::string& scheme) const {
DCHECK(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::UI));
ProtocolHandlerMap::const_iterator p = default_handlers_.find(
handler.protocol());
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::Bind(&IOThreadDelegate::SetDefault, io_thread_delegate_, handler));
}
void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) {
DCHECK(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::UI));
base::ListValue* protocol_handlers = new base::ListValue();
for (ProtocolHandlerMultiMap::iterator i = protocol_handlers_.begin();
i != protocol_handlers_.end(); ++i) {
for (ProtocolHandlerList::iterator j = i->second.begin();
j != i->second.end(); ++j) {
base::DictionaryValue* encoded = j->Encode();
if (IsDefault(*j)) {
encoded->Set("default", base::Value::CreateBooleanValue(true));
}
protocol_handlers->Append(encoded);
}
}
return protocol_handlers;
}
base::Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
base::ListValue* handlers = new base::ListValue();
for (ProtocolHandlerList::iterator i = ignored_protocol_handlers_.begin();
i != ignored_protocol_handlers_.end(); ++i) {
handlers->Append(i->Encode());
}
return handlers;
}
void ProtocolHandlerRegistry::NotifyChanged() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
content::Source<Profile>(profile_),
content::NotificationService::NoDetails());
}
void ProtocolHandlerRegistry::RegisterProtocolHandler(
const ProtocolHandler& handler) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(CanSchemeBeOverridden(handler.protocol()));
DCHECK(!handler.IsEmpty());
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(BrowserThread::CurrentlyOn(BrowserThread::UI));
std::vector<const base::DictionaryValue*> result;
PrefService* prefs = profile_->GetPrefs();
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::IgnoreProtocolHandler(
const ProtocolHandler& handler) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
ignored_protocol_handlers_.push_back(handler);
}
void ProtocolHandlerRegistry::AddPredefinedHandler(
const ProtocolHandler& handler) {
DCHECK(!is_loaded_);
RegisterProtocolHandler(handler);
SetDefault(handler);
}
scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
ProtocolHandlerRegistry::CreateJobInterceptorFactory() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return scoped_ptr<JobInterceptorFactory>(
new JobInterceptorFactory(io_thread_delegate_.get()));
}