Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_controllee_request_handler.cc
blobac27aa3a859b33e3ba650aa74c08d0dc56a4af87
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 "net/base/load_flags.h"
19 #include "net/base/net_util.h"
20 #include "net/url_request/url_request.h"
22 namespace content {
24 ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler(
25 base::WeakPtr<ServiceWorkerContextCore> context,
26 base::WeakPtr<ServiceWorkerProviderHost> provider_host,
27 base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
28 FetchRequestMode request_mode,
29 FetchCredentialsMode credentials_mode,
30 ResourceType resource_type,
31 RequestContextType request_context_type,
32 RequestContextFrameType frame_type,
33 scoped_refptr<ResourceRequestBody> body)
34 : ServiceWorkerRequestHandler(context,
35 provider_host,
36 blob_storage_context,
37 resource_type),
38 is_main_resource_load_(
39 ServiceWorkerUtils::IsMainResourceType(resource_type)),
40 request_mode_(request_mode),
41 credentials_mode_(credentials_mode),
42 request_context_type_(request_context_type),
43 frame_type_(frame_type),
44 body_(body),
45 weak_factory_(this) {
48 ServiceWorkerControlleeRequestHandler::
49 ~ServiceWorkerControlleeRequestHandler() {
50 // Navigation triggers an update to occur shortly after the page and
51 // its initial subresources load.
52 if (provider_host_ && provider_host_->active_version()) {
53 if (is_main_resource_load_)
54 provider_host_->active_version()->ScheduleUpdate();
55 else
56 provider_host_->active_version()->DeferScheduledUpdate();
59 if (is_main_resource_load_ && provider_host_)
60 provider_host_->SetAllowAssociation(true);
63 net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
64 net::URLRequest* request,
65 net::NetworkDelegate* network_delegate,
66 ResourceContext* resource_context) {
67 if (!context_ || !provider_host_) {
68 // We can't do anything other than to fall back to network.
69 job_ = NULL;
70 return NULL;
73 // This may get called multiple times for original and redirect requests:
74 // A. original request case: job_ is null, no previous location info.
75 // B. redirect or restarted request case:
76 // a) job_ is non-null if the previous location was forwarded to SW.
77 // b) job_ is null if the previous location was fallback.
78 // c) job_ is non-null if additional restart was required to fall back.
80 // We've come here by restart, we already have original request and it
81 // tells we should fallback to network. (Case B-c)
82 if (job_.get() && job_->ShouldFallbackToNetwork()) {
83 job_ = NULL;
84 return NULL;
87 // It's for original request (A) or redirect case (B-a or B-b).
88 DCHECK(!job_.get() || job_->ShouldForwardToServiceWorker());
90 job_ = new ServiceWorkerURLRequestJob(request,
91 network_delegate,
92 provider_host_,
93 blob_storage_context_,
94 resource_context,
95 request_mode_,
96 credentials_mode_,
97 request_context_type_,
98 frame_type_,
99 body_);
100 resource_context_ = resource_context;
102 if (is_main_resource_load_)
103 PrepareForMainResource(request);
104 else
105 PrepareForSubResource();
107 if (job_->ShouldFallbackToNetwork()) {
108 // If we know we can fallback to network at this point (in case
109 // the storage lookup returned immediately), just return NULL here to
110 // fallback to network.
111 job_ = NULL;
112 return NULL;
115 return job_.get();
118 void ServiceWorkerControlleeRequestHandler::GetExtraResponseInfo(
119 bool* was_fetched_via_service_worker,
120 bool* was_fallback_required_by_service_worker,
121 GURL* original_url_via_service_worker,
122 blink::WebServiceWorkerResponseType* response_type_via_service_worker,
123 base::TimeTicks* fetch_start_time,
124 base::TimeTicks* fetch_ready_time,
125 base::TimeTicks* fetch_end_time) const {
126 if (!job_.get()) {
127 *was_fetched_via_service_worker = false;
128 *was_fallback_required_by_service_worker = false;
129 *original_url_via_service_worker = GURL();
130 return;
132 job_->GetExtraResponseInfo(was_fetched_via_service_worker,
133 was_fallback_required_by_service_worker,
134 original_url_via_service_worker,
135 response_type_via_service_worker,
136 fetch_start_time,
137 fetch_ready_time,
138 fetch_end_time);
141 void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
142 const net::URLRequest* request) {
143 DCHECK(job_.get());
144 DCHECK(context_);
145 DCHECK(provider_host_);
146 TRACE_EVENT_ASYNC_BEGIN1(
147 "ServiceWorker",
148 "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
149 job_.get(),
150 "URL", request->url().spec());
151 // The corresponding provider_host may already have associated a registration
152 // in redirect case, unassociate it now.
153 provider_host_->DisassociateRegistration();
155 // Also prevent a registrater job for establishing an association to a new
156 // registration while we're finding an existing registration.
157 provider_host_->SetAllowAssociation(false);
159 stripped_url_ = net::SimplifyUrlForRequest(request->url());
160 provider_host_->SetDocumentUrl(stripped_url_);
161 provider_host_->SetTopmostFrameUrl(request->first_party_for_cookies());
162 context_->storage()->FindRegistrationForDocument(
163 stripped_url_, base::Bind(&self::DidLookupRegistrationForMainResource,
164 weak_factory_.GetWeakPtr()));
167 void
168 ServiceWorkerControlleeRequestHandler::DidLookupRegistrationForMainResource(
169 ServiceWorkerStatusCode status,
170 const scoped_refptr<ServiceWorkerRegistration>& registration) {
171 DCHECK(job_.get());
172 if (provider_host_)
173 provider_host_->SetAllowAssociation(true);
174 if (status != SERVICE_WORKER_OK || !provider_host_) {
175 job_->FallbackToNetwork();
176 TRACE_EVENT_ASYNC_END1(
177 "ServiceWorker",
178 "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
179 job_.get(),
180 "Status", status);
181 return;
183 DCHECK(registration.get());
185 if (!GetContentClient()->browser()->AllowServiceWorker(
186 registration->pattern(),
187 provider_host_->topmost_frame_url(),
188 resource_context_)) {
189 job_->FallbackToNetwork();
190 TRACE_EVENT_ASYNC_END2(
191 "ServiceWorker",
192 "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
193 job_.get(),
194 "Status", status,
195 "Info", "ServiceWorker is blocked");
196 return;
199 // Initiate activation of a waiting version.
200 // Usually a register job initiates activation but that
201 // doesn't happen if the browser exits prior to activation
202 // having occurred. This check handles that case.
203 if (registration->waiting_version())
204 registration->ActivateWaitingVersionWhenReady();
206 scoped_refptr<ServiceWorkerVersion> active_version =
207 registration->active_version();
209 // Wait until it's activated before firing fetch events.
210 if (active_version.get() &&
211 active_version->status() == ServiceWorkerVersion::ACTIVATING) {
212 provider_host_->SetAllowAssociation(false);
213 registration->active_version()->RegisterStatusChangeCallback(
214 base::Bind(&self::OnVersionStatusChanged,
215 weak_factory_.GetWeakPtr(),
216 registration,
217 active_version));
218 TRACE_EVENT_ASYNC_END2(
219 "ServiceWorker",
220 "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
221 job_.get(),
222 "Status", status,
223 "Info", "Wait until finished SW activation");
224 return;
227 if (!active_version.get() ||
228 active_version->status() != ServiceWorkerVersion::ACTIVATED) {
229 job_->FallbackToNetwork();
230 TRACE_EVENT_ASYNC_END2(
231 "ServiceWorker",
232 "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
233 job_.get(),
234 "Status", status,
235 "Info",
236 "ServiceWorkerVersion is not available, so falling back to network");
237 return;
240 ServiceWorkerMetrics::CountControlledPageLoad(stripped_url_);
242 provider_host_->AssociateRegistration(registration.get(),
243 false /* notify_controllerchange */);
244 job_->ForwardToServiceWorker();
245 TRACE_EVENT_ASYNC_END2(
246 "ServiceWorker",
247 "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
248 job_.get(),
249 "Status", status,
250 "Info",
251 "Forwarded to the ServiceWorker");
254 void ServiceWorkerControlleeRequestHandler::OnVersionStatusChanged(
255 ServiceWorkerRegistration* registration,
256 ServiceWorkerVersion* version) {
257 if (provider_host_)
258 provider_host_->SetAllowAssociation(true);
259 if (version != registration->active_version() ||
260 version->status() != ServiceWorkerVersion::ACTIVATED ||
261 !provider_host_) {
262 job_->FallbackToNetwork();
263 return;
266 ServiceWorkerMetrics::CountControlledPageLoad(stripped_url_);
268 provider_host_->AssociateRegistration(registration,
269 false /* notify_controllerchange */);
270 job_->ForwardToServiceWorker();
273 void ServiceWorkerControlleeRequestHandler::PrepareForSubResource() {
274 DCHECK(job_.get());
275 DCHECK(context_);
276 DCHECK(provider_host_->active_version());
277 job_->ForwardToServiceWorker();
280 } // namespace content