service_worker_read_from_cache_job.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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_read_from_cache_job.h"
6
7#include "content/browser/service_worker/service_worker_context_core.h"
8#include "content/browser/service_worker/service_worker_disk_cache.h"
9#include "net/base/io_buffer.h"
10#include "net/base/net_errors.h"
11#include "net/http/http_request_headers.h"
12#include "net/http/http_response_headers.h"
13#include "net/http/http_util.h"
14#include "net/url_request/url_request.h"
15#include "net/url_request/url_request_status.h"
16
17namespace content {
18
19ServiceWorkerReadFromCacheJob::ServiceWorkerReadFromCacheJob(
20    net::URLRequest* request,
21    net::NetworkDelegate* network_delegate,
22    base::WeakPtr<ServiceWorkerContextCore> context,
23    int64 response_id)
24    : net::URLRequestJob(request, network_delegate),
25      context_(context),
26      response_id_(response_id),
27      has_been_killed_(false),
28      weak_factory_(this) {
29}
30
31ServiceWorkerReadFromCacheJob::~ServiceWorkerReadFromCacheJob() {
32}
33
34void ServiceWorkerReadFromCacheJob::Start() {
35  if (!context_) {
36    NotifyStartError(net::URLRequestStatus(
37        net::URLRequestStatus::FAILED, net::ERR_FAILED));
38    return;
39  }
40
41  // Create a response reader and start reading the headers,
42  // we'll continue when thats done.
43  reader_ = context_->storage()->CreateResponseReader(response_id_);
44  http_info_io_buffer_ = new HttpResponseInfoIOBuffer;
45  reader_->ReadInfo(
46      http_info_io_buffer_,
47      base::Bind(&ServiceWorkerReadFromCacheJob::OnReadInfoComplete,
48                 weak_factory_.GetWeakPtr()));
49  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
50}
51
52void ServiceWorkerReadFromCacheJob::Kill() {
53  if (has_been_killed_)
54    return;
55  weak_factory_.InvalidateWeakPtrs();
56  has_been_killed_ = true;
57  reader_.reset();
58  context_.reset();
59  http_info_io_buffer_ = NULL;
60  http_info_.reset();
61  range_response_info_.reset();
62  net::URLRequestJob::Kill();
63}
64
65net::LoadState ServiceWorkerReadFromCacheJob::GetLoadState() const {
66  if (reader_.get() && reader_->IsReadPending())
67    return net::LOAD_STATE_READING_RESPONSE;
68  return net::LOAD_STATE_IDLE;
69}
70
71bool ServiceWorkerReadFromCacheJob::GetCharset(std::string* charset) {
72  if (!http_info())
73    return false;
74  return http_info()->headers->GetCharset(charset);
75}
76
77bool ServiceWorkerReadFromCacheJob::GetMimeType(std::string* mime_type) const {
78  if (!http_info())
79    return false;
80  return http_info()->headers->GetMimeType(mime_type);
81}
82
83void ServiceWorkerReadFromCacheJob::GetResponseInfo(
84    net::HttpResponseInfo* info) {
85  if (!http_info())
86    return;
87  *info = *http_info();
88}
89
90int ServiceWorkerReadFromCacheJob::GetResponseCode() const {
91  if (!http_info())
92    return -1;
93  return http_info()->headers->response_code();
94}
95
96void ServiceWorkerReadFromCacheJob::SetExtraRequestHeaders(
97      const net::HttpRequestHeaders& headers) {
98  std::string value;
99  std::vector<net::HttpByteRange> ranges;
100  if (!headers.GetHeader(net::HttpRequestHeaders::kRange, &value) ||
101      !net::HttpUtil::ParseRangeHeader(value, &ranges)) {
102    return;
103  }
104
105  // If multiple ranges are requested, we play dumb and
106  // return the entire response with 200 OK.
107  if (ranges.size() == 1U)
108    range_requested_ = ranges[0];
109}
110
111bool ServiceWorkerReadFromCacheJob::ReadRawData(
112    net::IOBuffer* buf,
113    int buf_size,
114    int *bytes_read) {
115  DCHECK_NE(buf_size, 0);
116  DCHECK(bytes_read);
117  DCHECK(!reader_->IsReadPending());
118  reader_->ReadData(
119      buf, buf_size, base::Bind(&ServiceWorkerReadFromCacheJob::OnReadComplete,
120                                weak_factory_.GetWeakPtr()));
121  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
122  return false;
123}
124
125const net::HttpResponseInfo* ServiceWorkerReadFromCacheJob::http_info() const {
126  if (!http_info_)
127    return NULL;
128  if (range_response_info_)
129    return range_response_info_.get();
130  return http_info_.get();
131}
132
133void ServiceWorkerReadFromCacheJob::OnReadInfoComplete(int result) {
134  scoped_refptr<ServiceWorkerReadFromCacheJob> protect(this);
135  if (!http_info_io_buffer_->http_info) {
136    DCHECK(result < 0);
137    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
138    return;
139  }
140  DCHECK(result >= 0);
141  SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status
142  http_info_.reset(http_info_io_buffer_->http_info.release());
143  if (is_range_request())
144    SetupRangeResponse(http_info_io_buffer_->response_data_size);
145  http_info_io_buffer_ = NULL;
146  NotifyHeadersComplete();
147}
148
149void ServiceWorkerReadFromCacheJob::SetupRangeResponse(int resource_size) {
150  DCHECK(is_range_request() && http_info_.get() && reader_.get());
151  if (resource_size < 0 || !range_requested_.ComputeBounds(resource_size)) {
152    range_requested_ = net::HttpByteRange();
153    return;
154  }
155
156  DCHECK(range_requested_.IsValid());
157  int offset = static_cast<int>(range_requested_.first_byte_position());
158  int length = static_cast<int>(range_requested_.last_byte_position() -
159                                range_requested_.first_byte_position() + 1);
160
161  // Tell the reader about the range to read.
162  reader_->SetReadRange(offset, length);
163
164  // Make a copy of the full response headers and fix them up
165  // for the range we'll be returning.
166  range_response_info_.reset(new net::HttpResponseInfo(*http_info_));
167  net::HttpResponseHeaders* headers = range_response_info_->headers.get();
168  headers->UpdateWithNewRange(
169      range_requested_, resource_size, true /* replace status line */);
170}
171
172void ServiceWorkerReadFromCacheJob::OnReadComplete(int result) {
173  if (result == 0)
174    NotifyDone(net::URLRequestStatus());
175  else if (result < 0)
176    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
177  else
178    SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status
179  NotifyReadComplete(result);
180}
181
182}  // namespace content
183