blob: e5258140d1952a834ae3b66ea78e41941b50807a [file] [log] [blame]
// 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 {
std::unique_ptr<AppCacheJob> AppCacheJob::Create(
bool is_main_resource,
AppCacheHost* host,
AppCacheStorage* storage,
AppCacheRequest* request,
net::NetworkDelegate* network_delegate,
OnPrepareToRestartCallback restart_callback,
std::unique_ptr<SubresourceLoadInfo> subresource_load_info,
URLLoaderFactoryGetter* loader_factory_getter) {
std::unique_ptr<AppCacheJob> job;
if (base::FeatureList::IsEnabled(features::kNetworkService)) {
job.reset(new AppCacheURLLoaderJob(
*(request->GetResourceRequest()), request->AsURLLoaderRequest(),
storage, std::move(subresource_load_info), loader_factory_getter));
} else {
job.reset(new AppCacheURLRequestJob(
request->GetURLRequest(), network_delegate, storage, host,
is_main_resource, std::move(restart_callback)));
}
return job;
}
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_;
}
base::WeakPtr<AppCacheJob> AppCacheJob::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
net::URLRequestJob* AppCacheJob::AsURLRequestJob() {
return nullptr;
}
AppCacheURLLoaderJob* AppCacheJob::AsURLLoaderJob() {
return nullptr;
}
AppCacheJob::AppCacheJob()
: cache_entry_not_found_(false),
delivery_type_(AWAITING_DELIVERY_ORDERS),
weak_factory_(this) {}
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_.reset(
new 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