appcache_url_request_job.cc revision 5e3f23d412006dc4db4e659864679f29341e113f
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "webkit/browser/appcache/appcache_url_request_job.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <vector>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/command_line.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop.h"
145e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
155e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_log.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_request_headers.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_response_headers.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_util.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_status.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "webkit/browser/appcache/appcache_histograms.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "webkit/browser/appcache/appcache_service.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace appcache {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AppCacheURLRequestJob::AppCacheURLRequestJob(
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLRequest* request,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::NetworkDelegate* network_delegate,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AppCacheStorage* storage)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : net::URLRequestJob(request, network_delegate),
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      storage_(storage),
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_been_started_(false), has_been_killed_(false),
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delivery_type_(AWAITING_DELIVERY_ORDERS),
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      group_id_(0), cache_id_(kNoCacheId), is_fallback_(false),
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache_entry_not_found_(false),
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(storage_);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppCacheURLRequestJob::DeliverAppCachedResponse(
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& manifest_url, int64 group_id, int64 cache_id,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AppCacheEntry& entry, bool is_fallback) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!has_delivery_orders());
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(entry.has_response_id());
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delivery_type_ = APPCACHED_DELIVERY;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  manifest_url_ = manifest_url;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  group_id_ = group_id;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cache_id_ = cache_id;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry_ = entry;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_fallback_ = is_fallback;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybeBeginDelivery();
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppCacheURLRequestJob::DeliverNetworkResponse() {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!has_delivery_orders());
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delivery_type_ = NETWORK_DELIVERY;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  storage_ = NULL;  // not needed
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybeBeginDelivery();
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppCacheURLRequestJob::DeliverErrorResponse() {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!has_delivery_orders());
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delivery_type_ = ERROR_DELIVERY;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  storage_ = NULL;  // not needed
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybeBeginDelivery();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppCacheURLRequestJob::MaybeBeginDelivery() {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (has_been_started() && has_delivery_orders()) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Start asynchronously so that all error reporting and data
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // callbacks happen as they would for network requests.
74b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&AppCacheURLRequestJob::BeginDelivery,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   weak_factory_.GetWeakPtr()));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppCacheURLRequestJob::BeginDelivery() {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(has_delivery_orders() && has_been_started());
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (has_been_killed())
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (delivery_type_) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case NETWORK_DELIVERY:
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AppCacheHistograms::AddNetworkJobStartDelaySample(
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::TimeTicks::Now() - start_time_tick_);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // To fallthru to the network, we restart the request which will
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // cause a new job to be created to retrieve the resource from the
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // network. Our caller is responsible for arranging to not re-intercept
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the same request.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyRestartRequired();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ERROR_DELIVERY:
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AppCacheHistograms::AddErrorJobStartDelaySample(
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::TimeTicks::Now() - start_time_tick_);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request()->net_log().AddEvent(
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          net::NetLog::TYPE_APPCACHE_DELIVERING_ERROR_RESPONSE);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             net::ERR_FAILED));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case APPCACHED_DELIVERY:
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (entry_.IsExecutable()) {
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        DCHECK(CommandLine::ForCurrentProcess()->HasSwitch(
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            kEnableExecutableHandlers));
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // TODO(michaeln): do something different here with
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // an AppCacheExecutableHandler.
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AppCacheHistograms::AddAppCacheJobStartDelaySample(
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::TimeTicks::Now() - start_time_tick_);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request()->net_log().AddEvent(
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          is_fallback_ ?
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              net::NetLog::TYPE_APPCACHE_DELIVERING_FALLBACK_RESPONSE :
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              net::NetLog::TYPE_APPCACHE_DELIVERING_CACHED_RESPONSE);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      storage_->LoadResponseInfo(
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          manifest_url_, group_id_, entry_.response_id(), this);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AppCacheURLRequestJob::~AppCacheURLRequestJob() {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (storage_)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    storage_->CancelDelegateCallbacks(this);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppCacheURLRequestJob::OnResponseInfoLoaded(
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AppCacheResponseInfo* response_info, int64 response_id) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(is_delivering_appcache_response());
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<AppCacheURLRequestJob> protect(this);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (response_info) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info_ = response_info;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reader_.reset(storage_->CreateResponseReader(
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        manifest_url_, group_id_, entry_.response_id()));
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (is_range_request())
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetupRangeResponse();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyHeadersComplete();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // A resource that is expected to be in the appcache is missing.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See http://code.google.com/p/chromium/issues/detail?id=50657
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Instead of failing the request, we restart the request. The retry
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // attempt will fallthru to the network instead of trying to load
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // from the appcache.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    storage_->service()->CheckAppCacheResponse(manifest_url_, cache_id_,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               entry_.response_id());
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache_entry_not_found_ = true;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyRestartRequired();
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const net::HttpResponseInfo* AppCacheURLRequestJob::http_info() const {
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!info_.get())
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
164b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (range_response_info_)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return range_response_info_.get();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return info_->http_response_info();
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppCacheURLRequestJob::SetupRangeResponse() {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(is_range_request() && info_.get() && reader_.get() &&
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         is_delivering_appcache_response());
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int resource_size = static_cast<int>(info_->response_data_size());
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (resource_size < 0 || !range_requested_.ComputeBounds(resource_size)) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    range_requested_ = net::HttpByteRange();
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(range_requested_.HasFirstBytePosition() &&
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         range_requested_.HasLastBytePosition());
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int offset = static_cast<int>(range_requested_.first_byte_position());
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int length = static_cast<int>(range_requested_.last_byte_position() -
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                range_requested_.first_byte_position() + 1);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tell the reader about the range to read.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reader_->SetReadRange(offset, length);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make a copy of the full response headers and fix them up
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for the range we'll be returning.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char kLengthHeader[] = "Content-Length";
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char kRangeHeader[] = "Content-Range";
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char kPartialStatusLine[] = "HTTP/1.1 206 Partial Content";
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  range_response_info_.reset(
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new net::HttpResponseInfo(*info_->http_response_info()));
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  net::HttpResponseHeaders* headers = range_response_info_->headers.get();
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  headers->RemoveHeader(kLengthHeader);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  headers->RemoveHeader(kRangeHeader);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  headers->ReplaceStatusLine(kPartialStatusLine);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  headers->AddHeader(
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::StringPrintf("%s: %d", kLengthHeader, length));
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  headers->AddHeader(
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::StringPrintf("%s: bytes %d-%d/%d",
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         kRangeHeader,
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         offset,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         offset + length - 1,
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         resource_size));
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppCacheURLRequestJob::OnReadComplete(int result) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(is_delivering_appcache_response());
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == 0) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyDone(net::URLRequestStatus());
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (result < 0) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    storage_->service()->CheckAppCacheResponse(manifest_url_, cache_id_,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               entry_.response_id());
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyReadComplete(result);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// net::URLRequestJob overrides ------------------------------------------------
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppCacheURLRequestJob::Start() {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!has_been_started());
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  has_been_started_ = true;
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  start_time_tick_ = base::TimeTicks::Now();
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybeBeginDelivery();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppCacheURLRequestJob::Kill() {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_been_killed_) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    has_been_killed_ = true;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reader_.reset();
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (storage_) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      storage_->CancelDelegateCallbacks(this);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      storage_ = NULL;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLRequestJob::Kill();
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    weak_factory_.InvalidateWeakPtrs();
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)net::LoadState AppCacheURLRequestJob::GetLoadState() const {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_been_started())
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return net::LOAD_STATE_IDLE;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_delivery_orders())
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return net::LOAD_STATE_WAITING_FOR_APPCACHE;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delivery_type_ != APPCACHED_DELIVERY)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return net::LOAD_STATE_IDLE;
251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!info_.get())
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return net::LOAD_STATE_WAITING_FOR_APPCACHE;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reader_.get() && reader_->IsReadPending())
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return net::LOAD_STATE_READING_RESPONSE;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return net::LOAD_STATE_IDLE;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AppCacheURLRequestJob::GetMimeType(std::string* mime_type) const {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!http_info())
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return http_info()->headers->GetMimeType(mime_type);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AppCacheURLRequestJob::GetCharset(std::string* charset) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!http_info())
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return http_info()->headers->GetCharset(charset);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppCacheURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!http_info())
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *info = *http_info();
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AppCacheURLRequestJob::GetResponseCode() const {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!http_info())
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return http_info()->headers->response_code();
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AppCacheURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size,
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        int *bytes_read) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(is_delivering_appcache_response());
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(buf_size, 0);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bytes_read);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!reader_->IsReadPending());
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reader_->ReadData(
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf, buf_size, base::Bind(&AppCacheURLRequestJob::OnReadComplete,
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                base::Unretained(this)));
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppCacheURLRequestJob::SetExtraRequestHeaders(
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::HttpRequestHeaders& headers) {
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string value;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<net::HttpByteRange> ranges;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!headers.GetHeader(net::HttpRequestHeaders::kRange, &value) ||
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !net::HttpUtil::ParseRangeHeader(value, &ranges)) {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If multiple ranges are requested, we play dumb and
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // return the entire response with 200 OK.
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ranges.size() == 1U)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    range_requested_ = ranges[0];
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace appcache
311