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_url_request_job.h"
8 #include "base/strings/stringprintf.h"
9 #include "content/browser/service_worker/service_worker_fetch_dispatcher.h"
10 #include "content/browser/service_worker/service_worker_provider_host.h"
11 #include "net/http/http_request_headers.h"
12 #include "net/http/http_response_headers.h"
13 #include "net/http/http_response_info.h"
14 #include "net/http/http_util.h"
18 ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob(
19 net::URLRequest
* request
,
20 net::NetworkDelegate
* network_delegate
,
21 base::WeakPtr
<ServiceWorkerProviderHost
> provider_host
)
22 : net::URLRequestJob(request
, network_delegate
),
23 provider_host_(provider_host
),
24 response_type_(NOT_DETERMINED
),
29 void ServiceWorkerURLRequestJob::FallbackToNetwork() {
30 DCHECK_EQ(NOT_DETERMINED
, response_type_
);
31 response_type_
= FALLBACK_TO_NETWORK
;
35 void ServiceWorkerURLRequestJob::ForwardToServiceWorker() {
36 DCHECK_EQ(NOT_DETERMINED
, response_type_
);
37 response_type_
= FORWARD_TO_SERVICE_WORKER
;
41 void ServiceWorkerURLRequestJob::Start() {
46 void ServiceWorkerURLRequestJob::Kill() {
47 net::URLRequestJob::Kill();
48 fetch_dispatcher_
.reset();
49 weak_factory_
.InvalidateWeakPtrs();
52 net::LoadState
ServiceWorkerURLRequestJob::GetLoadState() const {
53 // TODO(kinuko): refine this for better debug.
54 return net::URLRequestJob::GetLoadState();
57 bool ServiceWorkerURLRequestJob::GetCharset(std::string
* charset
) {
60 return http_info()->headers
->GetCharset(charset
);
63 bool ServiceWorkerURLRequestJob::GetMimeType(std::string
* mime_type
) const {
66 return http_info()->headers
->GetMimeType(mime_type
);
69 void ServiceWorkerURLRequestJob::GetResponseInfo(net::HttpResponseInfo
* info
) {
75 int ServiceWorkerURLRequestJob::GetResponseCode() const {
78 return http_info()->headers
->response_code();
81 void ServiceWorkerURLRequestJob::SetExtraRequestHeaders(
82 const net::HttpRequestHeaders
& headers
) {
83 std::string range_header
;
84 std::vector
<net::HttpByteRange
> ranges
;
85 if (!headers
.GetHeader(net::HttpRequestHeaders::kRange
, &range_header
) ||
86 !net::HttpUtil::ParseRangeHeader(range_header
, &ranges
)) {
90 // We don't support multiple range requests in one single URL request.
91 if (ranges
.size() == 1U)
92 byte_range_
= ranges
[0];
95 bool ServiceWorkerURLRequestJob::ReadRawData(
96 net::IOBuffer
* buf
, int buf_size
, int *bytes_read
) {
97 // TODO(kinuko): Implement this.
98 // If the response returned from ServiceWorker had an
99 // identifier to on-disk data (e.g. blob or cache entry) we'll need to
100 // pull the body from disk.
106 const net::HttpResponseInfo
* ServiceWorkerURLRequestJob::http_info() const {
107 if (!http_response_info_
)
109 if (range_response_info_
)
110 return range_response_info_
.get();
111 return http_response_info_
.get();
114 ServiceWorkerURLRequestJob::~ServiceWorkerURLRequestJob() {
117 void ServiceWorkerURLRequestJob::MaybeStartRequest() {
118 if (is_started_
&& response_type_
!= NOT_DETERMINED
) {
119 // Start asynchronously.
120 base::MessageLoop::current()->PostTask(
122 base::Bind(&ServiceWorkerURLRequestJob::StartRequest
,
123 weak_factory_
.GetWeakPtr()));
127 void ServiceWorkerURLRequestJob::StartRequest() {
128 switch (response_type_
) {
133 case FALLBACK_TO_NETWORK
:
134 // Restart the request to create a new job. Our request handler will
135 // return NULL, and the default job (which will hit network) should be
137 NotifyRestartRequired();
140 case FORWARD_TO_SERVICE_WORKER
:
141 DCHECK(provider_host_
&& provider_host_
->active_version());
142 DCHECK(!fetch_dispatcher_
);
144 // Send a fetch event to the ServiceWorker associated to the
146 fetch_dispatcher_
.reset(new ServiceWorkerFetchDispatcher(
147 request(), provider_host_
->active_version(),
148 base::Bind(&ServiceWorkerURLRequestJob::DidDispatchFetchEvent
,
149 weak_factory_
.GetWeakPtr())));
150 fetch_dispatcher_
->Run();
157 void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
158 ServiceWorkerStatusCode status
,
159 ServiceWorkerFetchEventResult fetch_result
,
160 const ServiceWorkerResponse
& response
) {
161 fetch_dispatcher_
.reset();
163 // Check if we're not orphaned.
167 if (status
!= SERVICE_WORKER_OK
) {
168 // Dispatching event has been failed, falling back to the network.
169 // (Tentative behavior described on github)
170 // TODO(kinuko): consider returning error if we've come here because
171 // unexpected worker termination etc (so that we could fix bugs).
172 // TODO(kinuko): Would be nice to log the error case.
173 response_type_
= FALLBACK_TO_NETWORK
;
174 NotifyRestartRequired();
177 if (fetch_result
== SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
) {
178 // Change the response type and restart the request to fallback to
180 response_type_
= FALLBACK_TO_NETWORK
;
181 NotifyRestartRequired();
185 // We should have response now.
186 DCHECK_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE
, fetch_result
);
188 CreateResponseHeader(response
);
189 NotifyHeadersComplete();
192 void ServiceWorkerURLRequestJob::CreateResponseHeader(
193 const ServiceWorkerResponse
& response
) {
194 // TODO(kinuko): If the response has an identifier to on-disk cache entry,
195 // pull response header from the disk.
196 std::string
status_line(base::StringPrintf("HTTP/1.1 %d %s",
197 response
.status_code
,
198 response
.status_text
.c_str()));
199 status_line
.push_back('\0');
200 scoped_refptr
<net::HttpResponseHeaders
> headers(
201 new net::HttpResponseHeaders(status_line
));
202 for (std::map
<std::string
, std::string
>::const_iterator it
=
203 response
.headers
.begin();
204 it
!= response
.headers
.end(); ++it
) {
206 header
.reserve(it
->first
.size() + 2 + it
->second
.size());
207 header
.append(it
->first
);
209 header
.append(it
->second
);
210 headers
->AddHeader(header
);
213 http_response_info_
.reset(new net::HttpResponseInfo());
214 http_response_info_
->headers
= headers
;
217 } // namespace content