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