blob: d0a7c7c9210a757facfc1ad4a0b88d82534a02c4 [file] [log] [blame]
// Copyright 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/download/download_job_factory.h"
#include <memory>
#include "base/memory/ptr_util.h"
#include "content/browser/download/download_item_impl.h"
#include "content/browser/download/download_job.h"
#include "content/browser/download/download_job_impl.h"
#include "content/browser/download/download_stats.h"
#include "content/browser/download/parallel_download_job.h"
#include "content/browser/download/parallel_download_utils.h"
#include "content/public/common/content_features.h"
namespace content {
namespace {
// Returns if the download should be a parallel download.
bool ShouldUseParallelDownload(const DownloadCreateInfo& create_info) {
// To enable parallel download, following conditions need to be satisfied.
// 1. Feature |kParallelDownloading| enabled.
// 2. Strong validators response headers. i.e. ETag and Last-Modified.
// 3. Accept-Ranges header.
// 4. Content-Length header.
// 5. Content-Length is no less than the minimum slice size configuration.
// 6. HTTP/1.1 protocol, not QUIC nor HTTP/1.0.
if (!base::FeatureList::IsEnabled(features::kParallelDownloading))
return false;
// Etag and last modified are stored into DownloadCreateInfo in
// DownloadRequestCore only if the response header complies to the strong
// validator rule.
bool has_strong_validator =
!create_info.etag.empty() || !create_info.last_modified.empty();
bool has_content_length = create_info.total_bytes > 0;
bool satisfy_min_file_size =
create_info.total_bytes >= GetMinSliceSizeConfig();
bool satisfy_connection_type = create_info.connection_info ==
net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1;
bool should_use_parallel_download =
has_strong_validator && create_info.accept_range && has_content_length &&
satisfy_min_file_size && satisfy_connection_type;
RecordParallelDownloadCreationEvent(
should_use_parallel_download
? ParallelDownloadCreationEvent::STARTED_PARALLEL_DOWNLOAD
: ParallelDownloadCreationEvent::FELL_BACK_TO_NORMAL_DOWNLOAD);
if (!has_strong_validator) {
RecordParallelDownloadCreationEvent(
ParallelDownloadCreationEvent::FALLBACK_REASON_STRONG_VALIDATORS);
}
if (!create_info.accept_range) {
RecordParallelDownloadCreationEvent(
ParallelDownloadCreationEvent::FALLBACK_REASON_ACCEPT_RANGE_HEADER);
}
if (!has_content_length) {
RecordParallelDownloadCreationEvent(
ParallelDownloadCreationEvent::FALLBACK_REASON_CONTENT_LENGTH_HEADER);
}
if (!satisfy_min_file_size) {
RecordParallelDownloadCreationEvent(
ParallelDownloadCreationEvent::FALLBACK_REASON_FILE_SIZE);
}
if (!satisfy_connection_type) {
RecordParallelDownloadCreationEvent(
ParallelDownloadCreationEvent::FALLBACK_REASON_CONNECTION_TYPE);
}
return should_use_parallel_download;
}
} // namespace
std::unique_ptr<DownloadJob> DownloadJobFactory::CreateJob(
DownloadItemImpl* download_item,
std::unique_ptr<DownloadRequestHandleInterface> req_handle,
const DownloadCreateInfo& create_info) {
// Build parallel download job.
if (ShouldUseParallelDownload(create_info)) {
return base::MakeUnique<ParallelDownloadJob>(download_item,
std::move(req_handle),
create_info);
}
// An ordinary download job.
return base::MakeUnique<DownloadJobImpl>(download_item,
std::move(req_handle));
}
} // namespace