service_worker_read_from_cache_job.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/service_worker/service_worker_read_from_cache_job.h"
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/service_worker/service_worker_context_core.h"
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/browser/service_worker/service_worker_disk_cache.h"
9a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "content/browser/service_worker/service_worker_histograms.h"
10a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "net/base/io_buffer.h"
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "net/base/net_errors.h"
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/http/http_request_headers.h"
1346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "net/http/http_response_headers.h"
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/http/http_util.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/url_request/url_request.h"
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/url_request/url_request_status.h"
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace content {
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ServiceWorkerReadFromCacheJob::ServiceWorkerReadFromCacheJob(
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    net::URLRequest* request,
22a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    net::NetworkDelegate* network_delegate,
23a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    base::WeakPtr<ServiceWorkerContextCore> context,
24a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    int64 response_id)
25a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    : net::URLRequestJob(request, network_delegate),
26a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      context_(context),
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      response_id_(response_id),
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      has_been_killed_(false),
2946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      weak_factory_(this) {
3046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
3146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)ServiceWorkerReadFromCacheJob::~ServiceWorkerReadFromCacheJob() {
3346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
3446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ServiceWorkerReadFromCacheJob::Start() {
3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!context_) {
3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    NotifyStartError(net::URLRequestStatus(
3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        net::URLRequestStatus::FAILED, net::ERR_FAILED));
3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Create a response reader and start reading the headers,
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // we'll continue when thats done.
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  reader_ = context_->storage()->CreateResponseReader(response_id_);
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  http_info_io_buffer_ = new HttpResponseInfoIOBuffer;
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  reader_->ReadInfo(
47      http_info_io_buffer_,
48      base::Bind(&ServiceWorkerReadFromCacheJob::OnReadInfoComplete,
49                 weak_factory_.GetWeakPtr()));
50  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
51}
52
53void ServiceWorkerReadFromCacheJob::Kill() {
54  if (has_been_killed_)
55    return;
56  weak_factory_.InvalidateWeakPtrs();
57  has_been_killed_ = true;
58  reader_.reset();
59  context_.reset();
60  http_info_io_buffer_ = NULL;
61  http_info_.reset();
62  range_response_info_.reset();
63  net::URLRequestJob::Kill();
64}
65
66net::LoadState ServiceWorkerReadFromCacheJob::GetLoadState() const {
67  if (reader_.get() && reader_->IsReadPending())
68    return net::LOAD_STATE_READING_RESPONSE;
69  return net::LOAD_STATE_IDLE;
70}
71
72bool ServiceWorkerReadFromCacheJob::GetCharset(std::string* charset) {
73  if (!http_info())
74    return false;
75  return http_info()->headers->GetCharset(charset);
76}
77
78bool ServiceWorkerReadFromCacheJob::GetMimeType(std::string* mime_type) const {
79  if (!http_info())
80    return false;
81  return http_info()->headers->GetMimeType(mime_type);
82}
83
84void ServiceWorkerReadFromCacheJob::GetResponseInfo(
85    net::HttpResponseInfo* info) {
86  if (!http_info())
87    return;
88  *info = *http_info();
89}
90
91int ServiceWorkerReadFromCacheJob::GetResponseCode() const {
92  if (!http_info())
93    return -1;
94  return http_info()->headers->response_code();
95}
96
97void ServiceWorkerReadFromCacheJob::SetExtraRequestHeaders(
98      const net::HttpRequestHeaders& headers) {
99  std::string value;
100  std::vector<net::HttpByteRange> ranges;
101  if (!headers.GetHeader(net::HttpRequestHeaders::kRange, &value) ||
102      !net::HttpUtil::ParseRangeHeader(value, &ranges)) {
103    return;
104  }
105
106  // If multiple ranges are requested, we play dumb and
107  // return the entire response with 200 OK.
108  if (ranges.size() == 1U)
109    range_requested_ = ranges[0];
110}
111
112bool ServiceWorkerReadFromCacheJob::ReadRawData(
113    net::IOBuffer* buf,
114    int buf_size,
115    int *bytes_read) {
116  DCHECK_NE(buf_size, 0);
117  DCHECK(bytes_read);
118  DCHECK(!reader_->IsReadPending());
119  reader_->ReadData(
120      buf, buf_size, base::Bind(&ServiceWorkerReadFromCacheJob::OnReadComplete,
121                                weak_factory_.GetWeakPtr()));
122  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
123  return false;
124}
125
126const net::HttpResponseInfo* ServiceWorkerReadFromCacheJob::http_info() const {
127  if (!http_info_)
128    return NULL;
129  if (range_response_info_)
130    return range_response_info_.get();
131  return http_info_.get();
132}
133
134void ServiceWorkerReadFromCacheJob::OnReadInfoComplete(int result) {
135  scoped_refptr<ServiceWorkerReadFromCacheJob> protect(this);
136  if (!http_info_io_buffer_->http_info) {
137    DCHECK(result < 0);
138    ServiceWorkerHistograms::CountReadResponseResult(
139        ServiceWorkerHistograms::READ_HEADERS_ERROR);
140    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
141    return;
142  }
143  DCHECK(result >= 0);
144  SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status
145  http_info_.reset(http_info_io_buffer_->http_info.release());
146  if (is_range_request())
147    SetupRangeResponse(http_info_io_buffer_->response_data_size);
148  http_info_io_buffer_ = NULL;
149  NotifyHeadersComplete();
150}
151
152void ServiceWorkerReadFromCacheJob::SetupRangeResponse(int resource_size) {
153  DCHECK(is_range_request() && http_info_.get() && reader_.get());
154  if (resource_size < 0 || !range_requested_.ComputeBounds(resource_size)) {
155    range_requested_ = net::HttpByteRange();
156    return;
157  }
158
159  DCHECK(range_requested_.IsValid());
160  int offset = static_cast<int>(range_requested_.first_byte_position());
161  int length = static_cast<int>(range_requested_.last_byte_position() -
162                                range_requested_.first_byte_position() + 1);
163
164  // Tell the reader about the range to read.
165  reader_->SetReadRange(offset, length);
166
167  // Make a copy of the full response headers and fix them up
168  // for the range we'll be returning.
169  range_response_info_.reset(new net::HttpResponseInfo(*http_info_));
170  net::HttpResponseHeaders* headers = range_response_info_->headers.get();
171  headers->UpdateWithNewRange(
172      range_requested_, resource_size, true /* replace status line */);
173}
174
175void ServiceWorkerReadFromCacheJob::OnReadComplete(int result) {
176  ServiceWorkerHistograms::ReadResponseResult check_result;
177  if (result == 0) {
178    check_result = ServiceWorkerHistograms::READ_OK;
179    NotifyDone(net::URLRequestStatus());
180  } else if (result < 0) {
181    check_result = ServiceWorkerHistograms::READ_DATA_ERROR;
182    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
183  } else {
184    check_result = ServiceWorkerHistograms::READ_OK;
185    SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status
186  }
187  ServiceWorkerHistograms::CountReadResponseResult(check_result);
188  NotifyReadComplete(result);
189}
190
191}  // namespace content
192