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/net/chrome_url_request_context.h" 16 #include "chrome/browser/profiles/profile_io_data.h" 17 #include "chrome/common/chrome_switches.h" 18 #include "chrome/common/custom_handlers/protocol_handler.h" 19 #include "chrome/common/pref_names.h" 20 #include "components/user_prefs/pref_registry_syncable.h" 21 #include "content/public/browser/child_process_security_policy.h" 22 #include "grit/generated_resources.h" 23 #include "net/base/network_delegate.h" 24 #include "net/url_request/url_request_redirect_job.h" 25 #include "ui/base/l10n/l10n_util.h" 26 27 using content::BrowserThread; 28 using content::ChildProcessSecurityPolicy; 29 30 namespace { 31 32 const ProtocolHandler& LookupHandler( 33 const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map, 34 const std::string& scheme) { 35 ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p = 36 handler_map.find(scheme); 37 38 if (p != handler_map.end()) 39 return p->second; 40 41 return ProtocolHandler::EmptyProtocolHandler(); 42 } 43 44 // If true default protocol handlers will be removed if the OS level 45 // registration for a protocol is no longer Chrome. 46 bool ShouldRemoveHandlersNotInOS() { 47 #if defined(OS_LINUX) 48 // We don't do this on Linux as the OS registration there is not reliable, 49 // and Chrome OS doesn't have any notion of OS registration. 50 // TODO(benwells): When Linux support is more reliable remove this 51 // difference (http://crbug.com/88255). 52 return false; 53 #else 54 return ShellIntegration::CanSetAsDefaultProtocolClient() != 55 ShellIntegration::SET_DEFAULT_NOT_ALLOWED; 56 #endif 57 } 58 59 } // namespace 60 61 // IOThreadDelegate ------------------------------------------------------------ 62 63 // IOThreadDelegate is an IO thread specific object. Access to the class should 64 // all be done via the IO thread. The registry living on the UI thread makes 65 // a best effort to update the IO object after local updates are completed. 66 class ProtocolHandlerRegistry::IOThreadDelegate 67 : public base::RefCountedThreadSafe< 68 ProtocolHandlerRegistry::IOThreadDelegate> { 69 public: 70 71 // Creates a new instance. If |enabled| is true the registry is considered 72 // enabled on the IO thread. 73 explicit IOThreadDelegate(bool enabled); 74 75 // Returns true if the protocol has a default protocol handler. 76 // Should be called only from the IO thread. 77 bool IsHandledProtocol(const std::string& scheme) const; 78 79 // Clears the default for the provided protocol. 80 // Should be called only from the IO thread. 81 void ClearDefault(const std::string& scheme); 82 83 // Makes this ProtocolHandler the default handler for its protocol. 84 // Should be called only from the IO thread. 85 void SetDefault(const ProtocolHandler& handler); 86 87 // Creates a URL request job for the given request if there is a matching 88 // protocol handler, returns NULL otherwise. 89 net::URLRequestJob* MaybeCreateJob( 90 net::URLRequest* request, net::NetworkDelegate* network_delegate) const; 91 92 // Indicate that the registry has been enabled in the IO thread's 93 // copy of the data. 94 void Enable() { enabled_ = true; } 95 96 // Indicate that the registry has been disabled in the IO thread's copy of 97 // the data. 98 void Disable() { enabled_ = false; } 99 100 private: 101 friend class base::RefCountedThreadSafe<IOThreadDelegate>; 102 virtual ~IOThreadDelegate(); 103 104 // Copy of protocol handlers use only on the IO thread. 105 ProtocolHandlerRegistry::ProtocolHandlerMap default_handlers_; 106 107 // Is the registry enabled on the IO thread. 108 bool enabled_; 109 110 DISALLOW_COPY_AND_ASSIGN(IOThreadDelegate); 111 }; 112 113 ProtocolHandlerRegistry::IOThreadDelegate::IOThreadDelegate(bool) 114 : enabled_(true) {} 115 ProtocolHandlerRegistry::IOThreadDelegate::~IOThreadDelegate() {} 116 117 bool ProtocolHandlerRegistry::IOThreadDelegate::IsHandledProtocol( 118 const std::string& scheme) const { 119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 120 return enabled_ && !LookupHandler(default_handlers_, scheme).IsEmpty(); 121 } 122 123 void ProtocolHandlerRegistry::IOThreadDelegate::ClearDefault( 124 const std::string& scheme) { 125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 126 default_handlers_.erase(scheme); 127 } 128 129 void ProtocolHandlerRegistry::IOThreadDelegate::SetDefault( 130 const ProtocolHandler& handler) { 131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 132 ClearDefault(handler.protocol()); 133 default_handlers_.insert(std::make_pair(handler.protocol(), handler)); 134 } 135 136 // Create a new job for the supplied |URLRequest| if a default handler 137 // is registered and the associated handler is able to interpret 138 // the url from |request|. 139 net::URLRequestJob* ProtocolHandlerRegistry::IOThreadDelegate::MaybeCreateJob( 140 net::URLRequest* request, net::NetworkDelegate* network_delegate) const { 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 142 143 ProtocolHandler handler = LookupHandler(default_handlers_, 144 request->url().scheme()); 145 if (handler.IsEmpty()) 146 return NULL; 147 148 GURL translated_url(handler.TranslateUrl(request->url())); 149 if (!translated_url.is_valid()) 150 return NULL; 151 152 return new net::URLRequestRedirectJob( 153 request, network_delegate, translated_url, 154 net::URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT); 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(Profile* profile, 312 Delegate* delegate) 313 : profile_(profile), 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); 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); 348 Save(); 349 NotifyChanged(); 350 } 351 352 void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler( 353 const ProtocolHandler& handler) { 354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 355 IgnoreProtocolHandler(handler); 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 l10n_util::GetStringUTF16(IDS_GOOGLE_MAILTO_HANDLER_NAME))); 422 AddPredefinedHandler( 423 ProtocolHandler::CreateProtocolHandler( 424 "webcal", 425 GURL(l10n_util::GetStringUTF8(IDS_GOOGLE_WEBCAL_HANDLER_URL)), 426 l10n_util::GetStringUTF16(IDS_GOOGLE_WEBCAL_HANDLER_NAME))); 427 #else 428 NOTREACHED(); // this method should only ever be called in chromeos. 429 #endif 430 } 431 432 void ProtocolHandlerRegistry::InitProtocolSettings() { 433 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 434 435 // Any further default additions to the table will get rejected from now on. 436 is_loaded_ = true; 437 is_loading_ = true; 438 439 PrefService* prefs = profile_->GetPrefs(); 440 if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) { 441 if (prefs->GetBoolean(prefs::kCustomHandlersEnabled)) { 442 Enable(); 443 } else { 444 Disable(); 445 } 446 } 447 std::vector<const DictionaryValue*> registered_handlers = 448 GetHandlersFromPref(prefs::kRegisteredProtocolHandlers); 449 for (std::vector<const DictionaryValue*>::const_iterator p = 450 registered_handlers.begin(); 451 p != registered_handlers.end(); ++p) { 452 ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p); 453 RegisterProtocolHandler(handler); 454 bool is_default = false; 455 if ((*p)->GetBoolean("default", &is_default) && is_default) { 456 SetDefault(handler); 457 } 458 } 459 std::vector<const DictionaryValue*> ignored_handlers = 460 GetHandlersFromPref(prefs::kIgnoredProtocolHandlers); 461 for (std::vector<const DictionaryValue*>::const_iterator p = 462 ignored_handlers.begin(); 463 p != ignored_handlers.end(); ++p) { 464 IgnoreProtocolHandler(ProtocolHandler::CreateProtocolHandler(*p)); 465 } 466 is_loading_ = false; 467 468 // For each default protocol handler, check that we are still registered 469 // with the OS as the default application. 470 if (ShouldRemoveHandlersNotInOS()) { 471 for (ProtocolHandlerMap::const_iterator p = default_handlers_.begin(); 472 p != default_handlers_.end(); ++p) { 473 ProtocolHandler handler = p->second; 474 DefaultClientObserver* observer = delegate_->CreateShellObserver(this); 475 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker; 476 worker = delegate_->CreateShellWorker(observer, handler.protocol()); 477 observer->SetWorker(worker.get()); 478 default_client_observers_.push_back(observer); 479 worker->StartCheckIsDefault(); 480 } 481 } 482 } 483 484 int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const { 485 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 486 const ProtocolHandler& handler = GetHandlerFor(scheme); 487 if (handler.IsEmpty()) 488 return -1; 489 const ProtocolHandlerList* handlers = GetHandlerList(scheme); 490 if (!handlers) 491 return -1; 492 493 ProtocolHandlerList::const_iterator p; 494 int i; 495 for (i = 0, p = handlers->begin(); p != handlers->end(); ++p, ++i) { 496 if (*p == handler) 497 return i; 498 } 499 return -1; 500 } 501 502 ProtocolHandlerRegistry::ProtocolHandlerList 503 ProtocolHandlerRegistry::GetHandlersFor( 504 const std::string& scheme) const { 505 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 506 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); 507 if (p == protocol_handlers_.end()) { 508 return ProtocolHandlerList(); 509 } 510 return p->second; 511 } 512 513 ProtocolHandlerRegistry::ProtocolHandlerList 514 ProtocolHandlerRegistry::GetIgnoredHandlers() { 515 return ignored_protocol_handlers_; 516 } 517 518 void ProtocolHandlerRegistry::GetRegisteredProtocols( 519 std::vector<std::string>* output) const { 520 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 521 ProtocolHandlerMultiMap::const_iterator p; 522 for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); ++p) { 523 if (!p->second.empty()) 524 output->push_back(p->first); 525 } 526 } 527 528 bool ProtocolHandlerRegistry::CanSchemeBeOverridden( 529 const std::string& scheme) const { 530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 531 const ProtocolHandlerList* handlers = GetHandlerList(scheme); 532 // If we already have a handler for this scheme, we can add more. 533 if (handlers != NULL && !handlers->empty()) 534 return true; 535 // Don't override a scheme if it already has an external handler. 536 return !delegate_->IsExternalHandlerRegistered(scheme); 537 } 538 539 bool ProtocolHandlerRegistry::IsRegistered( 540 const ProtocolHandler& handler) const { 541 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 542 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); 543 if (!handlers) { 544 return false; 545 } 546 return std::find(handlers->begin(), handlers->end(), handler) != 547 handlers->end(); 548 } 549 550 bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler& handler) const { 551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 552 ProtocolHandlerList::const_iterator i; 553 for (i = ignored_protocol_handlers_.begin(); 554 i != ignored_protocol_handlers_.end(); ++i) { 555 if (*i == handler) { 556 return true; 557 } 558 } 559 return false; 560 } 561 562 bool ProtocolHandlerRegistry::HasRegisteredEquivalent( 563 const ProtocolHandler& handler) const { 564 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 565 const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol()); 566 if (!handlers) { 567 return false; 568 } 569 ProtocolHandlerList::const_iterator i; 570 for (i = handlers->begin(); i != handlers->end(); ++i) { 571 if (handler.IsEquivalent(*i)) { 572 return true; 573 } 574 } 575 return false; 576 } 577 578 bool ProtocolHandlerRegistry::HasIgnoredEquivalent( 579 const ProtocolHandler& handler) const { 580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 581 ProtocolHandlerList::const_iterator i; 582 for (i = ignored_protocol_handlers_.begin(); 583 i != ignored_protocol_handlers_.end(); ++i) { 584 if (handler.IsEquivalent(*i)) { 585 return true; 586 } 587 } 588 return false; 589 } 590 591 void ProtocolHandlerRegistry::RemoveIgnoredHandler( 592 const ProtocolHandler& handler) { 593 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 594 bool should_notify = false; 595 ProtocolHandlerList::iterator p = std::find( 596 ignored_protocol_handlers_.begin(), ignored_protocol_handlers_.end(), 597 handler); 598 if (p != ignored_protocol_handlers_.end()) { 599 ignored_protocol_handlers_.erase(p); 600 Save(); 601 should_notify = true; 602 } 603 if (should_notify) 604 NotifyChanged(); 605 } 606 607 bool ProtocolHandlerRegistry::IsHandledProtocol( 608 const std::string& scheme) const { 609 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 610 return enabled_ && !GetHandlerFor(scheme).IsEmpty(); 611 } 612 613 void ProtocolHandlerRegistry::RemoveHandler( 614 const ProtocolHandler& handler) { 615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 616 ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()]; 617 ProtocolHandlerList::iterator p = 618 std::find(handlers.begin(), handlers.end(), handler); 619 if (p != handlers.end()) { 620 handlers.erase(p); 621 } 622 ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol()); 623 if (q != default_handlers_.end() && q->second == handler) { 624 // Make the new top handler in the list the default. 625 if (!handlers.empty()) { 626 // NOTE We pass a copy because SetDefault() modifies handlers. 627 SetDefault(ProtocolHandler(handlers[0])); 628 } else { 629 BrowserThread::PostTask( 630 BrowserThread::IO, FROM_HERE, 631 base::Bind(&IOThreadDelegate::ClearDefault, io_thread_delegate_, 632 q->second.protocol())); 633 634 default_handlers_.erase(q); 635 } 636 } 637 638 if (!IsHandledProtocol(handler.protocol())) { 639 delegate_->DeregisterExternalHandler(handler.protocol()); 640 } 641 Save(); 642 NotifyChanged(); 643 } 644 645 void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) { 646 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 647 ProtocolHandler current_default = GetHandlerFor(scheme); 648 if (!current_default.IsEmpty()) 649 RemoveHandler(current_default); 650 } 651 652 const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor( 653 const std::string& scheme) const { 654 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 655 return LookupHandler(default_handlers_, scheme); 656 } 657 658 void ProtocolHandlerRegistry::Enable() { 659 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 660 if (enabled_) { 661 return; 662 } 663 enabled_ = true; 664 BrowserThread::PostTask( 665 BrowserThread::IO, 666 FROM_HERE, 667 base::Bind(&IOThreadDelegate::Enable, io_thread_delegate_)); 668 669 ProtocolHandlerMap::const_iterator p; 670 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { 671 delegate_->RegisterExternalHandler(p->first); 672 } 673 Save(); 674 NotifyChanged(); 675 } 676 677 void ProtocolHandlerRegistry::Disable() { 678 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 679 if (!enabled_) { 680 return; 681 } 682 enabled_ = false; 683 BrowserThread::PostTask( 684 BrowserThread::IO, 685 FROM_HERE, 686 base::Bind(&IOThreadDelegate::Disable, io_thread_delegate_)); 687 688 ProtocolHandlerMap::const_iterator p; 689 for (p = default_handlers_.begin(); p != default_handlers_.end(); ++p) { 690 delegate_->DeregisterExternalHandler(p->first); 691 } 692 Save(); 693 NotifyChanged(); 694 } 695 696 void ProtocolHandlerRegistry::Shutdown() { 697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 698 delegate_.reset(NULL); 699 // We free these now in case there are any outstanding workers running. If 700 // we didn't free them they could respond to workers and try to update the 701 // protocol handler registry after it was deleted. 702 // Observers remove themselves from this list when they are deleted; so 703 // we delete the last item until none are left in the list. 704 while (!default_client_observers_.empty()) { 705 delete default_client_observers_.back(); 706 } 707 } 708 709 // static 710 void ProtocolHandlerRegistry::RegisterProfilePrefs( 711 user_prefs::PrefRegistrySyncable* registry) { 712 registry->RegisterListPref(prefs::kRegisteredProtocolHandlers, 713 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 714 registry->RegisterListPref(prefs::kIgnoredProtocolHandlers, 715 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 716 registry->RegisterBooleanPref( 717 prefs::kCustomHandlersEnabled, 718 true, 719 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 720 } 721 722 ProtocolHandlerRegistry::~ProtocolHandlerRegistry() { 723 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 724 DCHECK(default_client_observers_.empty()); 725 } 726 727 void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) { 728 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 729 DCHECK(IsRegistered(handler)); 730 ProtocolHandlerMultiMap::iterator p = 731 protocol_handlers_.find(handler.protocol()); 732 ProtocolHandlerList& list = p->second; 733 list.erase(std::find(list.begin(), list.end(), handler)); 734 list.insert(list.begin(), handler); 735 } 736 737 void ProtocolHandlerRegistry::Save() { 738 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 739 if (is_loading_) { 740 return; 741 } 742 scoped_ptr<Value> registered_protocol_handlers(EncodeRegisteredHandlers()); 743 scoped_ptr<Value> ignored_protocol_handlers(EncodeIgnoredHandlers()); 744 scoped_ptr<Value> enabled(Value::CreateBooleanValue(enabled_)); 745 profile_->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers, 746 *registered_protocol_handlers); 747 profile_->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers, 748 *ignored_protocol_handlers); 749 profile_->GetPrefs()->Set(prefs::kCustomHandlersEnabled, *enabled); 750 } 751 752 const ProtocolHandlerRegistry::ProtocolHandlerList* 753 ProtocolHandlerRegistry::GetHandlerList( 754 const std::string& scheme) const { 755 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 756 ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme); 757 if (p == protocol_handlers_.end()) { 758 return NULL; 759 } 760 return &p->second; 761 } 762 763 void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) { 764 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 765 ProtocolHandlerMap::const_iterator p = default_handlers_.find( 766 handler.protocol()); 767 // If we're not loading, and we are setting a default for a new protocol, 768 // register with the OS. 769 if (!is_loading_ && p == default_handlers_.end()) 770 delegate_->RegisterWithOSAsDefaultClient(handler.protocol(), this); 771 default_handlers_.erase(handler.protocol()); 772 default_handlers_.insert(std::make_pair(handler.protocol(), handler)); 773 PromoteHandler(handler); 774 BrowserThread::PostTask( 775 BrowserThread::IO, 776 FROM_HERE, 777 base::Bind(&IOThreadDelegate::SetDefault, io_thread_delegate_, handler)); 778 } 779 780 void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) { 781 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 782 ProtocolHandlerMultiMap::iterator p = 783 protocol_handlers_.find(handler.protocol()); 784 785 if (p != protocol_handlers_.end()) { 786 p->second.push_back(handler); 787 return; 788 } 789 790 ProtocolHandlerList new_list; 791 new_list.push_back(handler); 792 protocol_handlers_[handler.protocol()] = new_list; 793 } 794 795 Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() { 796 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 797 ListValue* protocol_handlers = new ListValue(); 798 for (ProtocolHandlerMultiMap::iterator i = protocol_handlers_.begin(); 799 i != protocol_handlers_.end(); ++i) { 800 for (ProtocolHandlerList::iterator j = i->second.begin(); 801 j != i->second.end(); ++j) { 802 DictionaryValue* encoded = j->Encode(); 803 if (IsDefault(*j)) { 804 encoded->Set("default", Value::CreateBooleanValue(true)); 805 } 806 protocol_handlers->Append(encoded); 807 } 808 } 809 return protocol_handlers; 810 } 811 812 Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() { 813 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 814 ListValue* handlers = new ListValue(); 815 for (ProtocolHandlerList::iterator i = ignored_protocol_handlers_.begin(); 816 i != ignored_protocol_handlers_.end(); ++i) { 817 handlers->Append(i->Encode()); 818 } 819 return handlers; 820 } 821 822 void ProtocolHandlerRegistry::NotifyChanged() { 823 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 824 content::NotificationService::current()->Notify( 825 chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, 826 content::Source<Profile>(profile_), 827 content::NotificationService::NoDetails()); 828 } 829 830 void ProtocolHandlerRegistry::RegisterProtocolHandler( 831 const ProtocolHandler& handler) { 832 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 833 DCHECK(CanSchemeBeOverridden(handler.protocol())); 834 DCHECK(!handler.IsEmpty()); 835 if (IsRegistered(handler)) { 836 return; 837 } 838 if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol())) 839 delegate_->RegisterExternalHandler(handler.protocol()); 840 InsertHandler(handler); 841 } 842 843 std::vector<const DictionaryValue*> 844 ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const { 845 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 846 std::vector<const DictionaryValue*> result; 847 PrefService* prefs = profile_->GetPrefs(); 848 if (!prefs->HasPrefPath(pref_name)) { 849 return result; 850 } 851 852 const ListValue* handlers = prefs->GetList(pref_name); 853 if (handlers) { 854 for (size_t i = 0; i < handlers->GetSize(); ++i) { 855 const DictionaryValue* dict; 856 if (!handlers->GetDictionary(i, &dict)) 857 continue; 858 if (ProtocolHandler::IsValidDict(dict)) { 859 result.push_back(dict); 860 } 861 } 862 } 863 return result; 864 } 865 866 void ProtocolHandlerRegistry::IgnoreProtocolHandler( 867 const ProtocolHandler& handler) { 868 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 869 ignored_protocol_handlers_.push_back(handler); 870 } 871 872 void ProtocolHandlerRegistry::AddPredefinedHandler( 873 const ProtocolHandler& handler) { 874 DCHECK(!is_loaded_); // Must be called prior InitProtocolSettings. 875 RegisterProtocolHandler(handler); 876 SetDefault(handler); 877 } 878 879 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory> 880 ProtocolHandlerRegistry::CreateJobInterceptorFactory() { 881 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 882 // this is always created on the UI thread (in profile_io's 883 // InitializeOnUIThread. Any method calls must be done 884 // on the IO thread (this is checked). 885 return scoped_ptr<JobInterceptorFactory>( 886 new JobInterceptorFactory(io_thread_delegate_.get())); 887 } 888