blob: 4044367295a0620e3b436d7002ed56a8ed3d38ac [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/resource_downloader.h"
#include "content/browser/blob_storage/blob_url_loader_factory.h"
#include "content/browser/download/download_utils.h"
#include "content/common/throttling_url_loader.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/browser_side_navigation_policy.h"
#include "storage/browser/fileapi/file_system_context.h"
namespace content {
// This class is only used for providing the WebContents to DownloadItemImpl.
class RequestHandle : public DownloadRequestHandleInterface {
public:
RequestHandle(int render_process_id,
int render_frame_id,
int frame_tree_node_id)
: render_process_id_(render_process_id),
render_frame_id_(render_frame_id),
frame_tree_node_id_(frame_tree_node_id) {}
RequestHandle(RequestHandle&& other)
: render_process_id_(other.render_process_id_),
render_frame_id_(other.render_frame_id_),
frame_tree_node_id_(other.frame_tree_node_id_) {}
// DownloadRequestHandleInterface
WebContents* GetWebContents() const override {
DCHECK(IsBrowserSideNavigationEnabled());
WebContents* web_contents = WebContents::FromRenderFrameHost(
RenderFrameHost::FromID(render_process_id_, render_frame_id_));
if (web_contents)
return web_contents;
return WebContents::FromFrameTreeNodeId(frame_tree_node_id_);
}
DownloadManager* GetDownloadManager() const override { return nullptr; }
void PauseRequest() const override {}
void ResumeRequest() const override {}
void CancelRequest(bool user_cancel) const override {}
private:
int render_process_id_;
int render_frame_id_;
int frame_tree_node_id_;
DISALLOW_COPY_AND_ASSIGN(RequestHandle);
};
// static
std::unique_ptr<ResourceDownloader> ResourceDownloader::BeginDownload(
base::WeakPtr<UrlDownloadHandler::Delegate> delegate,
std::unique_ptr<DownloadUrlParameters> params,
std::unique_ptr<ResourceRequest> request,
scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter,
scoped_refptr<storage::FileSystemContext> file_system_context,
uint32_t download_id,
bool is_parallel_request) {
mojom::URLLoaderFactoryPtr* factory =
params->url().SchemeIs(url::kBlobScheme)
? url_loader_factory_getter->GetBlobFactory()
: url_loader_factory_getter->GetNetworkFactory();
auto downloader = std::make_unique<ResourceDownloader>(
delegate, std::move(request),
std::make_unique<DownloadSaveInfo>(params->GetSaveInfo()), download_id,
params->guid(), is_parallel_request, params->is_transient(),
params->fetch_error_body());
downloader->Start(factory, file_system_context, std::move(params));
return downloader;
}
// static
std::unique_ptr<ResourceDownloader>
ResourceDownloader::InterceptNavigationResponse(
base::WeakPtr<UrlDownloadHandler::Delegate> delegate,
std::unique_ptr<ResourceRequest> resource_request,
const scoped_refptr<ResourceResponse>& response,
mojo::ScopedDataPipeConsumerHandle consumer_handle,
const SSLStatus& ssl_status,
int frame_tree_node_id,
std::unique_ptr<ThrottlingURLLoader> url_loader,
std::vector<GURL> url_chain,
base::Optional<network::URLLoaderCompletionStatus> status) {
auto downloader = std::make_unique<ResourceDownloader>(
delegate, std::move(resource_request),
std::make_unique<DownloadSaveInfo>(), content::DownloadItem::kInvalidId,
std::string(), false, false, false);
downloader->InterceptResponse(
std::move(url_loader), response, std::move(consumer_handle), ssl_status,
frame_tree_node_id, std::move(url_chain), std::move(status));
return downloader;
}
ResourceDownloader::ResourceDownloader(
base::WeakPtr<UrlDownloadHandler::Delegate> delegate,
std::unique_ptr<ResourceRequest> resource_request,
std::unique_ptr<DownloadSaveInfo> save_info,
uint32_t download_id,
std::string guid,
bool is_parallel_request,
bool is_transient,
bool fetch_error_body)
: delegate_(delegate),
resource_request_(std::move(resource_request)),
response_handler_(resource_request_.get(),
this,
std::move(save_info),
is_parallel_request,
is_transient,
fetch_error_body),
blob_client_binding_(&response_handler_),
download_id_(download_id),
guid_(guid),
weak_ptr_factory_(this) {}
ResourceDownloader::~ResourceDownloader() = default;
void ResourceDownloader::Start(
mojom::URLLoaderFactoryPtr* factory,
scoped_refptr<storage::FileSystemContext> file_system_context,
std::unique_ptr<DownloadUrlParameters> download_url_parameters) {
callback_ = download_url_parameters->callback();
if (download_url_parameters->url().SchemeIs(url::kBlobScheme)) {
mojom::URLLoaderRequest url_loader_request;
mojom::URLLoaderClientPtr client;
blob_client_binding_.Bind(mojo::MakeRequest(&client));
BlobURLLoaderFactory::CreateLoaderAndStart(
std::move(url_loader_request), *(resource_request_.get()),
std::move(client), download_url_parameters->GetBlobDataHandle(),
file_system_context.get());
} else {
url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
factory->get(), std::vector<std::unique_ptr<URLLoaderThrottle>>(),
0, // routing_id
0, // request_id
mojom::kURLLoadOptionSendSSLInfo | mojom::kURLLoadOptionSniffMimeType,
*(resource_request_.get()), &response_handler_,
download_url_parameters->GetNetworkTrafficAnnotation());
url_loader_->SetPriority(net::RequestPriority::IDLE,
0 /* intra_priority_value */);
}
}
void ResourceDownloader::InterceptResponse(
std::unique_ptr<ThrottlingURLLoader> url_loader,
const scoped_refptr<ResourceResponse>& response,
mojo::ScopedDataPipeConsumerHandle consumer_handle,
const SSLStatus& ssl_status,
int frame_tree_node_id,
std::vector<GURL> url_chain,
base::Optional<network::URLLoaderCompletionStatus> status) {
url_loader_ = std::move(url_loader);
url_loader_->set_forwarding_client(&response_handler_);
net::SSLInfo info;
info.cert_status = ssl_status.cert_status;
frame_tree_node_id_ = frame_tree_node_id;
response_handler_.SetURLChain(std::move(url_chain));
response_handler_.OnReceiveResponse(response->head,
base::Optional<net::SSLInfo>(info),
mojom::DownloadedTempFilePtr());
response_handler_.OnStartLoadingResponseBody(std::move(consumer_handle));
if (status.has_value())
response_handler_.OnComplete(status.value());
}
void ResourceDownloader::OnResponseStarted(
std::unique_ptr<DownloadCreateInfo> download_create_info,
mojom::DownloadStreamHandlePtr stream_handle) {
download_create_info->download_id = download_id_;
download_create_info->guid = guid_;
download_create_info->request_handle.reset(new RequestHandle(
resource_request_->origin_pid, resource_request_->render_frame_id,
frame_tree_node_id_));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&UrlDownloadHandler::Delegate::OnUrlDownloadStarted,
delegate_, std::move(download_create_info),
std::make_unique<DownloadManager::InputStream>(
std::move(stream_handle)),
callback_));
}
void ResourceDownloader::OnReceiveRedirect() {
url_loader_->FollowRedirect();
}
} // namespace content