
Bring back profile URLLoaderFactory by async retrieving through FullBrowserTransitionManager without breaking DownloadServiceFactory as a SKSF (SimpleKeyedServiceFactory). Bug: 395544421 Change-Id: I5c7126df0619ec7d57e78b947b0c1968f6d1fae3 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6249551 Reviewed-by: Peter Beverloo <peter@chromium.org> Reviewed-by: Henrique Nakashima <hnakashima@chromium.org> Commit-Queue: Claudio DeSouza <cdesouza@chromium.org> Cr-Commit-Position: refs/heads/main@{#1424112}
355 lines
14 KiB
C++
355 lines
14 KiB
C++
// Copyright 2018 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "content/web_test/browser/web_test_background_fetch_delegate.h"
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "base/files/file_path.h"
|
|
#include "base/functional/bind.h"
|
|
#include "base/functional/callback.h"
|
|
#include "base/memory/ptr_util.h"
|
|
#include "base/memory/raw_ptr.h"
|
|
#include "base/memory/weak_ptr.h"
|
|
#include "base/task/sequenced_task_runner.h"
|
|
#include "base/test/scoped_feature_list.h"
|
|
#include "components/download/content/factory/download_service_factory_helper.h"
|
|
#include "components/download/public/background_service/background_download_service.h"
|
|
#include "components/download/public/background_service/blob_context_getter_factory.h"
|
|
#include "components/download/public/background_service/clients.h"
|
|
#include "components/download/public/background_service/download_metadata.h"
|
|
#include "components/download/public/background_service/download_params.h"
|
|
#include "components/download/public/background_service/features.h"
|
|
#include "components/download/public/background_service/url_loader_factory_getter.h"
|
|
#include "components/keyed_service/core/simple_factory_key.h"
|
|
#include "components/keyed_service/core/simple_key_map.h"
|
|
#include "content/public/browser/background_fetch_description.h"
|
|
#include "content/public/browser/background_fetch_response.h"
|
|
#include "content/public/browser/browser_context.h"
|
|
#include "content/public/browser/browser_task_traits.h"
|
|
#include "content/public/browser/browser_thread.h"
|
|
#include "content/public/browser/network_service_instance.h"
|
|
#include "content/public/browser/storage_partition.h"
|
|
#include "mojo/public/cpp/bindings/pending_remote.h"
|
|
#include "mojo/public/cpp/bindings/remote.h"
|
|
#include "net/traffic_annotation/network_traffic_annotation.h"
|
|
#include "services/network/public/cpp/resource_request_body.h"
|
|
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
|
|
#include "ui/gfx/geometry/size.h"
|
|
|
|
namespace content {
|
|
|
|
// Provides BlobContextGetter from a BrowserContext.
|
|
class TestBlobContextGetterFactory : public download::BlobContextGetterFactory {
|
|
public:
|
|
TestBlobContextGetterFactory(content::BrowserContext* browser_context)
|
|
: browser_context_(browser_context) {}
|
|
|
|
TestBlobContextGetterFactory(const TestBlobContextGetterFactory&) = delete;
|
|
TestBlobContextGetterFactory& operator=(const TestBlobContextGetterFactory&) =
|
|
delete;
|
|
|
|
~TestBlobContextGetterFactory() override = default;
|
|
|
|
private:
|
|
// download::BlobContextGetterFactory implementation.
|
|
void RetrieveBlobContextGetter(
|
|
download::BlobContextGetterCallback callback) override {
|
|
auto blob_context_getter = browser_context_->GetBlobStorageContext();
|
|
std::move(callback).Run(blob_context_getter);
|
|
}
|
|
|
|
raw_ptr<content::BrowserContext> browser_context_;
|
|
};
|
|
|
|
// Provides URLLoaderFactory from a BrowserContext.
|
|
class TestURLLoaderFactoryGetter : public download::URLLoaderFactoryGetter {
|
|
public:
|
|
TestURLLoaderFactoryGetter(content::BrowserContext* browser_context)
|
|
: browser_context_(browser_context) {}
|
|
|
|
TestURLLoaderFactoryGetter(const TestURLLoaderFactoryGetter&) = delete;
|
|
TestURLLoaderFactoryGetter& operator=(const TestURLLoaderFactoryGetter&) =
|
|
delete;
|
|
|
|
~TestURLLoaderFactoryGetter() override = default;
|
|
|
|
private:
|
|
// download::URLLoaderFactoryGetter implementation.
|
|
void RetrieveURLLoaderFactory(
|
|
download::URLLoaderFactoryGetterCallback callback) override {
|
|
auto url_loader_factory = browser_context_->GetDefaultStoragePartition()
|
|
->GetURLLoaderFactoryForBrowserProcess();
|
|
std::move(callback).Run(url_loader_factory);
|
|
}
|
|
|
|
raw_ptr<content::BrowserContext> browser_context_;
|
|
};
|
|
|
|
// Implementation of a Download Service client that will be servicing
|
|
// Background Fetch requests when running web tests.
|
|
class WebTestBackgroundFetchDelegate::WebTestBackgroundFetchDownloadClient
|
|
: public download::Client {
|
|
public:
|
|
explicit WebTestBackgroundFetchDownloadClient(
|
|
base::WeakPtr<content::BackgroundFetchDelegate::Client> client)
|
|
: client_(std::move(client)) {}
|
|
|
|
WebTestBackgroundFetchDownloadClient(
|
|
const WebTestBackgroundFetchDownloadClient&) = delete;
|
|
WebTestBackgroundFetchDownloadClient& operator=(
|
|
const WebTestBackgroundFetchDownloadClient&) = delete;
|
|
|
|
~WebTestBackgroundFetchDownloadClient() override = default;
|
|
|
|
// Registers the |guid| as belonging to a Background Fetch job identified by
|
|
// |job_unique_id|. Downloads may only be registered once.
|
|
void RegisterDownload(const std::string& guid,
|
|
const std::string& job_unique_id,
|
|
bool has_request_body) {
|
|
DCHECK(!guid_to_unique_job_id_mapping_.count(guid));
|
|
guid_to_unique_job_id_mapping_[guid] = job_unique_id;
|
|
guid_to_request_body_mapping_[guid] = has_request_body;
|
|
}
|
|
|
|
// download::Client implementation:
|
|
void OnServiceInitialized(
|
|
bool state_lost,
|
|
const std::vector<download::DownloadMetaData>& downloads) override {}
|
|
|
|
void OnServiceUnavailable() override {}
|
|
|
|
void OnDownloadStarted(
|
|
const std::string& guid,
|
|
const std::vector<GURL>& url_chain,
|
|
const scoped_refptr<const net::HttpResponseHeaders>& headers) override {
|
|
DCHECK(guid_to_unique_job_id_mapping_.count(guid));
|
|
if (!client_)
|
|
return;
|
|
|
|
guid_to_response_[guid] =
|
|
std::make_unique<content::BackgroundFetchResponse>(url_chain,
|
|
std::move(headers));
|
|
|
|
client_->OnDownloadStarted(
|
|
guid_to_unique_job_id_mapping_[guid], guid,
|
|
std::make_unique<content::BackgroundFetchResponse>(
|
|
guid_to_response_[guid]->url_chain,
|
|
guid_to_response_[guid]->headers));
|
|
}
|
|
|
|
void OnDownloadUpdated(const std::string& guid,
|
|
uint64_t bytes_uploaded,
|
|
uint64_t bytes_downloaded) override {
|
|
DCHECK(guid_to_unique_job_id_mapping_.count(guid));
|
|
if (!client_)
|
|
return;
|
|
|
|
client_->OnDownloadUpdated(guid_to_unique_job_id_mapping_[guid], guid,
|
|
bytes_uploaded, bytes_downloaded);
|
|
}
|
|
|
|
void OnDownloadFailed(const std::string& guid,
|
|
const download::CompletionInfo& info,
|
|
download::Client::FailureReason reason) override {
|
|
DCHECK(guid_to_unique_job_id_mapping_.count(guid));
|
|
if (!client_)
|
|
return;
|
|
|
|
content::BackgroundFetchResult::FailureReason failure_reason;
|
|
switch (reason) {
|
|
case download::Client::FailureReason::NETWORK:
|
|
failure_reason = content::BackgroundFetchResult::FailureReason::NETWORK;
|
|
break;
|
|
case download::Client::FailureReason::TIMEDOUT:
|
|
failure_reason =
|
|
content::BackgroundFetchResult::FailureReason::TIMEDOUT;
|
|
break;
|
|
case download::Client::FailureReason::UNKNOWN:
|
|
failure_reason =
|
|
content::BackgroundFetchResult::FailureReason::FETCH_ERROR;
|
|
break;
|
|
case download::Client::FailureReason::ABORTED:
|
|
case download::Client::FailureReason::CANCELLED:
|
|
// The client cancelled or aborted it so no need to notify it.
|
|
return;
|
|
default:
|
|
NOTREACHED();
|
|
}
|
|
|
|
std::unique_ptr<BackgroundFetchResult> result =
|
|
std::make_unique<BackgroundFetchResult>(
|
|
std::move(guid_to_response_[guid]), base::Time::Now(),
|
|
failure_reason);
|
|
|
|
// Inform the client about the failed |result|. Then remove the mapping as
|
|
// no further communication is expected from the download service.
|
|
client_->OnDownloadComplete(guid_to_unique_job_id_mapping_[guid], guid,
|
|
std::move(result));
|
|
|
|
guid_to_unique_job_id_mapping_.erase(guid);
|
|
guid_to_request_body_mapping_.erase(guid);
|
|
guid_to_response_.erase(guid);
|
|
}
|
|
|
|
void OnDownloadSucceeded(const std::string& guid,
|
|
const download::CompletionInfo& info) override {
|
|
DCHECK(guid_to_unique_job_id_mapping_.count(guid));
|
|
if (!client_)
|
|
return;
|
|
|
|
std::unique_ptr<BackgroundFetchResult> result =
|
|
std::make_unique<BackgroundFetchResult>(
|
|
std::move(guid_to_response_[guid]), base::Time::Now(), info.path,
|
|
info.blob_handle, info.bytes_downloaded);
|
|
|
|
// Inform the client about the successful |result|. Then remove the mapping
|
|
// as no further communication is expected from the download service.
|
|
client_->OnDownloadComplete(guid_to_unique_job_id_mapping_[guid], guid,
|
|
std::move(result));
|
|
|
|
guid_to_unique_job_id_mapping_.erase(guid);
|
|
guid_to_request_body_mapping_.erase(guid);
|
|
guid_to_response_.erase(guid);
|
|
}
|
|
|
|
bool CanServiceRemoveDownloadedFile(const std::string& guid,
|
|
bool force_delete) override {
|
|
return true;
|
|
}
|
|
|
|
void GetUploadData(const std::string& guid,
|
|
download::GetUploadDataCallback callback) override {
|
|
if (!guid_to_request_body_mapping_[guid]) {
|
|
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
|
|
FROM_HERE, base::BindOnce(std::move(callback), nullptr));
|
|
return;
|
|
}
|
|
|
|
client_->GetUploadData(
|
|
guid_to_unique_job_id_mapping_[guid], guid,
|
|
base::BindOnce(&WebTestBackgroundFetchDownloadClient::DidGetUploadData,
|
|
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
|
|
}
|
|
|
|
void DidGetUploadData(download::GetUploadDataCallback callback,
|
|
blink::mojom::SerializedBlobPtr blob) {
|
|
mojo::PendingRemote<network::mojom::DataPipeGetter> data_pipe_getter_remote;
|
|
mojo::Remote<blink::mojom::Blob> blob_remote(std::move(blob->blob));
|
|
blob_remote->AsDataPipeGetter(
|
|
data_pipe_getter_remote.InitWithNewPipeAndPassReceiver());
|
|
|
|
auto request_body = base::MakeRefCounted<network::ResourceRequestBody>();
|
|
request_body->AppendDataPipe(std::move(data_pipe_getter_remote));
|
|
std::move(callback).Run(std::move(request_body));
|
|
}
|
|
|
|
const base::WeakPtr<content::BackgroundFetchDelegate::Client>& client()
|
|
const {
|
|
return client_;
|
|
}
|
|
|
|
private:
|
|
base::WeakPtr<content::BackgroundFetchDelegate::Client> client_;
|
|
base::flat_map<std::string, std::string> guid_to_unique_job_id_mapping_;
|
|
base::flat_map<std::string, bool> guid_to_request_body_mapping_;
|
|
base::flat_map<std::string, std::unique_ptr<content::BackgroundFetchResponse>>
|
|
guid_to_response_;
|
|
|
|
base::WeakPtrFactory<WebTestBackgroundFetchDownloadClient> weak_ptr_factory_{
|
|
this};
|
|
};
|
|
|
|
WebTestBackgroundFetchDelegate::WebTestBackgroundFetchDelegate(
|
|
BrowserContext* browser_context)
|
|
: browser_context_(browser_context) {}
|
|
|
|
WebTestBackgroundFetchDelegate::~WebTestBackgroundFetchDelegate() = default;
|
|
|
|
void WebTestBackgroundFetchDelegate::GetIconDisplaySize(
|
|
GetIconDisplaySizeCallback callback) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
std::move(callback).Run(gfx::Size(192, 192));
|
|
}
|
|
|
|
void WebTestBackgroundFetchDelegate::CreateDownloadJob(
|
|
base::WeakPtr<Client> client,
|
|
std::unique_ptr<BackgroundFetchDescription> fetch_description) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
|
|
// Lazily create the |download_service_| because only very few web tests
|
|
// actually require Background Fetch.
|
|
if (!download_service_) {
|
|
auto clients = std::make_unique<download::DownloadClientMap>();
|
|
auto background_fetch_client =
|
|
std::make_unique<WebTestBackgroundFetchDownloadClient>(client);
|
|
|
|
// Store a reference to the client for storing a GUID -> Unique ID mapping.
|
|
background_fetch_client_ = background_fetch_client.get();
|
|
|
|
clients->emplace(download::DownloadClient::BACKGROUND_FETCH,
|
|
std::move(background_fetch_client));
|
|
|
|
// Use a ScopedFeatureList to enable and configure the download service as
|
|
// if done by Finch. We have a strict dependency on it.
|
|
{
|
|
base::test::ScopedFeatureList download_service_configuration;
|
|
download_service_configuration.InitAndEnableFeatureWithParameters(
|
|
download::kDownloadServiceFeature, {{"start_up_delay_ms", "0"}});
|
|
SimpleFactoryKey* simple_key =
|
|
SimpleKeyMap::GetInstance()->GetForBrowserContext(browser_context_);
|
|
download_service_ = download::BuildInMemoryDownloadService(
|
|
simple_key, std::move(clients), GetNetworkConnectionTracker(),
|
|
base::FilePath(),
|
|
std::make_unique<TestBlobContextGetterFactory>(browser_context_),
|
|
GetIOThreadTaskRunner({}),
|
|
std::make_unique<TestURLLoaderFactoryGetter>(browser_context_));
|
|
}
|
|
}
|
|
}
|
|
|
|
void WebTestBackgroundFetchDelegate::DownloadUrl(
|
|
const std::string& job_unique_id,
|
|
const std::string& download_guid,
|
|
const std::string& method,
|
|
const GURL& url,
|
|
::network::mojom::CredentialsMode credentials_mode,
|
|
const net::NetworkTrafficAnnotationTag& traffic_annotation,
|
|
const net::HttpRequestHeaders& headers,
|
|
bool has_request_body) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
|
|
background_fetch_client_->RegisterDownload(download_guid, job_unique_id,
|
|
has_request_body);
|
|
|
|
download::DownloadParams params;
|
|
params.guid = download_guid;
|
|
params.client = download::DownloadClient::BACKGROUND_FETCH;
|
|
params.request_params.method = method;
|
|
params.request_params.url = url;
|
|
params.request_params.request_headers = headers;
|
|
params.traffic_annotation =
|
|
net::MutableNetworkTrafficAnnotationTag(traffic_annotation);
|
|
|
|
download_service_->StartDownload(std::move(params));
|
|
}
|
|
|
|
void WebTestBackgroundFetchDelegate::Abort(const std::string& job_unique_id) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
// TODO(peter): Implement the ability to abort the |job_unique_id|.
|
|
}
|
|
|
|
void WebTestBackgroundFetchDelegate::MarkJobComplete(
|
|
const std::string& job_unique_id) {}
|
|
|
|
void WebTestBackgroundFetchDelegate::UpdateUI(
|
|
const std::string& job_unique_id,
|
|
const std::optional<std::string>& title,
|
|
const std::optional<SkBitmap>& icon) {
|
|
background_fetch_client_->client()->OnUIUpdated(job_unique_id);
|
|
}
|
|
|
|
} // namespace content
|