service_worker_controllee_request_handler.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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/resource_request_body.h" 14#include "content/common/service_worker/service_worker_types.h" 15#include "net/base/load_flags.h" 16#include "net/base/net_util.h" 17#include "net/url_request/url_request.h" 18 19namespace content { 20 21ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler( 22 base::WeakPtr<ServiceWorkerContextCore> context, 23 base::WeakPtr<ServiceWorkerProviderHost> provider_host, 24 base::WeakPtr<storage::BlobStorageContext> blob_storage_context, 25 ResourceType resource_type, 26 scoped_refptr<ResourceRequestBody> body) 27 : ServiceWorkerRequestHandler(context, 28 provider_host, 29 blob_storage_context, 30 resource_type), 31 is_main_resource_load_( 32 ServiceWorkerUtils::IsMainResourceType(resource_type)), 33 body_(body), 34 weak_factory_(this) { 35} 36 37ServiceWorkerControlleeRequestHandler:: 38 ~ServiceWorkerControlleeRequestHandler() { 39 // Navigation triggers an update to occur shortly after the page and 40 // its initial subresources load. 41 if (provider_host_ && provider_host_->active_version()) { 42 if (is_main_resource_load_) 43 provider_host_->active_version()->ScheduleUpdate(); 44 else 45 provider_host_->active_version()->DeferScheduledUpdate(); 46 } 47} 48 49net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob( 50 net::URLRequest* request, 51 net::NetworkDelegate* network_delegate) { 52 if (!context_ || !provider_host_) { 53 // We can't do anything other than to fall back to network. 54 job_ = NULL; 55 return NULL; 56 } 57 58 if (request->load_flags() & net::LOAD_BYPASS_CACHE) { 59 if (is_main_resource_load_) { 60 provider_host_->SetDocumentUrl( 61 net::SimplifyUrlForRequest(request->url())); 62 } 63 job_ = NULL; 64 return NULL; 65 } 66 67 // This may get called multiple times for original and redirect requests: 68 // A. original request case: job_ is null, no previous location info. 69 // B. redirect or restarted request case: 70 // a) job_ is non-null if the previous location was forwarded to SW. 71 // b) job_ is null if the previous location was fallback. 72 // c) job_ is non-null if additional restart was required to fall back. 73 74 // We've come here by restart, we already have original request and it 75 // tells we should fallback to network. (Case B-c) 76 if (job_.get() && job_->ShouldFallbackToNetwork()) { 77 job_ = NULL; 78 return NULL; 79 } 80 81 // It's for original request (A) or redirect case (B-a or B-b). 82 DCHECK(!job_.get() || job_->ShouldForwardToServiceWorker()); 83 84 job_ = new ServiceWorkerURLRequestJob( 85 request, network_delegate, provider_host_, blob_storage_context_, body_); 86 if (is_main_resource_load_) 87 PrepareForMainResource(request->url()); 88 else 89 PrepareForSubResource(); 90 91 if (job_->ShouldFallbackToNetwork()) { 92 // If we know we can fallback to network at this point (in case 93 // the storage lookup returned immediately), just return NULL here to 94 // fallback to network. 95 job_ = NULL; 96 return NULL; 97 } 98 99 return job_.get(); 100} 101 102void ServiceWorkerControlleeRequestHandler::GetExtraResponseInfo( 103 bool* was_fetched_via_service_worker, 104 GURL* original_url_via_service_worker) const { 105 if (!job_) { 106 *was_fetched_via_service_worker = false; 107 *original_url_via_service_worker = GURL(); 108 return; 109 } 110 job_->GetExtraResponseInfo(was_fetched_via_service_worker, 111 original_url_via_service_worker); 112} 113 114void ServiceWorkerControlleeRequestHandler::PrepareForMainResource( 115 const GURL& url) { 116 DCHECK(job_.get()); 117 DCHECK(context_); 118 // The corresponding provider_host may already have associated a registration 119 // in redirect case, unassociate it now. 120 provider_host_->UnassociateRegistration(); 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_->AssociateRegistration(registration); 171 job_->ForwardToServiceWorker(); 172} 173 174void ServiceWorkerControlleeRequestHandler::OnVersionStatusChanged( 175 ServiceWorkerRegistration* registration, 176 ServiceWorkerVersion* version) { 177 if (version != registration->active_version() || 178 version->status() != ServiceWorkerVersion::ACTIVATED) { 179 job_->FallbackToNetwork(); 180 return; 181 } 182 183 provider_host_->AssociateRegistration(registration); 184 job_->ForwardToServiceWorker(); 185} 186 187void ServiceWorkerControlleeRequestHandler::PrepareForSubResource() { 188 DCHECK(job_.get()); 189 DCHECK(context_); 190 DCHECK(provider_host_->active_version()); 191 job_->ForwardToServiceWorker(); 192} 193 194} // namespace content 195