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