Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_controllee_request_handler.cc
blob1f383d73ee5a8b89ffef2d00cfc045b34ea29e4c
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 "base/trace_event/trace_event.h"
8 #include "content/browser/service_worker/service_worker_context_core.h"
9 #include "content/browser/service_worker/service_worker_metrics.h"
10 #include "content/browser/service_worker/service_worker_provider_host.h"
11 #include "content/browser/service_worker/service_worker_registration.h"
12 #include "content/browser/service_worker/service_worker_url_request_job.h"
13 #include "content/browser/service_worker/service_worker_utils.h"
14 #include "content/common/resource_request_body.h"
15 #include "content/common/service_worker/service_worker_types.h"
16 #include "content/public/browser/content_browser_client.h"
17 #include "content/public/common/content_client.h"
18 #include "content/public/common/resource_response_info.h"
19 #include "net/base/load_flags.h"
20 #include "net/base/net_util.h"
21 #include "net/url_request/url_request.h"
23 namespace content {
25 ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler(
26 base::WeakPtr<ServiceWorkerContextCore> context,
27 base::WeakPtr<ServiceWorkerProviderHost> provider_host,
28 base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
29 FetchRequestMode request_mode,
30 FetchCredentialsMode credentials_mode,
31 ResourceType resource_type,
32 RequestContextType request_context_type,
33 RequestContextFrameType frame_type,
34 scoped_refptr<ResourceRequestBody> body)
35 : ServiceWorkerRequestHandler(context,
36 provider_host,
37 blob_storage_context,
38 resource_type),
39 is_main_resource_load_(
40 ServiceWorkerUtils::IsMainResourceType(resource_type)),
41 request_mode_(request_mode),
42 credentials_mode_(credentials_mode),
43 request_context_type_(request_context_type),
44 frame_type_(frame_type),
45 body_(body),
46 weak_factory_(this) {
49 ServiceWorkerControlleeRequestHandler::
50 ~ServiceWorkerControlleeRequestHandler() {
51 // Navigation triggers an update to occur shortly after the page and
52 // its initial subresources load.
53 if (provider_host_ && provider_host_->active_version()) {
54 if (is_main_resource_load_)
55 provider_host_->active_version()->ScheduleUpdate();
56 else
57 provider_host_->active_version()->DeferScheduledUpdate();
60 if (is_main_resource_load_ && provider_host_)
61 provider_host_->SetAllowAssociation(true);
64 net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
65 net::URLRequest* request,
66 net::NetworkDelegate* network_delegate,
67 ResourceContext* resource_context) {
68 if (job_.get() && worker_start_time_.is_null()) {
69 // Save worker timings of the first job.
70 worker_start_time_ = job_->worker_start_time();
71 worker_ready_time_ = job_->worker_ready_time();
74 if (!context_ || !provider_host_) {
75 // We can't do anything other than to fall back to network.
76 job_ = NULL;
77 return NULL;
80 // This may get called multiple times for original and redirect requests:
81 // A. original request case: job_ is null, no previous location info.
82 // B. redirect or restarted request case:
83 // a) job_ is non-null if the previous location was forwarded to SW.
84 // b) job_ is null if the previous location was fallback.
85 // c) job_ is non-null if additional restart was required to fall back.
87 // We've come here by restart, we already have original request and it
88 // tells we should fallback to network. (Case B-c)
89 if (job_.get() && job_->ShouldFallbackToNetwork()) {
90 job_ = NULL;
91 return NULL;
94 // It's for original request (A) or redirect case (B-a or B-b).
95 DCHECK(!job_.get() || job_->ShouldForwardToServiceWorker());
97 job_ = new ServiceWorkerURLRequestJob(
98 request, network_delegate, provider_host_, blob_storage_context_,
99 resource_context, request_mode_, credentials_mode_,
100 is_main_resource_load_, request_context_type_, frame_type_, body_);
101 resource_context_ = resource_context;
103 if (is_main_resource_load_)
104 PrepareForMainResource(request);
105 else
106 PrepareForSubResource();
108 if (job_->ShouldFallbackToNetwork()) {
109 // If we know we can fallback to network at this point (in case
110 // the storage lookup returned immediately), just return NULL here to
111 // fallback to network.
112 job_ = NULL;
113 return NULL;
116 return job_.get();
119 void ServiceWorkerControlleeRequestHandler::GetExtraResponseInfo(
120 ResourceResponseInfo* response_info) const {
121 if (!job_.get()) {
122 response_info->was_fetched_via_service_worker = false;
123 response_info->was_fallback_required_by_service_worker = false;
124 response_info->original_url_via_service_worker = GURL();
125 response_info->service_worker_start_time = worker_start_time_;
126 response_info->service_worker_ready_time = worker_ready_time_;
127 return;
129 job_->GetExtraResponseInfo(response_info);
130 if (!worker_start_time_.is_null()) {
131 // If we have worker timings from previous job, use it.
132 response_info->service_worker_start_time = worker_start_time_;
133 response_info->service_worker_ready_time = worker_ready_time_;
137 void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
138 const net::URLRequest* request) {
139 DCHECK(job_.get());
140 DCHECK(context_);
141 DCHECK(provider_host_);
142 TRACE_EVENT_ASYNC_BEGIN1(
143 "ServiceWorker",
144 "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
145 job_.get(),
146 "URL", request->url().spec());
147 // The corresponding provider_host may already have associated a registration
148 // in redirect case, unassociate it now.
149 provider_host_->DisassociateRegistration();
151 // Also prevent a registrater job for establishing an association to a new
152 // registration while we're finding an existing registration.
153 provider_host_->SetAllowAssociation(false);
155 stripped_url_ = net::SimplifyUrlForRequest(request->url());
156 provider_host_->SetDocumentUrl(stripped_url_);
157 provider_host_->SetTopmostFrameUrl(request->first_party_for_cookies());
158 context_->storage()->FindRegistrationForDocument(
159 stripped_url_, base::Bind(&self::DidLookupRegistrationForMainResource,
160 weak_factory_.GetWeakPtr()));
163 void
164 ServiceWorkerControlleeRequestHandler::DidLookupRegistrationForMainResource(
165 ServiceWorkerStatusCode status,
166 const scoped_refptr<ServiceWorkerRegistration>& registration) {
167 DCHECK(job_.get());
168 if (provider_host_)
169 provider_host_->SetAllowAssociation(true);
170 if (status != SERVICE_WORKER_OK || !provider_host_) {
171 job_->FallbackToNetwork();
172 TRACE_EVENT_ASYNC_END1(
173 "ServiceWorker",
174 "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
175 job_.get(),
176 "Status", status);
177 return;
179 DCHECK(registration.get());
181 if (!GetContentClient()->browser()->AllowServiceWorker(
182 registration->pattern(), provider_host_->topmost_frame_url(),
183 resource_context_, provider_host_->process_id(),
184 provider_host_->frame_id())) {
185 job_->FallbackToNetwork();
186 TRACE_EVENT_ASYNC_END2(
187 "ServiceWorker",
188 "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
189 job_.get(),
190 "Status", status,
191 "Info", "ServiceWorker is blocked");
192 return;
195 // Initiate activation of a waiting version.
196 // Usually a register job initiates activation but that
197 // doesn't happen if the browser exits prior to activation
198 // having occurred. This check handles that case.
199 if (registration->waiting_version())
200 registration->ActivateWaitingVersionWhenReady();
202 scoped_refptr<ServiceWorkerVersion> active_version =
203 registration->active_version();
205 // Wait until it's activated before firing fetch events.
206 if (active_version.get() &&
207 active_version->status() == ServiceWorkerVersion::ACTIVATING) {
208 provider_host_->SetAllowAssociation(false);
209 registration->active_version()->RegisterStatusChangeCallback(
210 base::Bind(&self::OnVersionStatusChanged,
211 weak_factory_.GetWeakPtr(),
212 registration,
213 active_version));
214 TRACE_EVENT_ASYNC_END2(
215 "ServiceWorker",
216 "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
217 job_.get(),
218 "Status", status,
219 "Info", "Wait until finished SW activation");
220 return;
223 if (!active_version.get() ||
224 active_version->status() != ServiceWorkerVersion::ACTIVATED) {
225 job_->FallbackToNetwork();
226 TRACE_EVENT_ASYNC_END2(
227 "ServiceWorker",
228 "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
229 job_.get(),
230 "Status", status,
231 "Info",
232 "ServiceWorkerVersion is not available, so falling back to network");
233 return;
236 ServiceWorkerMetrics::CountControlledPageLoad(stripped_url_);
238 provider_host_->AssociateRegistration(registration.get(),
239 false /* notify_controllerchange */);
240 job_->ForwardToServiceWorker();
241 TRACE_EVENT_ASYNC_END2(
242 "ServiceWorker",
243 "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
244 job_.get(),
245 "Status", status,
246 "Info",
247 "Forwarded to the ServiceWorker");
250 void ServiceWorkerControlleeRequestHandler::OnVersionStatusChanged(
251 ServiceWorkerRegistration* registration,
252 ServiceWorkerVersion* version) {
253 if (provider_host_)
254 provider_host_->SetAllowAssociation(true);
255 if (version != registration->active_version() ||
256 version->status() != ServiceWorkerVersion::ACTIVATED ||
257 !provider_host_) {
258 job_->FallbackToNetwork();
259 return;
262 ServiceWorkerMetrics::CountControlledPageLoad(stripped_url_);
264 provider_host_->AssociateRegistration(registration,
265 false /* notify_controllerchange */);
266 job_->ForwardToServiceWorker();
269 void ServiceWorkerControlleeRequestHandler::PrepareForSubResource() {
270 DCHECK(job_.get());
271 DCHECK(context_);
272 DCHECK(provider_host_->active_version());
273 job_->ForwardToServiceWorker();
276 } // namespace content