| Index: content/browser/service_worker/service_worker_provider_host.cc
 | 
| diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
 | 
| index da614200afed55b3a69cc40b022f9e903a3d6509..3f333f9aa431c313593f18fffa5ad4915e80f0e9 100644
 | 
| --- a/content/browser/service_worker/service_worker_provider_host.cc
 | 
| +++ b/content/browser/service_worker/service_worker_provider_host.cc
 | 
| @@ -58,6 +58,15 @@ ServiceWorkerClientInfo FocusOnUIThread(
 | 
|  
 | 
|  }  // anonymous namespace
 | 
|  
 | 
| +ServiceWorkerProviderHost::OneShotGetReadyCallback::OneShotGetReadyCallback(
 | 
| +    const GetRegistrationForReadyCallback& callback)
 | 
| +    : callback(callback),
 | 
| +      called(false) {
 | 
| +}
 | 
| +
 | 
| +ServiceWorkerProviderHost::OneShotGetReadyCallback::~OneShotGetReadyCallback() {
 | 
| +}
 | 
| +
 | 
|  ServiceWorkerProviderHost::ServiceWorkerProviderHost(
 | 
|      int render_process_id,
 | 
|      int render_frame_id,
 | 
| @@ -88,24 +97,47 @@ ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
 | 
|    document_url_ = GURL();
 | 
|    if (controlling_version_.get())
 | 
|      controlling_version_->RemoveControllee(this);
 | 
| -  if (associated_registration_.get()) {
 | 
| -    DecreaseProcessReference(associated_registration_->pattern());
 | 
| -    associated_registration_->RemoveListener(this);
 | 
| +
 | 
| +  for (auto& key_registration : matching_registrations_) {
 | 
| +    DecreaseProcessReference(key_registration.second->pattern());
 | 
| +    key_registration.second->RemoveListener(this);
 | 
|    }
 | 
|  
 | 
|    for (const GURL& pattern : associated_patterns_)
 | 
|      DecreaseProcessReference(pattern);
 | 
|  }
 | 
|  
 | 
| +void ServiceWorkerProviderHost::OnVersionAttributesChanged(
 | 
| +    ServiceWorkerRegistration* registration,
 | 
| +    ChangedVersionAttributesMask changed_mask,
 | 
| +    const ServiceWorkerRegistrationInfo& info) {
 | 
| +  if (!get_ready_callback_ || get_ready_callback_->called)
 | 
| +    return;
 | 
| +  if (changed_mask.active_changed() && registration->active_version()) {
 | 
| +    // Wait until the state change so we don't send the get for ready
 | 
| +    // registration complete message before set version attributes message.
 | 
| +    registration->active_version()->RegisterStatusChangeCallback(base::Bind(
 | 
| +          &ServiceWorkerProviderHost::ReturnRegistrationForReadyIfNeeded,
 | 
| +          AsWeakPtr()));
 | 
| +  }
 | 
| +}
 | 
| +
 | 
|  void ServiceWorkerProviderHost::OnRegistrationFailed(
 | 
|      ServiceWorkerRegistration* registration) {
 | 
| -  DCHECK_EQ(associated_registration_.get(), registration);
 | 
| -  DisassociateRegistration();
 | 
| +  if (associated_registration_ == registration)
 | 
| +    DisassociateRegistration();
 | 
| +  RemoveMatchingRegistration(registration);
 | 
| +}
 | 
| +
 | 
| +void ServiceWorkerProviderHost::OnRegistrationFinishedUninstalling(
 | 
| +    ServiceWorkerRegistration* registration) {
 | 
| +  RemoveMatchingRegistration(registration);
 | 
|  }
 | 
|  
 | 
|  void ServiceWorkerProviderHost::OnSkippedWaiting(
 | 
|      ServiceWorkerRegistration* registration) {
 | 
| -  DCHECK_EQ(associated_registration_.get(), registration);
 | 
| +  if (associated_registration_ != registration)
 | 
| +    return;
 | 
|    // A client is "using" a registration if it is controlled by the active
 | 
|    // worker of the registration. skipWaiting doesn't cause a client to start
 | 
|    // using the registration.
 | 
| @@ -176,9 +208,8 @@ bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) {
 | 
|  void ServiceWorkerProviderHost::AssociateRegistration(
 | 
|      ServiceWorkerRegistration* registration) {
 | 
|    DCHECK(CanAssociateRegistration(registration));
 | 
| -  IncreaseProcessReference(registration->pattern());
 | 
|    associated_registration_ = registration;
 | 
| -  associated_registration_->AddListener(this);
 | 
| +  AddMatchingRegistration(registration);
 | 
|    SendAssociateRegistrationMessage();
 | 
|    SetControllerVersionAttribute(registration->active_version());
 | 
|  }
 | 
| @@ -187,8 +218,6 @@ void ServiceWorkerProviderHost::DisassociateRegistration() {
 | 
|    queued_events_.clear();
 | 
|    if (!associated_registration_.get())
 | 
|      return;
 | 
| -  DecreaseProcessReference(associated_registration_->pattern());
 | 
| -  associated_registration_->RemoveListener(this);
 | 
|    associated_registration_ = NULL;
 | 
|    SetControllerVersionAttribute(NULL);
 | 
|  
 | 
| @@ -201,6 +230,42 @@ void ServiceWorkerProviderHost::DisassociateRegistration() {
 | 
|        render_thread_id_, provider_id()));
 | 
|  }
 | 
|  
 | 
| +void ServiceWorkerProviderHost::AddMatchingRegistration(
 | 
| +    ServiceWorkerRegistration* registration) {
 | 
| +  DCHECK(ServiceWorkerUtils::ScopeMatches(
 | 
| +        registration->pattern(), document_url_));
 | 
| +  size_t key = registration->pattern().spec().size();
 | 
| +  if (ContainsKey(matching_registrations_, key))
 | 
| +    return;
 | 
| +  IncreaseProcessReference(registration->pattern());
 | 
| +  registration->AddListener(this);
 | 
| +  matching_registrations_[key] = registration;
 | 
| +  ReturnRegistrationForReadyIfNeeded();
 | 
| +}
 | 
| +
 | 
| +void ServiceWorkerProviderHost::RemoveMatchingRegistration(
 | 
| +    ServiceWorkerRegistration* registration) {
 | 
| +  size_t key = registration->pattern().spec().size();
 | 
| +  DCHECK(ContainsKey(matching_registrations_, key));
 | 
| +  DecreaseProcessReference(registration->pattern());
 | 
| +  registration->RemoveListener(this);
 | 
| +  matching_registrations_.erase(key);
 | 
| +}
 | 
| +
 | 
| +ServiceWorkerRegistration*
 | 
| +ServiceWorkerProviderHost::MatchRegistration() const {
 | 
| +  ServiceWorkerRegistrationMap::const_reverse_iterator it =
 | 
| +      matching_registrations_.rbegin();
 | 
| +  for (; it != matching_registrations_.rend(); ++it) {
 | 
| +    if (it->second->is_uninstalled())
 | 
| +      continue;
 | 
| +    if (it->second->is_uninstalling())
 | 
| +      return nullptr;
 | 
| +    return it->second.get();
 | 
| +  }
 | 
| +  return nullptr;
 | 
| +}
 | 
| +
 | 
|  scoped_ptr<ServiceWorkerRequestHandler>
 | 
|  ServiceWorkerProviderHost::CreateRequestHandler(
 | 
|      FetchRequestMode request_mode,
 | 
| @@ -332,6 +397,15 @@ void ServiceWorkerProviderHost::ClaimedByRegistration(
 | 
|    is_claiming_ = false;
 | 
|  }
 | 
|  
 | 
| +bool ServiceWorkerProviderHost::GetRegistrationForReady(
 | 
| +    const GetRegistrationForReadyCallback& callback) {
 | 
| +  if (get_ready_callback_)
 | 
| +    return false;
 | 
| +  get_ready_callback_.reset(new OneShotGetReadyCallback(callback));
 | 
| +  ReturnRegistrationForReadyIfNeeded();
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
|  void ServiceWorkerProviderHost::PrepareForCrossSiteTransfer() {
 | 
|    DCHECK_NE(ChildProcessHost::kInvalidUniqueID, render_process_id_);
 | 
|    DCHECK_NE(MSG_ROUTING_NONE, render_frame_id_);
 | 
| @@ -341,8 +415,10 @@ void ServiceWorkerProviderHost::PrepareForCrossSiteTransfer() {
 | 
|    for (const GURL& pattern : associated_patterns_)
 | 
|      DecreaseProcessReference(pattern);
 | 
|  
 | 
| +  for (auto& key_registration : matching_registrations_)
 | 
| +    DecreaseProcessReference(key_registration.second->pattern());
 | 
| +
 | 
|    if (associated_registration_.get()) {
 | 
| -    DecreaseProcessReference(associated_registration_->pattern());
 | 
|      if (dispatcher_host_) {
 | 
|        Send(new ServiceWorkerMsg_DisassociateRegistration(
 | 
|            render_thread_id_, provider_id()));
 | 
| @@ -377,8 +453,10 @@ void ServiceWorkerProviderHost::CompleteCrossSiteTransfer(
 | 
|    for (const GURL& pattern : associated_patterns_)
 | 
|      IncreaseProcessReference(pattern);
 | 
|  
 | 
| +  for (auto& key_registration : matching_registrations_)
 | 
| +    IncreaseProcessReference(key_registration.second->pattern());
 | 
| +
 | 
|    if (associated_registration_.get()) {
 | 
| -    IncreaseProcessReference(associated_registration_->pattern());
 | 
|      SendAssociateRegistrationMessage();
 | 
|      if (dispatcher_host_ && associated_registration_->active_version()) {
 | 
|        Send(new ServiceWorkerMsg_SetControllerServiceWorker(
 | 
| @@ -504,6 +582,20 @@ void ServiceWorkerProviderHost::DecreaseProcessReference(
 | 
|    }
 | 
|  }
 | 
|  
 | 
| +void ServiceWorkerProviderHost::ReturnRegistrationForReadyIfNeeded() {
 | 
| +  if (!get_ready_callback_ || get_ready_callback_->called)
 | 
| +    return;
 | 
| +  ServiceWorkerRegistration* registration = MatchRegistration();
 | 
| +  if (!registration)
 | 
| +    return;
 | 
| +  if (registration->active_version()) {
 | 
| +    get_ready_callback_->callback.Run(registration);
 | 
| +    get_ready_callback_->callback.Reset();
 | 
| +    get_ready_callback_->called = true;
 | 
| +    return;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
|  bool ServiceWorkerProviderHost::IsReadyToSendMessages() const {
 | 
|    return render_thread_id_ != kInvalidEmbeddedWorkerThreadId;
 | 
|  }
 | 
| 
 |