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