service_worker_controllee_request_handler.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1// Copyright 2014 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 "content/browser/service_worker/service_worker_controllee_request_handler.h" 6 7#include "content/browser/service_worker/service_worker_context_core.h" 8#include "content/browser/service_worker/service_worker_metrics.h" 9#include "content/browser/service_worker/service_worker_provider_host.h" 10#include "content/browser/service_worker/service_worker_registration.h" 11#include "content/browser/service_worker/service_worker_url_request_job.h" 12#include "content/browser/service_worker/service_worker_utils.h" 13#include "content/common/service_worker/service_worker_types.h" 14#include "net/base/load_flags.h" 15#include "net/base/net_util.h" 16#include "net/url_request/url_request.h" 17 18namespace content { 19 20ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler( 21 base::WeakPtr<ServiceWorkerContextCore> context, 22 base::WeakPtr<ServiceWorkerProviderHost> provider_host, 23 base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context, 24 ResourceType resource_type) 25 : ServiceWorkerRequestHandler(context, 26 provider_host, 27 blob_storage_context, 28 resource_type), 29 is_main_resource_load_( 30 ServiceWorkerUtils::IsMainResourceType(resource_type)), 31 weak_factory_(this) { 32} 33 34ServiceWorkerControlleeRequestHandler:: 35 ~ServiceWorkerControlleeRequestHandler() { 36 // Navigation triggers an update to occur shortly after the page and 37 // its initial subresources load. 38 if (provider_host_ && provider_host_->active_version()) { 39 if (is_main_resource_load_) 40 provider_host_->active_version()->ScheduleUpdate(); 41 else 42 provider_host_->active_version()->DeferScheduledUpdate(); 43 } 44} 45 46net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob( 47 net::URLRequest* request, 48 net::NetworkDelegate* network_delegate) { 49 if (!context_ || !provider_host_) { 50 // We can't do anything other than to fall back to network. 51 job_ = NULL; 52 return NULL; 53 } 54 55 if (request->load_flags() & net::LOAD_BYPASS_CACHE) { 56 if (is_main_resource_load_) { 57 provider_host_->SetDocumentUrl( 58 net::SimplifyUrlForRequest(request->url())); 59 } 60 job_ = NULL; 61 return NULL; 62 } 63 64 // This may get called multiple times for original and redirect requests: 65 // A. original request case: job_ is null, no previous location info. 66 // B. redirect or restarted request case: 67 // a) job_ is non-null if the previous location was forwarded to SW. 68 // b) job_ is null if the previous location was fallback. 69 // c) job_ is non-null if additional restart was required to fall back. 70 71 // We've come here by restart, we already have original request and it 72 // tells we should fallback to network. (Case B-c) 73 if (job_.get() && job_->ShouldFallbackToNetwork()) { 74 job_ = NULL; 75 return NULL; 76 } 77 78 // It's for original request (A) or redirect case (B-a or B-b). 79 DCHECK(!job_.get() || job_->ShouldForwardToServiceWorker()); 80 81 job_ = new ServiceWorkerURLRequestJob( 82 request, network_delegate, provider_host_, blob_storage_context_); 83 if (is_main_resource_load_) 84 PrepareForMainResource(request->url()); 85 else 86 PrepareForSubResource(); 87 88 if (job_->ShouldFallbackToNetwork()) { 89 // If we know we can fallback to network at this point (in case 90 // the storage lookup returned immediately), just return NULL here to 91 // fallback to network. 92 job_ = NULL; 93 return NULL; 94 } 95 96 return job_.get(); 97} 98 99void ServiceWorkerControlleeRequestHandler::GetExtraResponseInfo( 100 bool* was_fetched_via_service_worker, 101 GURL* original_url_via_service_worker) const { 102 if (!job_) { 103 *was_fetched_via_service_worker = false; 104 *original_url_via_service_worker = GURL(); 105 return; 106 } 107 job_->GetExtraResponseInfo(was_fetched_via_service_worker, 108 original_url_via_service_worker); 109} 110 111void ServiceWorkerControlleeRequestHandler::PrepareForMainResource( 112 const GURL& url) { 113 DCHECK(job_.get()); 114 DCHECK(context_); 115 // The corresponding provider_host may already have associated a registration 116 // in redirect case, unassociate it now. 117 provider_host_->SetControllerVersion(NULL); 118 provider_host_->SetActiveVersion(NULL); 119 provider_host_->SetWaitingVersion(NULL); 120 provider_host_->SetInstallingVersion(NULL); 121 122 GURL stripped_url = net::SimplifyUrlForRequest(url); 123 provider_host_->SetDocumentUrl(stripped_url); 124 context_->storage()->FindRegistrationForDocument( 125 stripped_url, 126 base::Bind(&self::DidLookupRegistrationForMainResource, 127 weak_factory_.GetWeakPtr())); 128} 129 130void 131ServiceWorkerControlleeRequestHandler::DidLookupRegistrationForMainResource( 132 ServiceWorkerStatusCode status, 133 const scoped_refptr<ServiceWorkerRegistration>& registration) { 134 DCHECK(job_.get()); 135 if (status != SERVICE_WORKER_OK) { 136 job_->FallbackToNetwork(); 137 return; 138 } 139 DCHECK(registration); 140 141 ServiceWorkerMetrics::CountControlledPageLoad(); 142 143 // Initiate activation of a waiting version. 144 // Usually a register job initiates activation but that 145 // doesn't happen if the browser exits prior to activation 146 // having occurred. This check handles that case. 147 if (registration->waiting_version()) 148 registration->ActivateWaitingVersionWhenReady(); 149 150 scoped_refptr<ServiceWorkerVersion> active_version = 151 registration->active_version(); 152 153 // Wait until it's activated before firing fetch events. 154 if (active_version && 155 active_version->status() == ServiceWorkerVersion::ACTIVATING) { 156 registration->active_version()->RegisterStatusChangeCallback( 157 base::Bind(&self::OnVersionStatusChanged, 158 weak_factory_.GetWeakPtr(), 159 registration, 160 active_version)); 161 return; 162 } 163 164 if (!active_version || 165 active_version->status() != ServiceWorkerVersion::ACTIVATED) { 166 job_->FallbackToNetwork(); 167 return; 168 } 169 170 provider_host_->SetControllerVersion(registration->active_version()); 171 provider_host_->SetActiveVersion(registration->active_version()); 172 provider_host_->SetWaitingVersion(registration->waiting_version()); 173 provider_host_->SetInstallingVersion(registration->installing_version()); 174 175 job_->ForwardToServiceWorker(); 176} 177 178void ServiceWorkerControlleeRequestHandler::OnVersionStatusChanged( 179 ServiceWorkerRegistration* registration, 180 ServiceWorkerVersion* version) { 181 if (version != registration->active_version() || 182 version->status() != ServiceWorkerVersion::ACTIVATED) { 183 job_->FallbackToNetwork(); 184 return; 185 } 186 provider_host_->SetControllerVersion(registration->active_version()); 187 provider_host_->SetActiveVersion(registration->active_version()); 188 provider_host_->SetWaitingVersion(registration->waiting_version()); 189 provider_host_->SetInstallingVersion(registration->installing_version()); 190 191 job_->ForwardToServiceWorker(); 192} 193 194void ServiceWorkerControlleeRequestHandler::PrepareForSubResource() { 195 DCHECK(job_.get()); 196 DCHECK(context_); 197 DCHECK(provider_host_->active_version()); 198 job_->ForwardToServiceWorker(); 199} 200 201} // namespace content 202