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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/custom_handlers/protocol_handler_registry.h" 6 7 #include <utility> 8 9 #include "base/bind.h" 10 #include "base/command_line.h" 11 #include "base/logging.h" 12 #include "base/prefs/pref_service.h" 13 #include "chrome/browser/chrome_notification_types.h" 14 #include "chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h" 15 #include "chrome/browser/profiles/profile_io_data.h" 16 #include "chrome/common/custom_handlers/protocol_handler.h" 17 #include "chrome/common/pref_names.h" 18 #include "chrome/grit/generated_resources.h" 19 #include "components/pref_registry/pref_registry_syncable.h" 20 #include "components/user_prefs/user_prefs.h" 21 #include "content/public/browser/child_process_security_policy.h" 22 #include "net/base/network_delegate.h" 23 #include "net/url_request/url_request_redirect_job.h" 24 #include "ui/base/l10n/l10n_util.h" 25 26 using content::BrowserThread; 27 using content::ChildProcessSecurityPolicy; 28 29 namespace { 30 31 const ProtocolHandler& LookupHandler( 32 const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map, 33 const std::string& scheme) { 34 ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p = 35 handler_map.find(scheme); 36 37 if (p != handler_map.end()) 38 return p->second; 39 40 return ProtocolHandler::EmptyProtocolHandler(); 41 } 42 43 // If true default protocol handlers will be removed if the OS level 44 // registration for a protocol is no longer Chrome. 45 bool ShouldRemoveHandlersNotInOS() { 46 #if defined(OS_LINUX) 47 // We don't do this on Linux as the OS registration there is not reliable, 48 // and Chrome OS doesn't have any notion of OS registration. 49 // TODO(benwells): When Linux support is more reliable remove this 50 // difference (http://crbug.com/88255). 51 return false; 52 #else 53 return ShellIntegration::CanSetAsDefaultProtocolClient() != 54 ShellIntegration::SET_DEFAULT_NOT_ALLOWED; 55 #endif 56 } 57 58 } // namespace 59 60 // IOThreadDelegate ------------------------------------------------------------ 61 62 // IOThreadDelegate is an IO thread specific object. Access to the class should 63 // all be done via the IO thread. The registry living on the UI thread makes 64 // a best effort to update the IO object after local updates are completed. 65 class ProtocolHandlerRegistry::IOThreadDelegate 66 : public base::RefCountedThreadSafe< 67 ProtocolHandlerRegistry::IOThreadDelegate> { 68 public: 69 70 // Creates a new instance. If |enabled| is true the registry is considered 71 // enabled on the IO thread. 72 explicit IOThreadDelegate(bool enabled); 73 74 // Returns true if the protocol has a default protocol handler. 75 // Should be called only from the IO thread. 76 bool IsHandledProtocol(const std::string& scheme) const; 77 78 // Clears the default for the provided protocol. 79 // Should be called only from the IO thread. 80 void ClearDefault(const std::string& scheme); 81 82 // Makes this ProtocolHandler the default handler for its protocol. 83 // Should be called only from the IO thread. 84 void SetDefault(const ProtocolHandler& handler); 85 86 // Creates a URL request job for the given request if there is a matching 87 // protocol handler, returns NULL otherwise. 88 net::URLRequestJob* MaybeCreateJob( 89 net::URLRequest* request, net::NetworkDelegate* network_delegate) const; 90 91 // Indicate that the registry has been enabled in the IO thread's 92 // copy of the data. 93 void Enable() { enabled_ = true; } 94 95 // Indicate that the registry has been disabled in the IO thread's copy of 96 // the data. 97 void Disable() { enabled_ = false; } 98 99 private: 100 friend class base::RefCountedThreadSafe<IOThreadDelegate>; 101 virtual ~IOThreadDelegate(); 102 103 // Copy of protocol handlers use only on the IO thread. 104 ProtocolHandlerRegistry::ProtocolHandlerMap default_handlers_; 105 106 // Is the registry enabled on the IO thread. 107 bool enabled_; 108 109 DISALLOW_COPY_AND_ASSIGN(IOThreadDelegate); 110 }; 111 112 ProtocolHandlerRegistry::IOThreadDelegate::IOThreadDelegate(bool) 113 : enabled_(true) {} 114 ProtocolHandlerRegistry::IOThreadDelegate::~IOThreadDelegate() {} 115 116 bool ProtocolHandlerRegistry::IOThreadDelegate::IsHandledProtocol( 117 const std::string& scheme) const { 118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 119 return enabled_ && !LookupHandler(default_handlers_, scheme).IsEmpty(); 120 } 121 122 void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault( 123 const std::string& scheme) { 124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 125 default_handlers_.erase(scheme); 126 } 127 128 void ProtocolHandlerRegistry::IOThreadDelegate::SetDefault( 129 const ProtocolHandler& handler) { 130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 131 ClearDefault(handler.protocol()); 132 default_handlers_.insert(std::make_pair(handler.protocol(), handler)); 133 } 134 135 // Create a new job for the supplied |URLRequest| if a default handler 136 // is registered and the associated handler is able to interpret 137 // the url from |request|. 138 net::URLRequestJob* ProtocolHandlerRegistry::IOThreadDelegate::MaybeCreateJob( 139 net::URLRequest* request, net::NetworkDelegate* network_delegate) const { 140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 141 142 ProtocolHandler handler = LookupHandler(default_handlers_, 143 request->url().scheme()); 144 if (handler.IsEmpty()) 145 return NULL; 146 147 GURL translated_url(handler.TranslateUrl(request->url())); 148 if (!translated_url.is_valid()) 149 return NULL; 150 151 return new net::URLRequestRedirectJob( 152 request, network_delegate, translated_url, 153 net::URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT, 154 "Protocol Handler Registry"); 155 } 156 157 // JobInterceptorFactory ------------------------------------------------------- 158 159 // Instances of JobInterceptorFactory are produced for ownership by the IO 160 // thread where it handler URL requests. We should never hold 161 // any pointers on this class, only produce them in response to 162 // requests via |ProtocolHandlerRegistry::CreateJobInterceptorFactory|. 163 ProtocolHandlerRegistry::JobInterceptorFactory::JobInterceptorFactory( 164 IOThreadDelegate* io_thread_delegate) 165 : io_thread_delegate_(io_thread_delegate) { 166 DCHECK(io_thread_delegate_.get()); 167 DetachFromThread(); 168 } 169 170 ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() { 171 } 172 173 void ProtocolHandlerRegistry::JobInterceptorFactory::Chain( 174 scoped_ptr<net::URLRequestJobFactory> job_factory) { 175 job_factory_ = job_factory.Pass(); 176 } 177 178 net::URLRequestJob* 179 ProtocolHandlerRegistry::JobInterceptorFactory:: 180 MaybeCreateJobWithProtocolHandler( 181 const std::string& scheme, 182 net::URLRequest* request, 183 net::NetworkDelegate* network_delegate) const { 184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 185 net::URLRequestJob* job = io_thread_delegate_->MaybeCreateJob( 186 request, network_delegate); 187 if (job) 188 return job; 189 return job_factory_->MaybeCreateJobWithProtocolHandler( 190 scheme, request, network_delegate); 191 } 192 193 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledProtocol( 194 const std::string& scheme) const { 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 196 return io_thread_delegate_->IsHandledProtocol(scheme) || 197 job_factory_->IsHandledProtocol(scheme); 198 } 199 200 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledURL( 201 const GURL& url) const { 202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 203 return (url.is_valid() && 204 io_thread_delegate_->IsHandledProtocol(url.scheme())) || 205 job_factory_->IsHandledURL(url); 206 } 207 208 bool ProtocolHandlerRegistry::JobInterceptorFactory::IsSafeRedirectTarget( 209 const GURL& location) const { 210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 211 return job_factory_->IsSafeRedirectTarget(location); 212 } 213 214 // DefaultClientObserver ------------------------------------------------------ 215 216 ProtocolHandlerRegistry::DefaultClientObserver::DefaultClientObserver( 217 ProtocolHandlerRegistry* registry) 218 : worker_(NULL), 219 registry_(registry) { 220 DCHECK(registry_); 221 } 222 223 ProtocolHandlerRegistry::DefaultClientObserver::~DefaultClientObserver() { 224 if (worker_) 225 worker_->ObserverDestroyed(); 226 227 DefaultClientObserverList::iterator iter = std::find( 228 registry_->default_client_observers_.begin(), 229 registry_->default_client_observers_.end(), this); 230 registry_->default_client_observers_.erase(iter); 231 } 232 233 void ProtocolHandlerRegistry::DefaultClientObserver::SetDefaultWebClientUIState( 234 ShellIntegration::DefaultWebClientUIState state) { 235 if (worker_) { 236 if (ShouldRemoveHandlersNotInOS() && 237 (state == ShellIntegration::STATE_NOT_DEFAULT)) { 238 registry_->ClearDefault(worker_->protocol()); 239 } 240 } else { 241 NOTREACHED(); 242 } 243 } 244 245 bool ProtocolHandlerRegistry::DefaultClientObserver:: 246 IsInteractiveSetDefaultPermitted() { 247 return true; 248 } 249 250 void ProtocolHandlerRegistry::DefaultClientObserver::SetWorker( 251 ShellIntegration::DefaultProtocolClientWorker* worker) { 252 worker_ = worker; 253 } 254 255 bool ProtocolHandlerRegistry::DefaultClientObserver::IsOwnedByWorker() { 256 return true; 257 } 258 259 // Delegate -------------------------------------------------------------------- 260 261 ProtocolHandlerRegistry::Delegate::~Delegate() {} 262 263 void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler( 264 const std::string& protocol) { 265 ChildProcessSecurityPolicy* policy = 266 ChildProcessSecurityPolicy::GetInstance(); 267 if (!policy->IsWebSafeScheme(protocol)) { 268 policy->RegisterWebSafeScheme(protocol); 269 } 270 } 271 272 void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler( 273 const std::string& protocol) { 274 } 275 276 bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered( 277 const std::string& protocol) { 278 // NOTE(koz): This function is safe to call from any thread, despite living 279 // in ProfileIOData. 280 return ProfileIOData::IsHandledProtocol(protocol); 281 } 282 283 ShellIntegration::DefaultProtocolClientWorker* 284 ProtocolHandlerRegistry::Delegate::CreateShellWorker( 285 ShellIntegration::DefaultWebClientObserver* observer, 286 const std::string& protocol) { 287 return new ShellIntegration::DefaultProtocolClientWorker(observer, protocol); 288 } 289 290 ProtocolHandlerRegistry::DefaultClientObserver* 291 ProtocolHandlerRegistry::Delegate::CreateShellObserver( 292 ProtocolHandlerRegistry* registry) { 293 return new DefaultClientObserver(registry); 294 } 295 296 void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient( 297 const std::string& protocol, ProtocolHandlerRegistry* registry) { 298 DefaultClientObserver* observer = CreateShellObserver(registry); 299 // The worker pointer is reference counted. While it is running the 300 // message loops of the FILE and UI thread will hold references to it 301 // and it will be automatically freed once all its tasks have finished. 302 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; 303 worker = CreateShellWorker(observer, protocol); 304 observer->SetWorker(worker.get()); 305 registry->default_client_observers_.push_back(observer); 306 worker->StartSetAsDefault(); 307 } 308 309 // ProtocolHandlerRegistry ----------------------------------------------------- 310 311 ProtocolHandlerRegistry::ProtocolHandlerRegistry( 312 content::BrowserContext* context, Delegate* delegate) 313 : context_(context), 314 delegate_(delegate), 315 enabled_(true), 316 is_loading_(false), 317 is_loaded_(false), 318 io_thread_delegate_(new IOThreadDelegate(enabled_)){ 319 } 320 321 bool ProtocolHandlerRegistry::SilentlyHandleRegisterHandlerRequest( 322 const ProtocolHandler& handler) { 323 if (handler.IsEmpty() || !CanSchemeBeOverridden(handler.protocol())) 324 return true; 325 326 if (!enabled() || IsRegistered(handler) || HasIgnoredEquivalent(handler)) 327 return true; 328 329 if (AttemptReplace(handler)) 330 return true; 331 332 return false; 333 } 334 335 void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler( 336 const ProtocolHandler& handler) { 337 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 338 RegisterProtocolHandler(handler, USER); 339 SetDefault(handler); 340 Save(); 341 NotifyChanged(); 342 } 343 344 void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler( 345 const ProtocolHandler& handler) { 346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 347 RegisterProtocolHandler(handler, USER); 348 Save(); 349 NotifyChanged(); 350 } 351 352 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler( 353 const ProtocolHandler& handler) { 354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 355 IgnoreProtocolHandler(handler, USER); 356 Save(); 357 NotifyChanged(); 358 } 359 360 bool ProtocolHandlerRegistry::AttemptReplace(const ProtocolHandler& handler) { 361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 362 ProtocolHandler old_default = GetHandlerFor(handler.protocol()); 363 bool make_new_handler_default = handler.IsSameOrigin(old_default); 364 ProtocolHandlerList to_replace(GetReplacedHandlers(handler)); 365 if (to_replace.empty()) 366 return false; 367 for (ProtocolHandlerList::iterator p = to_replace.begin(); 368 p != to_replace.end(); ++p) { 369 RemoveHandler(*p); 370 } 371 if (make_new_handler_default) { 372 OnAcceptRegisterProtocolHandler(handler); 373 } else { 374 InsertHandler(handler); 375 NotifyChanged(); 376 } 377 return true; 378 } 379 380 ProtocolHandlerRegistry::ProtocolHandlerList 381 ProtocolHandlerRegistry::GetReplacedHandlers( 382 const ProtocolHandler& handler) const { 383 ProtocolHandlerList replaced_handlers; 384 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); 385 if (!handlers) 386 return replaced_handlers; 387 for (ProtocolHandlerList::const_iterator p = handlers->begin(); 388 p != handlers->end(); p++) { 389 if (handler.IsSameOrigin(*p)) { 390 replaced_handlers.push_back(*p); 391 } 392 } 393 return replaced_handlers; 394 } 395 396 void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) { 397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 398 399 default_handlers_.erase(scheme); 400 BrowserThread::PostTask( 401 BrowserThread::IO, 402 FROM_HERE, 403 base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_, scheme)); 404 Save(); 405 NotifyChanged(); 406 } 407 408 bool ProtocolHandlerRegistry::IsDefault( 409 const ProtocolHandler& handler) const { 410 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 411 return GetHandlerFor(handler.protocol()) == handler; 412 } 413 414 void ProtocolHandlerRegistry::InstallDefaultsForChromeOS() { 415 #if defined(OS_CHROMEOS) 416 // Only chromeos has default protocol handlers at this point. 417 AddPredefinedHandler( 418 ProtocolHandler::CreateProtocolHandler( 419 "mailto", 420 GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_MAILTO_HANDLER_URL)))); 421 AddPredefinedHandler( 422 ProtocolHandler::CreateProtocolHandler( 423 "webcal", 424 GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL)))); 425 #else 426 NOTREACHED(); // this method should only ever be called in chromeos. 427 #endif 428 } 429 430 void ProtocolHandlerRegistry::InitProtocolSettings() { 431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 432 433 // Any further default additions to the table will get rejected from now on. 434 is_loaded_ = true; 435 is_loading_ = true; 436 437 PrefService* prefs = user_prefs::UserPrefs::Get(context_); 438 if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) { 439 if (prefs->GetBoolean(prefs::kCustomHandlersEnabled)) { 440 Enable(); 441 } else { 442 Disable(); 443 } 444 } 445 446 RegisterProtocolHandlersFromPref(prefs::kPolicyRegisteredProtocolHandlers, 447 POLICY); 448 RegisterProtocolHandlersFromPref(prefs::kRegisteredProtocolHandlers, USER); 449 IgnoreProtocolHandlersFromPref(prefs::kPolicyIgnoredProtocolHandlers, POLICY); 450 IgnoreProtocolHandlersFromPref(prefs::kIgnoredProtocolHandlers, USER); 451 452 is_loading_ = false; 453 454 // For each default protocol handler, check that we are still registered 455 // with the OS as the default application. 456 if (ShouldRemoveHandlersNotInOS()) { 457 for (ProtocolHandlerMap::const_iterator p = default_handlers_.begin(); 458 p != default_handlers_.end(); ++p) { 459 ProtocolHandler handler = p->second; 460 DefaultClientObserver* observer = delegate_->CreateShellObserver(this); 461 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; 462 worker = delegate_->CreateShellWorker(observer, handler.protocol()); 463 observer->SetWorker(worker.get()); 464 default_client_observers_.push_back(observer); 465 worker->StartCheckIsDefault(); 466 } 467 } 468 } 469 470 int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const { 471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 472 const ProtocolHandler& handler = GetHandlerFor(scheme); 473 if (handler.IsEmpty()) 474 return -1; 475 const ProtocolHandlerList* handlers = GetHandlerList(scheme); 476 if (!handlers) 477 return -1; 478 479 ProtocolHandlerList::const_iterator p; 480 int i; 481 for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) { 482 if (*p == handler) 483 return i; 484 } 485 return -1; 486 } 487 488 ProtocolHandlerRegistry::ProtocolHandlerList 489 ProtocolHandlerRegistry::GetHandlersFor( 490 const std::string& scheme) const { 491 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 492 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); 493 if (p == protocol_handlers_.end()) { 494 return ProtocolHandlerList(); 495 } 496 return p->second; 497 } 498 499 ProtocolHandlerRegistry::ProtocolHandlerList 500 ProtocolHandlerRegistry::GetIgnoredHandlers() { 501 return ignored_protocol_handlers_; 502 } 503 504 void ProtocolHandlerRegistry::GetRegisteredProtocols( 505 std::vector<std::string>* output) const { 506 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 507 ProtocolHandlerMultiMap::const_iterator p; 508 for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) { 509 if (!p->second.empty()) 510 output->push_back(p->first); 511 } 512 } 513 514 bool ProtocolHandlerRegistry::CanSchemeBeOverridden( 515 const std::string& scheme) const { 516 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 517 const ProtocolHandlerList* handlers = GetHandlerList(scheme); 518 // If we already have a handler for this scheme, we can add more. 519 if (handlers != NULL && !handlers->empty()) 520 return true; 521 // Don't override a scheme if it already has an external handler. 522 return !delegate_->IsExternalHandlerRegistered(scheme); 523 } 524 525 bool ProtocolHandlerRegistry::IsRegistered( 526 const ProtocolHandler& handler) const { 527 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 528 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); 529 if (!handlers) { 530 return false; 531 } 532 return std::find(handlers->begin(), handlers->end(), handler) != 533 handlers->end(); 534 } 535 536 bool ProtocolHandlerRegistry::IsRegisteredByUser( 537 const ProtocolHandler& handler) { 538 return HandlerExists(handler, &user_protocol_handlers_); 539 } 540 541 bool ProtocolHandlerRegistry::HasPolicyRegisteredHandler( 542 const std::string& scheme) { 543 return (policy_protocol_handlers_.find(scheme) != 544 policy_protocol_handlers_.end()); 545 } 546 547 bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const { 548 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 549 ProtocolHandlerList::const_iterator i; 550 for (i = ignored_protocol_handlers_.begin(); 551 i != ignored_protocol_handlers_.end(); ++i) { 552 if (*i == handler) { 553 return true; 554 } 555 } 556 return false; 557 } 558 559 bool ProtocolHandlerRegistry::HasRegisteredEquivalent( 560 const ProtocolHandler& handler) const { 561 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 562 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); 563 if (!handlers) { 564 return false; 565 } 566 ProtocolHandlerList::const_iterator i; 567 for (i = handlers->begin(); i != handlers->end(); ++i) { 568 if (handler.IsEquivalent(*i)) { 569 return true; 570 } 571 } 572 return false; 573 } 574 575 bool ProtocolHandlerRegistry::HasIgnoredEquivalent( 576 const ProtocolHandler& handler) const { 577 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 578 ProtocolHandlerList::const_iterator i; 579 for (i = ignored_protocol_handlers_.begin(); 580 i != ignored_protocol_handlers_.end(); ++i) { 581 if (handler.IsEquivalent(*i)) { 582 return true; 583 } 584 } 585 return false; 586 } 587 588 void ProtocolHandlerRegistry::RemoveIgnoredHandler( 589 const ProtocolHandler& handler) { 590 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 591 bool should_notify = false; 592 if (HandlerExists(handler, ignored_protocol_handlers_) && 593 HandlerExists(handler, user_ignored_protocol_handlers_)) { 594 EraseHandler(handler, &user_ignored_protocol_handlers_); 595 Save(); 596 if (!HandlerExists(handler, policy_ignored_protocol_handlers_)) { 597 EraseHandler(handler, &ignored_protocol_handlers_); 598 should_notify = true; 599 } 600 } 601 if (should_notify) 602 NotifyChanged(); 603 } 604 605 bool ProtocolHandlerRegistry::IsHandledProtocol( 606 const std::string& scheme) const { 607 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 608 return enabled_ && !GetHandlerFor(scheme).IsEmpty(); 609 } 610 611 void ProtocolHandlerRegistry::RemoveHandler( 612 const ProtocolHandler& handler) { 613 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 614 ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()]; 615 bool erase_success = false; 616 if (HandlerExists(handler, handlers) && 617 HandlerExists(handler, &user_protocol_handlers_)) { 618 EraseHandler(handler, &user_protocol_handlers_); 619 erase_success = true; 620 if (!HandlerExists(handler, &policy_protocol_handlers_)) 621 EraseHandler(handler, &protocol_handlers_); 622 } 623 ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol()); 624 if (erase_success && q != default_handlers_.end() && q->second == handler) { 625 // Make the new top handler in the list the default. 626 if (!handlers.empty()) { 627 // NOTE We pass a copy because SetDefault() modifies handlers. 628 SetDefault(ProtocolHandler(handlers[0])); 629 } else { 630 BrowserThread::PostTask( 631 BrowserThread::IO, FROM_HERE, 632 base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_, 633 q->second.protocol())); 634 635 default_handlers_.erase(q); 636 } 637 } 638 639 if (erase_success && !IsHandledProtocol(handler.protocol())) { 640 delegate_->DeregisterExternalHandler(handler.protocol()); 641 } 642 Save(); 643 if (erase_success) 644 NotifyChanged(); 645 } 646 647 void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) { 648 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 649 ProtocolHandler current_default = GetHandlerFor(scheme); 650 if (!current_default.IsEmpty()) 651 RemoveHandler(current_default); 652 } 653 654 const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor( 655 const std::string& scheme) const { 656 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 657 return LookupHandler(default_handlers_, scheme); 658 } 659 660 void ProtocolHandlerRegistry::Enable() { 661 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 662 if (enabled_) { 663 return; 664 } 665 enabled_ = true; 666 BrowserThread::PostTask( 667 BrowserThread::IO, 668 FROM_HERE, 669 base::Bind(&IOThreadDelegate::Enable, io_thread_delegate_)); 670 671 ProtocolHandlerMap::const_iterator p; 672 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { 673 delegate_->RegisterExternalHandler(p->first); 674 } 675 Save(); 676 NotifyChanged(); 677 } 678 679 void ProtocolHandlerRegistry::Disable() { 680 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 681 if (!enabled_) { 682 return; 683 } 684 enabled_ = false; 685 BrowserThread::PostTask( 686 BrowserThread::IO, 687 FROM_HERE, 688 base::Bind(&IOThreadDelegate::Disable, io_thread_delegate_)); 689 690 ProtocolHandlerMap::const_iterator p; 691 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { 692 delegate_->DeregisterExternalHandler(p->first); 693 } 694 Save(); 695 NotifyChanged(); 696 } 697 698 void ProtocolHandlerRegistry::Shutdown() { 699 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 700 delegate_.reset(NULL); 701 // We free these now in case there are any outstanding workers running. If 702 // we didn't free them they could respond to workers and try to update the 703 // protocol handler registry after it was deleted. 704 // Observers remove themselves from this list when they are deleted; so 705 // we delete the last item until none are left in the list. 706 while (!default_client_observers_.empty()) { 707 delete default_client_observers_.back(); 708 } 709 } 710 711 // static 712 void ProtocolHandlerRegistry::RegisterProfilePrefs( 713 user_prefs::PrefRegistrySyncable* registry) { 714 registry->RegisterListPref(prefs::kRegisteredProtocolHandlers, 715 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 716 registry->RegisterListPref(prefs::kIgnoredProtocolHandlers, 717 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 718 registry->RegisterListPref(prefs::kPolicyRegisteredProtocolHandlers, 719 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 720 registry->RegisterListPref(prefs::kPolicyIgnoredProtocolHandlers, 721 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 722 registry->RegisterBooleanPref( 723 prefs::kCustomHandlersEnabled, 724 true, 725 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 726 } 727 728 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() { 729 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 730 DCHECK(default_client_observers_.empty()); 731 } 732 733 void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) { 734 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 735 DCHECK(IsRegistered(handler)); 736 ProtocolHandlerMultiMap::iterator p = 737 protocol_handlers_.find(handler.protocol()); 738 ProtocolHandlerList& list = p->second; 739 list.erase(std::find(list.begin(), list.end(), handler)); 740 list.insert(list.begin(), handler); 741 } 742 743 void ProtocolHandlerRegistry::Save() { 744 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 745 if (is_loading_) { 746 return; 747 } 748 scoped_ptr<base::Value> registered_protocol_handlers( 749 EncodeRegisteredHandlers()); 750 scoped_ptr<base::Value> ignored_protocol_handlers(EncodeIgnoredHandlers()); 751 PrefService* prefs = user_prefs::UserPrefs::Get(context_); 752 753 prefs->Set(prefs::kRegisteredProtocolHandlers, 754 *registered_protocol_handlers); 755 prefs->Set(prefs::kIgnoredProtocolHandlers, 756 *ignored_protocol_handlers); 757 prefs->SetBoolean(prefs::kCustomHandlersEnabled, enabled_); 758 } 759 760 const ProtocolHandlerRegistry::ProtocolHandlerList* 761 ProtocolHandlerRegistry::GetHandlerList( 762 const std::string& scheme) const { 763 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 764 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); 765 if (p == protocol_handlers_.end()) { 766 return NULL; 767 } 768 return &p->second; 769 } 770 771 void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) { 772 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 773 ProtocolHandlerMap::const_iterator p = default_handlers_.find( 774 handler.protocol()); 775 // If we're not loading, and we are setting a default for a new protocol, 776 // register with the OS. 777 if (!is_loading_ && p == default_handlers_.end()) 778 delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this); 779 default_handlers_.erase(handler.protocol()); 780 default_handlers_.insert(std::make_pair(handler.protocol(), handler)); 781 PromoteHandler(handler); 782 BrowserThread::PostTask( 783 BrowserThread::IO, 784 FROM_HERE, 785 base::Bind(&IOThreadDelegate::SetDefault, io_thread_delegate_, handler)); 786 } 787 788 void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) { 789 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 790 ProtocolHandlerMultiMap::iterator p = 791 protocol_handlers_.find(handler.protocol()); 792 793 if (p != protocol_handlers_.end()) { 794 p->second.push_back(handler); 795 return; 796 } 797 798 ProtocolHandlerList new_list; 799 new_list.push_back(handler); 800 protocol_handlers_[handler.protocol()] = new_list; 801 } 802 803 base::Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() { 804 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 805 base::ListValue* protocol_handlers = new base::ListValue(); 806 for (ProtocolHandlerMultiMap::iterator i = user_protocol_handlers_.begin(); 807 i != user_protocol_handlers_.end(); 808 ++i) { 809 for (ProtocolHandlerList::iterator j = i->second.begin(); 810 j != i->second.end(); ++j) { 811 base::DictionaryValue* encoded = j->Encode(); 812 if (IsDefault(*j)) { 813 encoded->Set("default", new base::FundamentalValue(true)); 814 } 815 protocol_handlers->Append(encoded); 816 } 817 } 818 return protocol_handlers; 819 } 820 821 base::Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() { 822 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 823 base::ListValue* handlers = new base::ListValue(); 824 for (ProtocolHandlerList::iterator i = 825 user_ignored_protocol_handlers_.begin(); 826 i != user_ignored_protocol_handlers_.end(); 827 ++i) { 828 handlers->Append(i->Encode()); 829 } 830 return handlers; 831 } 832 833 void ProtocolHandlerRegistry::NotifyChanged() { 834 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 835 content::NotificationService::current()->Notify( 836 chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, 837 content::Source<content::BrowserContext>(context_), 838 content::NotificationService::NoDetails()); 839 } 840 841 void ProtocolHandlerRegistry::RegisterProtocolHandler( 842 const ProtocolHandler& handler, 843 const HandlerSource source) { 844 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 845 DCHECK(CanSchemeBeOverridden(handler.protocol())); 846 DCHECK(!handler.IsEmpty()); 847 ProtocolHandlerMultiMap& map = 848 (source == POLICY) ? policy_protocol_handlers_ : user_protocol_handlers_; 849 ProtocolHandlerList& list = map[handler.protocol()]; 850 if (!HandlerExists(handler, list)) 851 list.push_back(handler); 852 if (IsRegistered(handler)) { 853 return; 854 } 855 if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol())) 856 delegate_->RegisterExternalHandler(handler.protocol()); 857 InsertHandler(handler); 858 } 859 860 std::vector<const base::DictionaryValue*> 861 ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const { 862 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 863 std::vector<const base::DictionaryValue*> result; 864 PrefService* prefs = user_prefs::UserPrefs::Get(context_); 865 if (!prefs->HasPrefPath(pref_name)) { 866 return result; 867 } 868 869 const base::ListValue* handlers = prefs->GetList(pref_name); 870 if (handlers) { 871 for (size_t i = 0; i < handlers->GetSize(); ++i) { 872 const base::DictionaryValue* dict; 873 if (!handlers->GetDictionary(i, &dict)) 874 continue; 875 if (ProtocolHandler::IsValidDict(dict)) { 876 result.push_back(dict); 877 } 878 } 879 } 880 return result; 881 } 882 883 void ProtocolHandlerRegistry::RegisterProtocolHandlersFromPref( 884 const char* pref_name, 885 const HandlerSource source) { 886 std::vector<const base::DictionaryValue*> registered_handlers = 887 GetHandlersFromPref(pref_name); 888 for (std::vector<const base::DictionaryValue*>::const_iterator p = 889 registered_handlers.begin(); 890 p != registered_handlers.end(); 891 ++p) { 892 ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p); 893 RegisterProtocolHandler(handler, source); 894 bool is_default = false; 895 if ((*p)->GetBoolean("default", &is_default) && is_default) { 896 SetDefault(handler); 897 } 898 } 899 } 900 901 void ProtocolHandlerRegistry::IgnoreProtocolHandler( 902 const ProtocolHandler& handler, 903 const HandlerSource source) { 904 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 905 ProtocolHandlerList& list = (source == POLICY) 906 ? policy_ignored_protocol_handlers_ 907 : user_ignored_protocol_handlers_; 908 if (!HandlerExists(handler, list)) 909 list.push_back(handler); 910 if (HandlerExists(handler, ignored_protocol_handlers_)) 911 return; 912 ignored_protocol_handlers_.push_back(handler); 913 } 914 915 void ProtocolHandlerRegistry::IgnoreProtocolHandlersFromPref( 916 const char* pref_name, 917 const HandlerSource source) { 918 std::vector<const base::DictionaryValue*> ignored_handlers = 919 GetHandlersFromPref(pref_name); 920 for (std::vector<const base::DictionaryValue*>::const_iterator p = 921 ignored_handlers.begin(); 922 p != ignored_handlers.end(); 923 ++p) { 924 IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p), source); 925 } 926 } 927 928 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler, 929 ProtocolHandlerMultiMap* map) { 930 return HandlerExists(handler, (*map)[handler.protocol()]); 931 } 932 933 bool ProtocolHandlerRegistry::HandlerExists(const ProtocolHandler& handler, 934 const ProtocolHandlerList& list) { 935 return std::find(list.begin(), list.end(), handler) != list.end(); 936 } 937 938 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler, 939 ProtocolHandlerMultiMap* map) { 940 EraseHandler(handler, &(*map)[handler.protocol()]); 941 } 942 943 void ProtocolHandlerRegistry::EraseHandler(const ProtocolHandler& handler, 944 ProtocolHandlerList* list) { 945 list->erase(std::find(list->begin(), list->end(), handler)); 946 } 947 948 void ProtocolHandlerRegistry::AddPredefinedHandler( 949 const ProtocolHandler& handler) { 950 DCHECK(!is_loaded_); // Must be called prior InitProtocolSettings. 951 RegisterProtocolHandler(handler, USER); 952 SetDefault(handler); 953 } 954 955 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory> 956 ProtocolHandlerRegistry::CreateJobInterceptorFactory() { 957 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 958 // this is always created on the UI thread (in profile_io's 959 // InitializeOnUIThread. Any method calls must be done 960 // on the IO thread (this is checked). 961 return scoped_ptr<JobInterceptorFactory>( 962 new JobInterceptorFactory(io_thread_delegate_.get())); 963 } 964