OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/custom_handlers/protocol_handler_registry.h" | 5 #include "chrome/browser/custom_handlers/protocol_handler_registry.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
13 #include "chrome/browser/custom_handlers/register_protocol_handler_infobar_deleg
ate.h" | 13 #include "chrome/browser/custom_handlers/register_protocol_handler_infobar_deleg
ate.h" |
14 #include "chrome/browser/net/chrome_url_request_context.h" | 14 #include "chrome/browser/net/chrome_url_request_context.h" |
15 #include "chrome/browser/prefs/pref_service.h" | 15 #include "chrome/browser/prefs/pref_service.h" |
16 #include "chrome/browser/profiles/profile_io_data.h" | 16 #include "chrome/browser/profiles/profile_io_data.h" |
17 #include "chrome/common/chrome_notification_types.h" | 17 #include "chrome/common/chrome_notification_types.h" |
18 #include "chrome/common/chrome_switches.h" | 18 #include "chrome/common/chrome_switches.h" |
19 #include "chrome/common/custom_handlers/protocol_handler.h" | 19 #include "chrome/common/custom_handlers/protocol_handler.h" |
20 #include "chrome/common/pref_names.h" | 20 #include "chrome/common/pref_names.h" |
21 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
22 #include "content/public/browser/child_process_security_policy.h" | 22 #include "content/public/browser/child_process_security_policy.h" |
23 #include "content/public/browser/notification_service.h" | 23 #include "content/public/browser/notification_service.h" |
24 #include "net/base/network_delegate.h" | 24 #include "net/base/network_delegate.h" |
25 #include "net/url_request/url_request_redirect_job.h" | 25 #include "net/url_request/url_request_redirect_job.h" |
26 | 26 |
27 using content::BrowserThread; | 27 using content::BrowserThread; |
28 using content::ChildProcessSecurityPolicy; | 28 using content::ChildProcessSecurityPolicy; |
29 | 29 |
30 // ProtocolHandlerRegistry ----------------------------------------------------- | |
31 | |
32 ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile, | |
33 Delegate* delegate) | |
34 : profile_(profile), | |
35 delegate_(delegate), | |
36 enabled_(true), | |
37 enabled_io_(enabled_), | |
38 is_loading_(false) { | |
39 } | |
40 | |
41 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() { | |
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
43 DCHECK(default_client_observers_.empty()); | |
44 } | |
45 | |
46 void ProtocolHandlerRegistry::Finalize() { | |
47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
48 delegate_.reset(NULL); | |
49 // We free these now in case there are any outstanding workers running. If | |
50 // we didn't free them they could respond to workers and try to update the | |
51 // protocol handler registry after it was deleted. | |
52 // Observers remove themselves from this list when they are deleted; so | |
53 // we delete the last item until none are left in the list. | |
54 while (!default_client_observers_.empty()) { | |
55 delete default_client_observers_.back(); | |
56 } | |
57 } | |
58 | |
59 const ProtocolHandlerRegistry::ProtocolHandlerList* | |
60 ProtocolHandlerRegistry::GetHandlerList( | |
61 const std::string& scheme) const { | |
62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
63 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); | |
64 if (p == protocol_handlers_.end()) { | |
65 return NULL; | |
66 } | |
67 return &p->second; | |
68 } | |
69 | |
70 ProtocolHandlerRegistry::ProtocolHandlerList | |
71 ProtocolHandlerRegistry::GetHandlersFor( | |
72 const std::string& scheme) const { | |
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
74 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); | |
75 if (p == protocol_handlers_.end()) { | |
76 return ProtocolHandlerList(); | |
77 } | |
78 return p->second; | |
79 } | |
80 | |
81 ProtocolHandlerRegistry::ProtocolHandlerList | |
82 ProtocolHandlerRegistry::GetIgnoredHandlers() { | |
83 return ignored_protocol_handlers_; | |
84 } | |
85 | |
86 void ProtocolHandlerRegistry::RegisterProtocolHandler( | |
87 const ProtocolHandler& handler) { | |
88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
89 DCHECK(CanSchemeBeOverridden(handler.protocol())); | |
90 DCHECK(!handler.IsEmpty()); | |
91 if (IsRegistered(handler)) { | |
92 return; | |
93 } | |
94 if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol())) | |
95 delegate_->RegisterExternalHandler(handler.protocol()); | |
96 InsertHandler(handler); | |
97 } | |
98 | |
99 void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) { | |
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
101 ProtocolHandlerMultiMap::iterator p = | |
102 protocol_handlers_.find(handler.protocol()); | |
103 | |
104 if (p != protocol_handlers_.end()) { | |
105 p->second.push_back(handler); | |
106 return; | |
107 } | |
108 | |
109 ProtocolHandlerList new_list; | |
110 new_list.push_back(handler); | |
111 protocol_handlers_[handler.protocol()] = new_list; | |
112 } | |
113 | |
114 void ProtocolHandlerRegistry::IgnoreProtocolHandler( | |
115 const ProtocolHandler& handler) { | |
116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
117 ignored_protocol_handlers_.push_back(handler); | |
118 } | |
119 | |
120 void ProtocolHandlerRegistry::Enable() { | |
121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
122 if (enabled_) { | |
123 return; | |
124 } | |
125 enabled_ = true; | |
126 BrowserThread::PostTask( | |
127 BrowserThread::IO, | |
128 FROM_HERE, | |
129 base::Bind(&ProtocolHandlerRegistry::EnableIO, this)); | |
130 ProtocolHandlerMap::const_iterator p; | |
131 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { | |
132 delegate_->RegisterExternalHandler(p->first); | |
133 } | |
134 Save(); | |
135 NotifyChanged(); | |
136 } | |
137 | |
138 void ProtocolHandlerRegistry::Disable() { | |
139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
140 if (!enabled_) { | |
141 return; | |
142 } | |
143 enabled_ = false; | |
144 BrowserThread::PostTask( | |
145 BrowserThread::IO, | |
146 FROM_HERE, | |
147 base::Bind(&ProtocolHandlerRegistry::DisableIO, this)); | |
148 ProtocolHandlerMap::const_iterator p; | |
149 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { | |
150 delegate_->DeregisterExternalHandler(p->first); | |
151 } | |
152 Save(); | |
153 NotifyChanged(); | |
154 } | |
155 | |
156 std::vector<const DictionaryValue*> | |
157 ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const { | |
158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
159 std::vector<const DictionaryValue*> result; | |
160 PrefService* prefs = profile_->GetPrefs(); | |
161 if (!prefs->HasPrefPath(pref_name)) { | |
162 return result; | |
163 } | |
164 | |
165 const ListValue* handlers = prefs->GetList(pref_name); | |
166 if (handlers) { | |
167 for (size_t i = 0; i < handlers->GetSize(); ++i) { | |
168 DictionaryValue* dict; | |
169 if (!handlers->GetDictionary(i, &dict)) | |
170 continue; | |
171 if (ProtocolHandler::IsValidDict(dict)) { | |
172 result.push_back(dict); | |
173 } | |
174 } | |
175 } | |
176 return result; | |
177 } | |
178 | |
179 namespace { | 30 namespace { |
180 | 31 |
181 // If true default protocol handlers will be removed if the OS level | 32 // If true default protocol handlers will be removed if the OS level |
182 // registration for a protocol is no longer Chrome. | 33 // registration for a protocol is no longer Chrome. |
183 bool ShouldRemoveHandlersNotInOS() { | 34 bool ShouldRemoveHandlersNotInOS() { |
184 #if defined(OS_LINUX) | 35 #if defined(OS_LINUX) |
185 // We don't do this on Linux as the OS registration there is not reliable, | 36 // We don't do this on Linux as the OS registration there is not reliable, |
186 // and Chrome OS doesn't have any notion of OS registration. | 37 // and Chrome OS doesn't have any notion of OS registration. |
187 // TODO(benwells): When Linux support is more reliable remove this | 38 // TODO(benwells): When Linux support is more reliable remove this |
188 // difference (http://crbug.com/88255). | 39 // difference (http://crbug.com/88255). |
189 return false; | 40 return false; |
190 #else | 41 #else |
191 return ShellIntegration::CanSetAsDefaultProtocolClient(); | 42 return ShellIntegration::CanSetAsDefaultProtocolClient(); |
192 #endif | 43 #endif |
193 } | 44 } |
194 | 45 |
195 } // namespace | 46 } // namespace |
196 | 47 |
| 48 static const ProtocolHandler& LookupHandler( |
| 49 const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map, |
| 50 const std::string& scheme) { |
| 51 ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p = |
| 52 handler_map.find(scheme); |
| 53 if (p != handler_map.end()) { |
| 54 return p->second; |
| 55 } |
| 56 return ProtocolHandler::EmptyProtocolHandler(); |
| 57 } |
| 58 |
| 59 // DefaultClientObserver ------------------------------------------------------ |
| 60 |
| 61 ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver( |
| 62 ProtocolHandlerRegistry* registry) |
| 63 : worker_(NULL), |
| 64 registry_(registry) { |
| 65 DCHECK(registry_); |
| 66 } |
| 67 |
| 68 ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() { |
| 69 if (worker_) |
| 70 worker_->ObserverDestroyed(); |
| 71 |
| 72 DefaultClientObserverList::iterator iter = std::find( |
| 73 registry_->default_client_observers_.begin(), |
| 74 registry_->default_client_observers_.end(), this); |
| 75 registry_->default_client_observers_.erase(iter); |
| 76 } |
| 77 |
| 78 void |
| 79 ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState( |
| 80 ShellIntegration::DefaultWebClientUIState state) { |
| 81 if (worker_) { |
| 82 if (ShouldRemoveHandlersNotInOS() && |
| 83 (state == ShellIntegration::STATE_NOT_DEFAULT)) { |
| 84 registry_->ClearDefault(worker_->protocol()); |
| 85 } |
| 86 } else { |
| 87 NOTREACHED(); |
| 88 } |
| 89 } |
| 90 |
| 91 void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker( |
| 92 ShellIntegration::DefaultProtocolClientWorker* worker) { |
| 93 worker_ = worker; |
| 94 } |
| 95 |
| 96 // Delegate -------------------------------------------------------------------- |
| 97 |
| 98 ProtocolHandlerRegistry::Delegate::~Delegate() {} |
| 99 |
| 100 void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler( |
| 101 const std::string& protocol) { |
| 102 ChildProcessSecurityPolicy* policy = |
| 103 ChildProcessSecurityPolicy::GetInstance(); |
| 104 if (!policy->IsWebSafeScheme(protocol)) { |
| 105 policy->RegisterWebSafeScheme(protocol); |
| 106 } |
| 107 } |
| 108 |
| 109 void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler( |
| 110 const std::string& protocol) { |
| 111 } |
| 112 |
| 113 bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered( |
| 114 const std::string& protocol) { |
| 115 // NOTE(koz): This function is safe to call from any thread, despite living |
| 116 // in ProfileIOData. |
| 117 return ProfileIOData::IsHandledProtocol(protocol); |
| 118 } |
| 119 |
| 120 ShellIntegration::DefaultProtocolClientWorker* |
| 121 ProtocolHandlerRegistry::Delegate::CreateShellWorker( |
| 122 ShellIntegration::DefaultWebClientObserver* observer, |
| 123 const std::string& protocol) { |
| 124 return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol); |
| 125 } |
| 126 |
| 127 ProtocolHandlerRegistry::DefaultClientObserver* |
| 128 ProtocolHandlerRegistry::Delegate::CreateShellObserver( |
| 129 ProtocolHandlerRegistry* registry) { |
| 130 return new DefaultClientObserver(registry); |
| 131 } |
| 132 |
| 133 void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient( |
| 134 const std::string& protocol, ProtocolHandlerRegistry* registry) { |
| 135 DefaultClientObserver* observer = CreateShellObserver(registry); |
| 136 // The worker pointer is reference counted. While it is running the |
| 137 // message loops of the FILE and UI thread will hold references to it |
| 138 // and it will be automatically freed once all its tasks have finished. |
| 139 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; |
| 140 worker = CreateShellWorker(observer, protocol); |
| 141 observer->SetWorker(worker); |
| 142 registry->default_client_observers_.push_back(observer); |
| 143 worker->StartSetAsDefault(); |
| 144 } |
| 145 |
| 146 // ProtocolHandlerRegistry ----------------------------------------------------- |
| 147 |
| 148 ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile, |
| 149 Delegate* delegate) |
| 150 : profile_(profile), |
| 151 delegate_(delegate), |
| 152 enabled_(true), |
| 153 enabled_io_(enabled_), |
| 154 is_loading_(false) { |
| 155 } |
| 156 |
| 157 bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest( |
| 158 const ProtocolHandler& handler) { |
| 159 if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol())) |
| 160 return true; |
| 161 |
| 162 if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler)) |
| 163 return true; |
| 164 |
| 165 if (AttemptReplace(handler)) |
| 166 return true; |
| 167 |
| 168 return false; |
| 169 } |
| 170 |
| 171 void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler( |
| 172 const ProtocolHandler& handler) { |
| 173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 174 RegisterProtocolHandler(handler); |
| 175 SetDefault(handler); |
| 176 Save(); |
| 177 NotifyChanged(); |
| 178 } |
| 179 |
| 180 void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler( |
| 181 const ProtocolHandler& handler) { |
| 182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 183 RegisterProtocolHandler(handler); |
| 184 Save(); |
| 185 NotifyChanged(); |
| 186 } |
| 187 |
| 188 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler( |
| 189 const ProtocolHandler& handler) { |
| 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 191 IgnoreProtocolHandler(handler); |
| 192 Save(); |
| 193 NotifyChanged(); |
| 194 } |
| 195 |
| 196 bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) { |
| 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 198 ProtocolHandler old_default = GetHandlerFor(handler.protocol()); |
| 199 bool make_new_handler_default = handler.IsSameOrigin(old_default); |
| 200 ProtocolHandlerList to_replace(GetReplacedHandlers(handler)); |
| 201 if (to_replace.empty()) |
| 202 return false; |
| 203 for (ProtocolHandlerList::iterator p = to_replace.begin(); |
| 204 p != to_replace.end(); ++p) { |
| 205 RemoveHandler(*p); |
| 206 } |
| 207 if (make_new_handler_default) { |
| 208 OnAcceptRegisterProtocolHandler(handler); |
| 209 } else { |
| 210 InsertHandler(handler); |
| 211 NotifyChanged(); |
| 212 } |
| 213 return true; |
| 214 } |
| 215 |
| 216 ProtocolHandlerRegistry::ProtocolHandlerList |
| 217 ProtocolHandlerRegistry::GetReplacedHandlers( |
| 218 const ProtocolHandler& handler) const { |
| 219 ProtocolHandlerList replaced_handlers; |
| 220 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); |
| 221 if (!handlers) |
| 222 return replaced_handlers; |
| 223 for (ProtocolHandlerList::const_iterator p = handlers->begin(); |
| 224 p != handlers->end(); p++) { |
| 225 if (handler.IsSameOrigin(*p)) { |
| 226 replaced_handlers.push_back(*p); |
| 227 } |
| 228 } |
| 229 return replaced_handlers; |
| 230 } |
| 231 |
| 232 void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) { |
| 233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 234 default_handlers_.erase(scheme); |
| 235 BrowserThread::PostTask( |
| 236 BrowserThread::IO, |
| 237 FROM_HERE, |
| 238 base::Bind(&ProtocolHandlerRegistry::ClearDefaultIO, this, scheme)); |
| 239 Save(); |
| 240 NotifyChanged(); |
| 241 } |
| 242 |
| 243 bool ProtocolHandlerRegistry::IsDefault( |
| 244 const ProtocolHandler& handler) const { |
| 245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 246 return GetHandlerFor(handler.protocol()) == handler; |
| 247 } |
| 248 |
197 void ProtocolHandlerRegistry::Load() { | 249 void ProtocolHandlerRegistry::Load() { |
198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
199 is_loading_ = true; | 251 is_loading_ = true; |
200 PrefService* prefs = profile_->GetPrefs(); | 252 PrefService* prefs = profile_->GetPrefs(); |
201 if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) { | 253 if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) { |
202 enabled_ = prefs->GetBoolean(prefs::kCustomHandlersEnabled); | 254 enabled_ = prefs->GetBoolean(prefs::kCustomHandlersEnabled); |
203 BrowserThread::PostTask( | 255 BrowserThread::PostTask( |
204 BrowserThread::IO, | 256 BrowserThread::IO, |
205 FROM_HERE, | 257 FROM_HERE, |
206 base::Bind(enabled_ ? &ProtocolHandlerRegistry::EnableIO : | 258 base::Bind(enabled_ ? &ProtocolHandlerRegistry::EnableIO : |
(...skipping 29 matching lines...) Expand all Loading... |
236 DefaultClientObserver* observer = delegate_->CreateShellObserver(this); | 288 DefaultClientObserver* observer = delegate_->CreateShellObserver(this); |
237 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; | 289 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; |
238 worker = delegate_->CreateShellWorker(observer, handler.protocol()); | 290 worker = delegate_->CreateShellWorker(observer, handler.protocol()); |
239 observer->SetWorker(worker); | 291 observer->SetWorker(worker); |
240 default_client_observers_.push_back(observer); | 292 default_client_observers_.push_back(observer); |
241 worker->StartCheckIsDefault(); | 293 worker->StartCheckIsDefault(); |
242 } | 294 } |
243 } | 295 } |
244 } | 296 } |
245 | 297 |
246 void ProtocolHandlerRegistry::Save() { | 298 int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const { |
247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
248 if (is_loading_) { | 300 const ProtocolHandler& handler = GetHandlerFor(scheme); |
249 return; | 301 if (handler.IsEmpty()) |
| 302 return -1; |
| 303 const ProtocolHandlerList* handlers = GetHandlerList(scheme); |
| 304 if (!handlers) |
| 305 return -1; |
| 306 |
| 307 ProtocolHandlerList::const_iterator p; |
| 308 int i; |
| 309 for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) { |
| 310 if (*p == handler) |
| 311 return i; |
250 } | 312 } |
251 scoped_ptr<Value> registered_protocol_handlers(EncodeRegisteredHandlers()); | 313 return -1; |
252 scoped_ptr<Value> ignored_protocol_handlers(EncodeIgnoredHandlers()); | |
253 scoped_ptr<Value> enabled(Value::CreateBooleanValue(enabled_)); | |
254 profile_->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers, | |
255 *registered_protocol_handlers); | |
256 profile_->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers, | |
257 *ignored_protocol_handlers); | |
258 profile_->GetPrefs()->Set(prefs::kCustomHandlersEnabled, *enabled); | |
259 } | 314 } |
260 | 315 |
261 bool ProtocolHandlerRegistry::CanSchemeBeOverridden( | 316 ProtocolHandlerRegistry::ProtocolHandlerList |
| 317 ProtocolHandlerRegistry::GetHandlersFor( |
262 const std::string& scheme) const { | 318 const std::string& scheme) const { |
263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
264 const ProtocolHandlerList* handlers = GetHandlerList(scheme); | 320 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); |
265 // If we already have a handler for this scheme, we can add more. | 321 if (p == protocol_handlers_.end()) { |
266 if (handlers != NULL && !handlers->empty()) | 322 return ProtocolHandlerList(); |
267 return true; | 323 } |
268 // Don't override a scheme if it already has an external handler. | 324 return p->second; |
269 return !delegate_->IsExternalHandlerRegistered(scheme); | 325 } |
| 326 |
| 327 ProtocolHandlerRegistry::ProtocolHandlerList |
| 328 ProtocolHandlerRegistry::GetIgnoredHandlers() { |
| 329 return ignored_protocol_handlers_; |
270 } | 330 } |
271 | 331 |
272 void ProtocolHandlerRegistry::GetRegisteredProtocols( | 332 void ProtocolHandlerRegistry::GetRegisteredProtocols( |
273 std::vector<std::string>* output) const { | 333 std::vector<std::string>* output) const { |
274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
275 ProtocolHandlerMultiMap::const_iterator p; | 335 ProtocolHandlerMultiMap::const_iterator p; |
276 for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) { | 336 for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) { |
277 if (!p->second.empty()) | 337 if (!p->second.empty()) |
278 output->push_back(p->first); | 338 output->push_back(p->first); |
279 } | 339 } |
280 } | 340 } |
281 | 341 |
282 void ProtocolHandlerRegistry::RemoveIgnoredHandler( | 342 bool ProtocolHandlerRegistry::CanSchemeBeOverridden( |
283 const ProtocolHandler& handler) { | 343 const std::string& scheme) const { |
284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
285 bool should_notify = false; | 345 const ProtocolHandlerList* handlers = GetHandlerList(scheme); |
286 ProtocolHandlerList::iterator p = std::find( | 346 // If we already have a handler for this scheme, we can add more. |
287 ignored_protocol_handlers_.begin(), ignored_protocol_handlers_.end(), | 347 if (handlers != NULL && !handlers->empty()) |
288 handler); | 348 return true; |
289 if (p != ignored_protocol_handlers_.end()) { | 349 // Don't override a scheme if it already has an external handler. |
290 ignored_protocol_handlers_.erase(p); | 350 return !delegate_->IsExternalHandlerRegistered(scheme); |
291 Save(); | |
292 should_notify = true; | |
293 } | |
294 if (should_notify) | |
295 NotifyChanged(); | |
296 } | 351 } |
297 | 352 |
298 bool ProtocolHandlerRegistry::IsRegistered( | 353 bool ProtocolHandlerRegistry::IsRegistered( |
299 const ProtocolHandler& handler) const { | 354 const ProtocolHandler& handler) const { |
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
301 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); | 356 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); |
302 if (!handlers) { | 357 if (!handlers) { |
303 return false; | 358 return false; |
304 } | 359 } |
305 return std::find(handlers->begin(), handlers->end(), handler) != | 360 return std::find(handlers->begin(), handlers->end(), handler) != |
306 handlers->end(); | 361 handlers->end(); |
307 } | 362 } |
308 | 363 |
| 364 bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const { |
| 365 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 366 ProtocolHandlerList::const_iterator i; |
| 367 for (i = ignored_protocol_handlers_.begin(); |
| 368 i != ignored_protocol_handlers_.end(); ++i) { |
| 369 if (*i == handler) { |
| 370 return true; |
| 371 } |
| 372 } |
| 373 return false; |
| 374 } |
| 375 |
309 bool ProtocolHandlerRegistry::HasRegisteredEquivalent( | 376 bool ProtocolHandlerRegistry::HasRegisteredEquivalent( |
310 const ProtocolHandler& handler) const { | 377 const ProtocolHandler& handler) const { |
311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
312 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); | 379 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); |
313 if (!handlers) { | 380 if (!handlers) { |
314 return false; | 381 return false; |
315 } | 382 } |
316 ProtocolHandlerList::const_iterator i; | 383 ProtocolHandlerList::const_iterator i; |
317 for (i = handlers->begin(); i != handlers->end(); ++i) { | 384 for (i = handlers->begin(); i != handlers->end(); ++i) { |
318 if (handler.IsEquivalent(*i)) { | 385 if (handler.IsEquivalent(*i)) { |
319 return true; | 386 return true; |
320 } | 387 } |
321 } | 388 } |
322 return false; | 389 return false; |
323 } | 390 } |
324 | 391 |
325 bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const { | |
326 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
327 ProtocolHandlerList::const_iterator i; | |
328 for (i = ignored_protocol_handlers_.begin(); | |
329 i != ignored_protocol_handlers_.end(); ++i) { | |
330 if (*i == handler) { | |
331 return true; | |
332 } | |
333 } | |
334 return false; | |
335 } | |
336 | |
337 bool ProtocolHandlerRegistry::HasIgnoredEquivalent( | 392 bool ProtocolHandlerRegistry::HasIgnoredEquivalent( |
338 const ProtocolHandler& handler) const { | 393 const ProtocolHandler& handler) const { |
339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 394 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
340 ProtocolHandlerList::const_iterator i; | 395 ProtocolHandlerList::const_iterator i; |
341 for (i = ignored_protocol_handlers_.begin(); | 396 for (i = ignored_protocol_handlers_.begin(); |
342 i != ignored_protocol_handlers_.end(); ++i) { | 397 i != ignored_protocol_handlers_.end(); ++i) { |
343 if (handler.IsEquivalent(*i)) { | 398 if (handler.IsEquivalent(*i)) { |
344 return true; | 399 return true; |
345 } | 400 } |
346 } | 401 } |
347 return false; | 402 return false; |
348 } | 403 } |
349 | 404 |
| 405 void ProtocolHandlerRegistry::RemoveIgnoredHandler( |
| 406 const ProtocolHandler& handler) { |
| 407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 408 bool should_notify = false; |
| 409 ProtocolHandlerList::iterator p = std::find( |
| 410 ignored_protocol_handlers_.begin(), ignored_protocol_handlers_.end(), |
| 411 handler); |
| 412 if (p != ignored_protocol_handlers_.end()) { |
| 413 ignored_protocol_handlers_.erase(p); |
| 414 Save(); |
| 415 should_notify = true; |
| 416 } |
| 417 if (should_notify) |
| 418 NotifyChanged(); |
| 419 } |
| 420 |
350 bool ProtocolHandlerRegistry::IsHandledProtocol( | 421 bool ProtocolHandlerRegistry::IsHandledProtocol( |
351 const std::string& scheme) const { | 422 const std::string& scheme) const { |
352 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
353 return enabled_ && !GetHandlerFor(scheme).IsEmpty(); | 424 return enabled_ && !GetHandlerFor(scheme).IsEmpty(); |
354 } | 425 } |
355 | 426 |
| 427 bool ProtocolHandlerRegistry::IsHandledProtocolIO( |
| 428 const std::string& scheme) const { |
| 429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 430 return enabled_io_ && !LookupHandler(default_handlers_io_, scheme).IsEmpty(); |
| 431 } |
| 432 |
356 void ProtocolHandlerRegistry::RemoveHandler( | 433 void ProtocolHandlerRegistry::RemoveHandler( |
357 const ProtocolHandler& handler) { | 434 const ProtocolHandler& handler) { |
358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
359 ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()]; | 436 ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()]; |
360 ProtocolHandlerList::iterator p = | 437 ProtocolHandlerList::iterator p = |
361 std::find(handlers.begin(), handlers.end(), handler); | 438 std::find(handlers.begin(), handlers.end(), handler); |
362 if (p != handlers.end()) { | 439 if (p != handlers.end()) { |
363 handlers.erase(p); | 440 handlers.erase(p); |
364 } | 441 } |
365 ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol()); | 442 ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol()); |
(...skipping 18 matching lines...) Expand all Loading... |
384 NotifyChanged(); | 461 NotifyChanged(); |
385 } | 462 } |
386 | 463 |
387 void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) { | 464 void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) { |
388 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 465 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
389 ProtocolHandler current_default = GetHandlerFor(scheme); | 466 ProtocolHandler current_default = GetHandlerFor(scheme); |
390 if (!current_default.IsEmpty()) | 467 if (!current_default.IsEmpty()) |
391 RemoveHandler(current_default); | 468 RemoveHandler(current_default); |
392 } | 469 } |
393 | 470 |
394 static const ProtocolHandler& LookupHandler( | 471 const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor( |
395 const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map, | 472 const std::string& scheme) const { |
396 const std::string& scheme) { | 473 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
397 ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p = | 474 return LookupHandler(default_handlers_, scheme); |
398 handler_map.find(scheme); | |
399 if (p != handler_map.end()) { | |
400 return p->second; | |
401 } | |
402 return ProtocolHandler::EmptyProtocolHandler(); | |
403 } | 475 } |
404 | 476 |
405 Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() { | 477 net::URLRequestJob* ProtocolHandlerRegistry::MaybeCreateJob( |
406 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 478 net::URLRequest* request) const { |
407 ListValue* protocol_handlers = new ListValue(); | 479 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
408 for (ProtocolHandlerMultiMap::iterator i = protocol_handlers_.begin(); | 480 ProtocolHandler handler = LookupHandler(default_handlers_io_, |
409 i != protocol_handlers_.end(); ++i) { | 481 request->url().scheme()); |
410 for (ProtocolHandlerList::iterator j = i->second.begin(); | 482 if (handler.IsEmpty()) { |
411 j != i->second.end(); ++j) { | 483 return NULL; |
412 DictionaryValue* encoded = j->Encode(); | |
413 if (IsDefault(*j)) { | |
414 encoded->Set("default", Value::CreateBooleanValue(true)); | |
415 } | |
416 protocol_handlers->Append(encoded); | |
417 } | |
418 } | 484 } |
419 return protocol_handlers; | 485 GURL translated_url(handler.TranslateUrl(request->url())); |
| 486 if (!translated_url.is_valid()) { |
| 487 return NULL; |
| 488 } |
| 489 return new net::URLRequestRedirectJob(request, translated_url); |
420 } | 490 } |
421 | 491 |
422 Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() { | 492 void ProtocolHandlerRegistry::Enable() { |
423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 493 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
424 ListValue* handlers = new ListValue(); | 494 if (enabled_) { |
425 for (ProtocolHandlerList::iterator i = ignored_protocol_handlers_.begin(); | 495 return; |
426 i != ignored_protocol_handlers_.end(); ++i) { | |
427 handlers->Append(i->Encode()); | |
428 } | 496 } |
429 return handlers; | 497 enabled_ = true; |
430 } | 498 BrowserThread::PostTask( |
431 | 499 BrowserThread::IO, |
432 bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest( | 500 FROM_HERE, |
433 const ProtocolHandler& handler) { | 501 base::Bind(&ProtocolHandlerRegistry::EnableIO, this)); |
434 if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol())) | 502 ProtocolHandlerMap::const_iterator p; |
435 return true; | 503 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { |
436 | 504 delegate_->RegisterExternalHandler(p->first); |
437 if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler)) | 505 } |
438 return true; | |
439 | |
440 if (AttemptReplace(handler)) | |
441 return true; | |
442 | |
443 return false; | |
444 } | |
445 | |
446 void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler( | |
447 const ProtocolHandler& handler) { | |
448 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
449 RegisterProtocolHandler(handler); | |
450 SetDefault(handler); | |
451 Save(); | 506 Save(); |
452 NotifyChanged(); | 507 NotifyChanged(); |
453 } | 508 } |
454 | 509 |
455 void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler( | 510 void ProtocolHandlerRegistry::Disable() { |
456 const ProtocolHandler& handler) { | |
457 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 511 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
458 RegisterProtocolHandler(handler); | 512 if (!enabled_) { |
| 513 return; |
| 514 } |
| 515 enabled_ = false; |
| 516 BrowserThread::PostTask( |
| 517 BrowserThread::IO, |
| 518 FROM_HERE, |
| 519 base::Bind(&ProtocolHandlerRegistry::DisableIO, this)); |
| 520 ProtocolHandlerMap::const_iterator p; |
| 521 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { |
| 522 delegate_->DeregisterExternalHandler(p->first); |
| 523 } |
459 Save(); | 524 Save(); |
460 NotifyChanged(); | 525 NotifyChanged(); |
461 } | 526 } |
462 | 527 |
463 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler( | 528 void ProtocolHandlerRegistry::Finalize() { |
464 const ProtocolHandler& handler) { | |
465 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 529 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
466 IgnoreProtocolHandler(handler); | 530 delegate_.reset(NULL); |
467 Save(); | 531 // We free these now in case there are any outstanding workers running. If |
468 NotifyChanged(); | 532 // we didn't free them they could respond to workers and try to update the |
| 533 // protocol handler registry after it was deleted. |
| 534 // Observers remove themselves from this list when they are deleted; so |
| 535 // we delete the last item until none are left in the list. |
| 536 while (!default_client_observers_.empty()) { |
| 537 delete default_client_observers_.back(); |
| 538 } |
469 } | 539 } |
470 | 540 |
471 bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) { | |
472 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
473 ProtocolHandler old_default = GetHandlerFor(handler.protocol()); | |
474 bool make_new_handler_default = handler.IsSameOrigin(old_default); | |
475 ProtocolHandlerList to_replace(GetReplacedHandlers(handler)); | |
476 if (to_replace.empty()) | |
477 return false; | |
478 for (ProtocolHandlerList::iterator p = to_replace.begin(); | |
479 p != to_replace.end(); ++p) { | |
480 RemoveHandler(*p); | |
481 } | |
482 if (make_new_handler_default) { | |
483 OnAcceptRegisterProtocolHandler(handler); | |
484 } else { | |
485 InsertHandler(handler); | |
486 NotifyChanged(); | |
487 } | |
488 return true; | |
489 } | |
490 | |
491 ProtocolHandlerRegistry::ProtocolHandlerList | |
492 ProtocolHandlerRegistry::GetReplacedHandlers( | |
493 const ProtocolHandler& handler) const { | |
494 ProtocolHandlerList replaced_handlers; | |
495 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); | |
496 if (!handlers) | |
497 return replaced_handlers; | |
498 for (ProtocolHandlerList::const_iterator p = handlers->begin(); | |
499 p != handlers->end(); p++) { | |
500 if (handler.IsSameOrigin(*p)) { | |
501 replaced_handlers.push_back(*p); | |
502 } | |
503 } | |
504 return replaced_handlers; | |
505 } | |
506 | |
507 | |
508 // static | 541 // static |
509 void ProtocolHandlerRegistry::RegisterPrefs(PrefService* pref_service) { | 542 void ProtocolHandlerRegistry::RegisterPrefs(PrefService* pref_service) { |
510 pref_service->RegisterListPref(prefs::kRegisteredProtocolHandlers, | 543 pref_service->RegisterListPref(prefs::kRegisteredProtocolHandlers, |
511 PrefService::UNSYNCABLE_PREF); | 544 PrefService::UNSYNCABLE_PREF); |
512 pref_service->RegisterListPref(prefs::kIgnoredProtocolHandlers, | 545 pref_service->RegisterListPref(prefs::kIgnoredProtocolHandlers, |
513 PrefService::UNSYNCABLE_PREF); | 546 PrefService::UNSYNCABLE_PREF); |
514 pref_service->RegisterBooleanPref(prefs::kCustomHandlersEnabled, true, | 547 pref_service->RegisterBooleanPref(prefs::kCustomHandlersEnabled, true, |
515 PrefService::UNSYNCABLE_PREF); | 548 PrefService::UNSYNCABLE_PREF); |
516 } | 549 } |
517 | 550 |
518 void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) { | 551 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() { |
519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 552 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
520 ProtocolHandlerMap::const_iterator p = default_handlers_.find( | 553 DCHECK(default_client_observers_.empty()); |
521 handler.protocol()); | |
522 // If we're not loading, and we are setting a default for a new protocol, | |
523 // register with the OS. | |
524 if (!is_loading_ && p == default_handlers_.end()) | |
525 delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this); | |
526 default_handlers_.erase(handler.protocol()); | |
527 default_handlers_.insert(std::make_pair(handler.protocol(), handler)); | |
528 PromoteHandler(handler); | |
529 BrowserThread::PostTask( | |
530 BrowserThread::IO, | |
531 FROM_HERE, | |
532 base::Bind(&ProtocolHandlerRegistry::SetDefaultIO, this, handler)); | |
533 } | |
534 | |
535 void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) { | |
536 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
537 default_handlers_.erase(scheme); | |
538 BrowserThread::PostTask( | |
539 BrowserThread::IO, | |
540 FROM_HERE, | |
541 base::Bind(&ProtocolHandlerRegistry::ClearDefaultIO, this, scheme)); | |
542 Save(); | |
543 NotifyChanged(); | |
544 } | |
545 | |
546 bool ProtocolHandlerRegistry::IsDefault( | |
547 const ProtocolHandler& handler) const { | |
548 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
549 return GetHandlerFor(handler.protocol()) == handler; | |
550 } | |
551 | |
552 const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor( | |
553 const std::string& scheme) const { | |
554 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
555 return LookupHandler(default_handlers_, scheme); | |
556 } | |
557 | |
558 int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const { | |
559 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
560 const ProtocolHandler& handler = GetHandlerFor(scheme); | |
561 if (handler.IsEmpty()) | |
562 return -1; | |
563 const ProtocolHandlerList* handlers = GetHandlerList(scheme); | |
564 if (!handlers) | |
565 return -1; | |
566 | |
567 ProtocolHandlerList::const_iterator p; | |
568 int i; | |
569 for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) { | |
570 if (*p == handler) | |
571 return i; | |
572 } | |
573 return -1; | |
574 } | 554 } |
575 | 555 |
576 void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) { | 556 void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) { |
577 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 557 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
578 DCHECK(IsRegistered(handler)); | 558 DCHECK(IsRegistered(handler)); |
579 ProtocolHandlerMultiMap::iterator p = | 559 ProtocolHandlerMultiMap::iterator p = |
580 protocol_handlers_.find(handler.protocol()); | 560 protocol_handlers_.find(handler.protocol()); |
581 ProtocolHandlerList& list = p->second; | 561 ProtocolHandlerList& list = p->second; |
582 list.erase(std::find(list.begin(), list.end(), handler)); | 562 list.erase(std::find(list.begin(), list.end(), handler)); |
583 list.insert(list.begin(), handler); | 563 list.insert(list.begin(), handler); |
584 } | 564 } |
585 | 565 |
586 void ProtocolHandlerRegistry::NotifyChanged() { | |
587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
588 content::NotificationService::current()->Notify( | |
589 chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, | |
590 content::Source<Profile>(profile_), | |
591 content::NotificationService::NoDetails()); | |
592 } | |
593 | |
594 // IO thread methods ----------------------------------------------------------- | |
595 | |
596 void ProtocolHandlerRegistry::ClearDefaultIO(const std::string& scheme) { | 566 void ProtocolHandlerRegistry::ClearDefaultIO(const std::string& scheme) { |
597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 567 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
598 default_handlers_io_.erase(scheme); | 568 default_handlers_io_.erase(scheme); |
599 } | 569 } |
600 | 570 |
601 void ProtocolHandlerRegistry::SetDefaultIO(const ProtocolHandler& handler) { | 571 void ProtocolHandlerRegistry::SetDefaultIO(const ProtocolHandler& handler) { |
602 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 572 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
603 ClearDefaultIO(handler.protocol()); | 573 ClearDefaultIO(handler.protocol()); |
604 default_handlers_io_.insert(std::make_pair(handler.protocol(), handler)); | 574 default_handlers_io_.insert(std::make_pair(handler.protocol(), handler)); |
605 } | 575 } |
606 | 576 |
607 bool ProtocolHandlerRegistry::IsHandledProtocolIO( | 577 void ProtocolHandlerRegistry::Save() { |
608 const std::string& scheme) const { | 578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
609 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 579 if (is_loading_) { |
610 return enabled_io_ && !LookupHandler(default_handlers_io_, scheme).IsEmpty(); | 580 return; |
| 581 } |
| 582 scoped_ptr<Value> registered_protocol_handlers(EncodeRegisteredHandlers()); |
| 583 scoped_ptr<Value> ignored_protocol_handlers(EncodeIgnoredHandlers()); |
| 584 scoped_ptr<Value> enabled(Value::CreateBooleanValue(enabled_)); |
| 585 profile_->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers, |
| 586 *registered_protocol_handlers); |
| 587 profile_->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers, |
| 588 *ignored_protocol_handlers); |
| 589 profile_->GetPrefs()->Set(prefs::kCustomHandlersEnabled, *enabled); |
611 } | 590 } |
612 | 591 |
613 net::URLRequestJob* ProtocolHandlerRegistry::MaybeCreateJob( | 592 const ProtocolHandlerRegistry::ProtocolHandlerList* |
614 net::URLRequest* request) const { | 593 ProtocolHandlerRegistry::GetHandlerList( |
615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 594 const std::string& scheme) const { |
616 ProtocolHandler handler = LookupHandler(default_handlers_io_, | 595 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
617 request->url().scheme()); | 596 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); |
618 if (handler.IsEmpty()) { | 597 if (p == protocol_handlers_.end()) { |
619 return NULL; | 598 return NULL; |
620 } | 599 } |
621 GURL translated_url(handler.TranslateUrl(request->url())); | 600 return &p->second; |
622 if (!translated_url.is_valid()) { | |
623 return NULL; | |
624 } | |
625 return new net::URLRequestRedirectJob(request, translated_url); | |
626 } | 601 } |
627 | 602 |
628 // Delegate -------------------------------------------------------------------- | 603 void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) { |
629 | 604 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
630 ProtocolHandlerRegistry::Delegate::~Delegate() { | 605 ProtocolHandlerMap::const_iterator p = default_handlers_.find( |
| 606 handler.protocol()); |
| 607 // If we're not loading, and we are setting a default for a new protocol, |
| 608 // register with the OS. |
| 609 if (!is_loading_ && p == default_handlers_.end()) |
| 610 delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this); |
| 611 default_handlers_.erase(handler.protocol()); |
| 612 default_handlers_.insert(std::make_pair(handler.protocol(), handler)); |
| 613 PromoteHandler(handler); |
| 614 BrowserThread::PostTask( |
| 615 BrowserThread::IO, |
| 616 FROM_HERE, |
| 617 base::Bind(&ProtocolHandlerRegistry::SetDefaultIO, this, handler)); |
631 } | 618 } |
632 | 619 |
633 void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler( | 620 void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) { |
634 const std::string& protocol) { | 621 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
635 ChildProcessSecurityPolicy* policy = | 622 ProtocolHandlerMultiMap::iterator p = |
636 ChildProcessSecurityPolicy::GetInstance(); | 623 protocol_handlers_.find(handler.protocol()); |
637 if (!policy->IsWebSafeScheme(protocol)) { | 624 |
638 policy->RegisterWebSafeScheme(protocol); | 625 if (p != protocol_handlers_.end()) { |
| 626 p->second.push_back(handler); |
| 627 return; |
639 } | 628 } |
| 629 |
| 630 ProtocolHandlerList new_list; |
| 631 new_list.push_back(handler); |
| 632 protocol_handlers_[handler.protocol()] = new_list; |
640 } | 633 } |
641 | 634 |
642 void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler( | 635 Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() { |
643 const std::string& protocol) { | 636 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 637 ListValue* protocol_handlers = new ListValue(); |
| 638 for (ProtocolHandlerMultiMap::iterator i = protocol_handlers_.begin(); |
| 639 i != protocol_handlers_.end(); ++i) { |
| 640 for (ProtocolHandlerList::iterator j = i->second.begin(); |
| 641 j != i->second.end(); ++j) { |
| 642 DictionaryValue* encoded = j->Encode(); |
| 643 if (IsDefault(*j)) { |
| 644 encoded->Set("default", Value::CreateBooleanValue(true)); |
| 645 } |
| 646 protocol_handlers->Append(encoded); |
| 647 } |
| 648 } |
| 649 return protocol_handlers; |
644 } | 650 } |
645 | 651 |
646 ShellIntegration::DefaultProtocolClientWorker* | 652 Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() { |
647 ProtocolHandlerRegistry::Delegate::CreateShellWorker( | 653 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
648 ShellIntegration::DefaultWebClientObserver* observer, | 654 ListValue* handlers = new ListValue(); |
649 const std::string& protocol) { | 655 for (ProtocolHandlerList::iterator i = ignored_protocol_handlers_.begin(); |
650 return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol); | 656 i != ignored_protocol_handlers_.end(); ++i) { |
| 657 handlers->Append(i->Encode()); |
| 658 } |
| 659 return handlers; |
651 } | 660 } |
652 | 661 |
653 ProtocolHandlerRegistry::DefaultClientObserver* | 662 void ProtocolHandlerRegistry::NotifyChanged() { |
654 ProtocolHandlerRegistry::Delegate::CreateShellObserver( | 663 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
655 ProtocolHandlerRegistry* registry) { | 664 content::NotificationService::current()->Notify( |
656 return new DefaultClientObserver(registry); | 665 chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, |
| 666 content::Source<Profile>(profile_), |
| 667 content::NotificationService::NoDetails()); |
657 } | 668 } |
658 | 669 |
659 void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient( | 670 void ProtocolHandlerRegistry::RegisterProtocolHandler( |
660 const std::string& protocol, ProtocolHandlerRegistry* registry) { | 671 const ProtocolHandler& handler) { |
661 DefaultClientObserver* observer = CreateShellObserver(registry); | 672 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
662 // The worker pointer is reference counted. While it is running the | 673 DCHECK(CanSchemeBeOverridden(handler.protocol())); |
663 // message loops of the FILE and UI thread will hold references to it | 674 DCHECK(!handler.IsEmpty()); |
664 // and it will be automatically freed once all its tasks have finished. | 675 if (IsRegistered(handler)) { |
665 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; | 676 return; |
666 worker = CreateShellWorker(observer, protocol); | 677 } |
667 observer->SetWorker(worker); | 678 if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol())) |
668 registry->default_client_observers_.push_back(observer); | 679 delegate_->RegisterExternalHandler(handler.protocol()); |
669 worker->StartSetAsDefault(); | 680 InsertHandler(handler); |
670 } | 681 } |
671 | 682 |
672 bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered( | 683 std::vector<const DictionaryValue*> |
673 const std::string& protocol) { | 684 ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const { |
674 // NOTE(koz): This function is safe to call from any thread, despite living | 685 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
675 // in ProfileIOData. | 686 std::vector<const DictionaryValue*> result; |
676 return ProfileIOData::IsHandledProtocol(protocol); | 687 PrefService* prefs = profile_->GetPrefs(); |
| 688 if (!prefs->HasPrefPath(pref_name)) { |
| 689 return result; |
| 690 } |
| 691 |
| 692 const ListValue* handlers = prefs->GetList(pref_name); |
| 693 if (handlers) { |
| 694 for (size_t i = 0; i < handlers->GetSize(); ++i) { |
| 695 DictionaryValue* dict; |
| 696 if (!handlers->GetDictionary(i, &dict)) |
| 697 continue; |
| 698 if (ProtocolHandler::IsValidDict(dict)) { |
| 699 result.push_back(dict); |
| 700 } |
| 701 } |
| 702 } |
| 703 return result; |
677 } | 704 } |
678 | 705 |
679 // DefaultClientObserver ------------------------------------------------------ | 706 void ProtocolHandlerRegistry::IgnoreProtocolHandler( |
680 | 707 const ProtocolHandler& handler) { |
681 ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver( | 708 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
682 ProtocolHandlerRegistry* registry) | 709 ignored_protocol_handlers_.push_back(handler); |
683 : worker_(NULL), registry_(registry) { | |
684 DCHECK(registry_); | |
685 } | 710 } |
686 | |
687 ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() { | |
688 if (worker_) { | |
689 worker_->ObserverDestroyed(); | |
690 }; | |
691 DefaultClientObserverList::iterator iter = std::find( | |
692 registry_->default_client_observers_.begin(), | |
693 registry_->default_client_observers_.end(), this); | |
694 registry_->default_client_observers_.erase(iter); | |
695 } | |
696 | |
697 void | |
698 ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState( | |
699 ShellIntegration::DefaultWebClientUIState state) { | |
700 if (worker_) { | |
701 if (ShouldRemoveHandlersNotInOS() && | |
702 (state == ShellIntegration::STATE_NOT_DEFAULT)) { | |
703 registry_->ClearDefault(worker_->protocol()); | |
704 } | |
705 } else { | |
706 NOTREACHED(); | |
707 } | |
708 } | |
709 | |
710 void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker( | |
711 ShellIntegration::DefaultProtocolClientWorker* worker) { | |
712 worker_ = worker; | |
713 } | |
OLD | NEW |