|  | // Copyright (c) 2017 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "content/browser/appcache/appcache_job.h" | 
|  |  | 
|  | #include "base/command_line.h" | 
|  | #include "content/browser/appcache/appcache_request.h" | 
|  | #include "content/browser/appcache/appcache_response.h" | 
|  | #include "content/browser/appcache/appcache_url_loader_job.h" | 
|  | #include "content/browser/appcache/appcache_url_request_job.h" | 
|  | #include "content/public/common/content_features.h" | 
|  | #include "net/http/http_request_headers.h" | 
|  | #include "net/http/http_response_headers.h" | 
|  | #include "net/http/http_util.h" | 
|  |  | 
|  | namespace content { | 
|  |  | 
|  | AppCacheJob::~AppCacheJob() { | 
|  | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 
|  | } | 
|  |  | 
|  | bool AppCacheJob::IsWaiting() const { | 
|  | return delivery_type_ == AWAITING_DELIVERY_ORDERS; | 
|  | } | 
|  |  | 
|  | bool AppCacheJob::IsDeliveringAppCacheResponse() const { | 
|  | return delivery_type_ == APPCACHED_DELIVERY; | 
|  | } | 
|  |  | 
|  | bool AppCacheJob::IsDeliveringNetworkResponse() const { | 
|  | return delivery_type_ == NETWORK_DELIVERY; | 
|  | } | 
|  |  | 
|  | bool AppCacheJob::IsDeliveringErrorResponse() const { | 
|  | return delivery_type_ == ERROR_DELIVERY; | 
|  | } | 
|  |  | 
|  | bool AppCacheJob::IsCacheEntryNotFound() const { | 
|  | return cache_entry_not_found_; | 
|  | } | 
|  |  | 
|  | AppCacheURLRequestJob* AppCacheJob::AsURLRequestJob() { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | AppCacheURLLoaderJob* AppCacheJob::AsURLLoaderJob() { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | AppCacheJob::AppCacheJob() | 
|  | : cache_entry_not_found_(false), delivery_type_(AWAITING_DELIVERY_ORDERS) {} | 
|  |  | 
|  | void AppCacheJob::InitializeRangeRequestInfo( | 
|  | const net::HttpRequestHeaders& headers) { | 
|  | std::string value; | 
|  | std::vector<net::HttpByteRange> ranges; | 
|  | if (!headers.GetHeader(net::HttpRequestHeaders::kRange, &value) || | 
|  | !net::HttpUtil::ParseRangeHeader(value, &ranges)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // If multiple ranges are requested, we play dumb and | 
|  | // return the entire response with 200 OK. | 
|  | if (ranges.size() == 1U) | 
|  | range_requested_ = ranges[0]; | 
|  | } | 
|  |  | 
|  | void AppCacheJob::SetupRangeResponse() { | 
|  | DCHECK(is_range_request() && reader_.get() && IsDeliveringAppCacheResponse()); | 
|  | int resource_size = static_cast<int>(info_->response_data_size()); | 
|  | if (resource_size < 0 || !range_requested_.ComputeBounds(resource_size)) { | 
|  | range_requested_ = net::HttpByteRange(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | DCHECK(range_requested_.IsValid()); | 
|  | int offset = static_cast<int>(range_requested_.first_byte_position()); | 
|  | int length = static_cast<int>(range_requested_.last_byte_position() - | 
|  | range_requested_.first_byte_position() + 1); | 
|  |  | 
|  | // Tell the reader about the range to read. | 
|  | reader_->SetReadRange(offset, length); | 
|  |  | 
|  | // Make a copy of the full response headers and fix them up | 
|  | // for the range we'll be returning. | 
|  | range_response_info_ = | 
|  | std::make_unique<net::HttpResponseInfo>(info_->http_response_info()); | 
|  | net::HttpResponseHeaders* headers = range_response_info_->headers.get(); | 
|  | headers->UpdateWithNewRange(range_requested_, resource_size, | 
|  | true /* replace status line */); | 
|  | } | 
|  |  | 
|  | }  // namespace content |