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