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.
5 #include "content/browser/service_worker/service_worker_controllee_request_handler.h"
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"
21 ServiceWorkerControlleeRequestHandler::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
,
31 is_main_resource_load_(
32 ServiceWorkerUtils::IsMainResourceType(resource_type
)),
37 ServiceWorkerControlleeRequestHandler::
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();
45 provider_host_
->active_version()->DeferScheduledUpdate();
49 net::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.
58 if (request
->load_flags() & net::LOAD_BYPASS_CACHE
) {
59 if (is_main_resource_load_
) {
60 provider_host_
->SetDocumentUrl(
61 net::SimplifyUrlForRequest(request
->url()));
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.
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()) {
81 // It's for original request (A) or redirect case (B-a or B-b).
82 DCHECK(!job_
.get() || job_
->ShouldForwardToServiceWorker());
84 job_
= new ServiceWorkerURLRequestJob(
85 request
, network_delegate
, provider_host_
, blob_storage_context_
, body_
);
86 if (is_main_resource_load_
)
87 PrepareForMainResource(request
->url());
89 PrepareForSubResource();
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.
102 void ServiceWorkerControlleeRequestHandler::GetExtraResponseInfo(
103 bool* was_fetched_via_service_worker
,
104 GURL
* original_url_via_service_worker
) const {
106 *was_fetched_via_service_worker
= false;
107 *original_url_via_service_worker
= GURL();
110 job_
->GetExtraResponseInfo(was_fetched_via_service_worker
,
111 original_url_via_service_worker
);
114 void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
118 // The corresponding provider_host may already have associated a registration
119 // in redirect case, unassociate it now.
120 provider_host_
->UnassociateRegistration();
122 GURL stripped_url
= net::SimplifyUrlForRequest(url
);
123 provider_host_
->SetDocumentUrl(stripped_url
);
124 context_
->storage()->FindRegistrationForDocument(
126 base::Bind(&self::DidLookupRegistrationForMainResource
,
127 weak_factory_
.GetWeakPtr()));
131 ServiceWorkerControlleeRequestHandler::DidLookupRegistrationForMainResource(
132 ServiceWorkerStatusCode status
,
133 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
135 if (status
!= SERVICE_WORKER_OK
) {
136 job_
->FallbackToNetwork();
139 DCHECK(registration
.get());
141 ServiceWorkerMetrics::CountControlledPageLoad();
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();
150 scoped_refptr
<ServiceWorkerVersion
> active_version
=
151 registration
->active_version();
153 // Wait until it's activated before firing fetch events.
154 if (active_version
.get() &&
155 active_version
->status() == ServiceWorkerVersion::ACTIVATING
) {
156 registration
->active_version()->RegisterStatusChangeCallback(
157 base::Bind(&self::OnVersionStatusChanged
,
158 weak_factory_
.GetWeakPtr(),
164 if (!active_version
.get() ||
165 active_version
->status() != ServiceWorkerVersion::ACTIVATED
) {
166 job_
->FallbackToNetwork();
170 provider_host_
->AssociateRegistration(registration
.get());
171 job_
->ForwardToServiceWorker();
174 void ServiceWorkerControlleeRequestHandler::OnVersionStatusChanged(
175 ServiceWorkerRegistration
* registration
,
176 ServiceWorkerVersion
* version
) {
177 if (version
!= registration
->active_version() ||
178 version
->status() != ServiceWorkerVersion::ACTIVATED
) {
179 job_
->FallbackToNetwork();
183 provider_host_
->AssociateRegistration(registration
);
184 job_
->ForwardToServiceWorker();
187 void ServiceWorkerControlleeRequestHandler::PrepareForSubResource() {
190 DCHECK(provider_host_
->active_version());
191 job_
->ForwardToServiceWorker();
194 } // namespace content