0

[Background Fetch] Simplify fetch storage workflow.

In addition, MatchAll should return all records, including unprocessed
ones. To support this, the following changes were made:
- Creating a registration also stores all the requests with an empty
response in the cache.
- When an individual request is processed, the failure reason (if any)
is stored in the metadata.
- The logic of GetSettledFetchesTask was moved to
MarkRegistrationForDeletionTask. It checks the metadata rather than the
cache itself to find a failure reason (if any).
- Match/MatchAll logic was moved to a new database task
(MatchRequestsTask). A new API call was added to the cache storage to
allow querying request/response pairs. If a response is found to be
empty it will be exposed as a nullptr.

Change-Id: I631a3ef3da95117aed759a675fe591da5201eeca
Reviewed-on: https://chromium-review.googlesource.com/c/1280851
Reviewed-by: Peter Beverloo <peter@chromium.org>
Reviewed-by: Steven Holte <holte@chromium.org>
Reviewed-by: Joshua Bell <jsbell@chromium.org>
Reviewed-by: Ben Kelly <wanderview@chromium.org>
Reviewed-by: Mugdha Lakhani <nator@chromium.org>
Commit-Queue: Rayan Kanso <rayankans@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600768}
This commit is contained in:
Rayan Kanso
2018-10-18 15:28:27 +00:00
committed by Commit Bot
parent 6196b626c6
commit ac0b91e2c7
32 changed files with 757 additions and 645 deletions

@ -452,14 +452,14 @@ jumbo_source_set("browser") {
"background_fetch/storage/get_metadata_task.h",
"background_fetch/storage/get_registration_task.cc",
"background_fetch/storage/get_registration_task.h",
"background_fetch/storage/get_settled_fetches_task.cc",
"background_fetch/storage/get_settled_fetches_task.h",
"background_fetch/storage/image_helpers.cc",
"background_fetch/storage/image_helpers.h",
"background_fetch/storage/mark_registration_for_deletion_task.cc",
"background_fetch/storage/mark_registration_for_deletion_task.h",
"background_fetch/storage/mark_request_complete_task.cc",
"background_fetch/storage/mark_request_complete_task.h",
"background_fetch/storage/match_requests_task.cc",
"background_fetch/storage/match_requests_task.h",
"background_fetch/storage/start_next_pending_request_task.cc",
"background_fetch/storage/start_next_pending_request_task.h",
"background_fetch/storage/update_registration_ui_task.cc",

@ -134,11 +134,13 @@ message BackgroundFetchActiveRequest {
// A background fetch request in the completed state. This means that
// the DownloadManager returned the download.
//
// Next Tag: 6
// Next Tag: 7
message BackgroundFetchCompletedRequest {
optional string unique_id = 1;
optional int32 request_index = 2;
optional string serialized_request = 3;
optional string download_guid = 4;
optional bool succeeded = 5;
optional bool succeeded = 5 [deprecated = true];
optional BackgroundFetchRegistration.BackgroundFetchFailureReason
failure_reason = 6;
}

@ -426,16 +426,17 @@ void BackgroundFetchContext::DidFinishJob(
// active JobController, to terminate in-progress requests.
data_manager_->MarkRegistrationForDeletion(
registration_id,
/* check_for_failure= */ failure_reason == FailureReason::NONE,
base::BindOnce(&BackgroundFetchContext::DidMarkForDeletion,
weak_factory_.GetWeakPtr(), registration_id,
failure_reason, std::move(callback)));
std::move(callback)));
}
void BackgroundFetchContext::DidMarkForDeletion(
const BackgroundFetchRegistrationId& registration_id,
FailureReason failure_reason,
base::OnceCallback<void(blink::mojom::BackgroundFetchError)> callback,
blink::mojom::BackgroundFetchError error) {
blink::mojom::BackgroundFetchError error,
FailureReason failure_reason) {
DCHECK(callback);
std::move(callback).Run(error);
@ -446,40 +447,10 @@ void BackgroundFetchContext::DidMarkForDeletion(
if (error != blink::mojom::BackgroundFetchError::NONE)
return;
if (failure_reason == FailureReason::NONE) {
// As far as we know the fetch was successful, go over the entries in the
// cache and make sure all the responses are there and successful.
data_manager_->GetSettledFetchesForRegistration(
registration_id, std::make_unique<BackgroundFetchRequestMatchParams>(),
base::BindOnce(&BackgroundFetchContext::DidGetSettledFetches,
weak_factory_.GetWeakPtr(), registration_id));
return;
}
// The fetch failed, dispatch an appropriate event.
auto controllers_iter = job_controllers_.find(registration_id.unique_id());
DCHECK(controllers_iter != job_controllers_.end());
auto registration = controllers_iter->second->NewRegistration(
blink::mojom::BackgroundFetchResult::FAILURE);
DispatchCompletionEvent(registration_id, std::move(registration));
}
void BackgroundFetchContext::DidGetSettledFetches(
const BackgroundFetchRegistrationId& registration_id,
blink::mojom::BackgroundFetchError error,
FailureReason failure_reason,
std::vector<BackgroundFetchSettledFetch> settled_fetches,
std::vector<std::unique_ptr<storage::BlobDataHandle>> blob_data_handles) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(failure_reason == FailureReason::NONE ||
failure_reason == FailureReason::FETCH_ERROR ||
failure_reason == FailureReason::SERVICE_WORKER_UNAVAILABLE ||
failure_reason == FailureReason::BAD_STATUS);
auto controllers_iter = job_controllers_.find(registration_id.unique_id());
DCHECK(controllers_iter != job_controllers_.end());
failure_reason = controllers_iter->second->MergeFailureReason(failure_reason);
blink::mojom::BackgroundFetchResult result =
failure_reason == FailureReason::NONE
? blink::mojom::BackgroundFetchResult::SUCCESS
@ -596,7 +567,7 @@ void BackgroundFetchContext::MatchRequests(
blink::mojom::BackgroundFetchService::MatchRequestsCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
data_manager_->GetSettledFetchesForRegistration(
data_manager_->MatchRequests(
registration_id, std::move(match_params),
base::BindOnce(&BackgroundFetchContext::DidGetMatchingRequests,
weak_factory_.GetWeakPtr(), std::move(callback)));
@ -605,9 +576,7 @@ void BackgroundFetchContext::MatchRequests(
void BackgroundFetchContext::DidGetMatchingRequests(
blink::mojom::BackgroundFetchService::MatchRequestsCallback callback,
blink::mojom::BackgroundFetchError error,
FailureReason failure_reason,
std::vector<BackgroundFetchSettledFetch> settled_fetches,
std::vector<std::unique_ptr<storage::BlobDataHandle>> blob_data_handles) {
std::vector<BackgroundFetchSettledFetch> settled_fetches) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// TODO(crbug.com/863016): Update to 0u once we've stopped sending an

@ -206,9 +206,9 @@ class CONTENT_EXPORT BackgroundFetchContext
// Called when the data manager finishes marking a registration as deleted.
void DidMarkForDeletion(
const BackgroundFetchRegistrationId& registration_id,
blink::mojom::BackgroundFetchFailureReason failure_reason,
base::OnceCallback<void(blink::mojom::BackgroundFetchError)> callback,
blink::mojom::BackgroundFetchError error);
blink::mojom::BackgroundFetchError error,
blink::mojom::BackgroundFetchFailureReason failure_reason);
// Called when the sequence of settled fetches for |registration_id| have been
// retrieved from storage, and the Service Worker event can be invoked.
@ -225,9 +225,7 @@ class CONTENT_EXPORT BackgroundFetchContext
void DidGetMatchingRequests(
blink::mojom::BackgroundFetchService::MatchRequestsCallback callback,
blink::mojom::BackgroundFetchError error,
blink::mojom::BackgroundFetchFailureReason failure_reason,
std::vector<BackgroundFetchSettledFetch> settled_fetches,
std::vector<std::unique_ptr<storage::BlobDataHandle>> blob_data_handles);
std::vector<BackgroundFetchSettledFetch> settled_fetches);
// Dispatches an appropriate event (success, fail, abort).
void DispatchCompletionEvent(

@ -19,9 +19,9 @@
#include "content/browser/background_fetch/storage/get_developer_ids_task.h"
#include "content/browser/background_fetch/storage/get_metadata_task.h"
#include "content/browser/background_fetch/storage/get_registration_task.h"
#include "content/browser/background_fetch/storage/get_settled_fetches_task.h"
#include "content/browser/background_fetch/storage/mark_registration_for_deletion_task.h"
#include "content/browser/background_fetch/storage/mark_request_complete_task.h"
#include "content/browser/background_fetch/storage/match_requests_task.h"
#include "content/browser/background_fetch/storage/start_next_pending_request_task.h"
#include "content/browser/background_fetch/storage/update_registration_ui_task.h"
#include "content/browser/cache_storage/cache_storage_manager.h"
@ -150,24 +150,25 @@ void BackgroundFetchDataManager::MarkRequestAsComplete(
this, registration_id, std::move(request_info), std::move(callback)));
}
void BackgroundFetchDataManager::GetSettledFetchesForRegistration(
void BackgroundFetchDataManager::MatchRequests(
const BackgroundFetchRegistrationId& registration_id,
std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
SettledFetchesCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
AddDatabaseTask(std::make_unique<background_fetch::GetSettledFetchesTask>(
AddDatabaseTask(std::make_unique<background_fetch::MatchRequestsTask>(
this, registration_id, std::move(match_params), std::move(callback)));
}
void BackgroundFetchDataManager::MarkRegistrationForDeletion(
const BackgroundFetchRegistrationId& registration_id,
HandleBackgroundFetchErrorCallback callback) {
bool check_for_failure,
MarkRegistrationForDeletionCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
AddDatabaseTask(
std::make_unique<background_fetch::MarkRegistrationForDeletionTask>(
this, registration_id, std::move(callback)));
this, registration_id, check_for_failure, std::move(callback)));
}
void BackgroundFetchDataManager::DeleteRegistration(

@ -63,14 +63,15 @@ class CONTENT_EXPORT BackgroundFetchDataManager
using GetInitializationDataCallback = base::OnceCallback<void(
blink::mojom::BackgroundFetchError,
std::vector<background_fetch::BackgroundFetchInitializationData>)>;
using SettledFetchesCallback = base::OnceCallback<void(
blink::mojom::BackgroundFetchError,
blink::mojom::BackgroundFetchFailureReason,
std::vector<BackgroundFetchSettledFetch>,
std::vector<std::unique_ptr<storage::BlobDataHandle>>)>;
using SettledFetchesCallback =
base::OnceCallback<void(blink::mojom::BackgroundFetchError,
std::vector<BackgroundFetchSettledFetch>)>;
using GetRegistrationCallback =
base::OnceCallback<void(blink::mojom::BackgroundFetchError,
const BackgroundFetchRegistration&)>;
using MarkRegistrationForDeletionCallback =
base::OnceCallback<void(blink::mojom::BackgroundFetchError,
blink::mojom::BackgroundFetchFailureReason)>;
using MarkRequestCompleteCallback =
base::OnceCallback<void(blink::mojom::BackgroundFetchError)>;
using NextRequestCallback =
@ -125,7 +126,7 @@ class CONTENT_EXPORT BackgroundFetchDataManager
// |match_params|. Both the Request and Response objects will be initialised
// based on the stored data. Will invoke the |callback| when the list of
// fetches has been compiled.
void GetSettledFetchesForRegistration(
void MatchRequests(
const BackgroundFetchRegistrationId& registration_id,
std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
SettledFetchesCallback callback);
@ -140,10 +141,13 @@ class CONTENT_EXPORT BackgroundFetchDataManager
// memory. So instead this step disassociates the |developer_id| from the
// |unique_id|, so that existing JS objects with a reference to |unique_id|
// can still access the data, but it can no longer be reached using GetIds or
// GetRegistration.
// GetRegistration. If |check_for_failure| is true, the task will also check
// whether there is any associated failure reason with the fetches. This
// helps figure out whether a success or fail event should be dispatched.
void MarkRegistrationForDeletion(
const BackgroundFetchRegistrationId& registration_id,
HandleBackgroundFetchErrorCallback callback);
bool check_for_failure,
MarkRegistrationForDeletionCallback callback);
// Deletes the registration identified by |registration_id|. Should only be
// called once the refcount of JavaScript BackgroundFetchRegistration objects

@ -240,6 +240,10 @@ class BackgroundFetchDataManagerTest
base::BindOnce(&DidCreateRegistration, run_loop.QuitClosure(),
out_error));
run_loop.Run();
// Check that a cache was created.
if (*out_error == blink::mojom::BackgroundFetchError::NONE)
DCHECK(HasCache(registration_id.unique_id()));
}
BackgroundFetchRegistration GetRegistration(
@ -334,13 +338,19 @@ class BackgroundFetchDataManagerTest
// BackgroundFetchDataManager::MarkRegistrationForDeletion().
void MarkRegistrationForDeletion(
const BackgroundFetchRegistrationId& registration_id,
blink::mojom::BackgroundFetchError* out_error) {
bool check_for_failure,
blink::mojom::BackgroundFetchError* out_error,
blink::mojom::BackgroundFetchFailureReason* out_failure_reason) {
DCHECK(out_error);
DCHECK(out_failure_reason);
base::RunLoop run_loop;
background_fetch_data_manager_->MarkRegistrationForDeletion(
registration_id,
base::BindOnce(&DidGetError, run_loop.QuitClosure(), out_error));
registration_id, check_for_failure,
base::BindOnce(
&BackgroundFetchDataManagerTest::DidMarkRegistrationForDeletion,
base::Unretained(this), run_loop.QuitClosure(), out_error,
out_failure_reason));
run_loop.Run();
}
@ -373,28 +383,25 @@ class BackgroundFetchDataManagerTest
}
// Synchronous version of
// BackgroundFetchDataManager::GetSettledFetchesForRegistration().
void GetSettledFetchesForRegistration(
// BackgroundFetchDataManager::MatchRequests().
void MatchRequests(
const BackgroundFetchRegistrationId& registration_id,
base::Optional<ServiceWorkerFetchRequest> request_to_match,
blink::mojom::QueryParamsPtr cache_query_params,
bool match_all,
blink::mojom::BackgroundFetchError* out_error,
blink::mojom::BackgroundFetchFailureReason* out_failure_reason,
std::vector<BackgroundFetchSettledFetch>* out_settled_fetches) {
DCHECK(out_error);
DCHECK(out_failure_reason);
DCHECK(out_settled_fetches);
base::RunLoop run_loop;
auto match_params = std::make_unique<BackgroundFetchRequestMatchParams>(
request_to_match, std::move(cache_query_params), match_all);
background_fetch_data_manager_->GetSettledFetchesForRegistration(
background_fetch_data_manager_->MatchRequests(
registration_id, std::move(match_params),
base::BindOnce(&BackgroundFetchDataManagerTest::
DidGetSettledFetchesForRegistration,
base::BindOnce(&BackgroundFetchDataManagerTest::DidMatchRequests,
base::Unretained(this), run_loop.QuitClosure(),
out_error, out_failure_reason, out_settled_fetches));
out_error, out_settled_fetches));
run_loop.Run();
}
@ -643,19 +650,25 @@ class BackgroundFetchDataManagerTest
std::move(quit_closure).Run();
}
void DidGetSettledFetchesForRegistration(
void DidMarkRegistrationForDeletion(
base::OnceClosure quit_closure,
blink::mojom::BackgroundFetchError* out_error,
blink::mojom::BackgroundFetchFailureReason* out_failure_reason,
std::vector<BackgroundFetchSettledFetch>* out_settled_fetches,
blink::mojom::BackgroundFetchError error,
blink::mojom::BackgroundFetchFailureReason failure_reason,
std::vector<BackgroundFetchSettledFetch> settled_fetches,
std::vector<std::unique_ptr<storage::BlobDataHandle>>) {
blink::mojom::BackgroundFetchFailureReason failure_reason) {
*out_error = error;
*out_failure_reason = failure_reason;
*out_settled_fetches = std::move(settled_fetches);
std::move(quit_closure).Run();
}
void DidMatchRequests(
base::OnceClosure quit_closure,
blink::mojom::BackgroundFetchError* out_error,
std::vector<BackgroundFetchSettledFetch>* out_settled_fetches,
blink::mojom::BackgroundFetchError error,
std::vector<BackgroundFetchSettledFetch> settled_fetches) {
*out_error = error;
*out_settled_fetches = std::move(settled_fetches);
std::move(quit_closure).Run();
}
@ -672,12 +685,9 @@ class BackgroundFetchDataManagerTest
bool* out_result,
blink::mojom::CacheStorageError error,
blink::mojom::FetchAPIResponsePtr response) {
if (error == blink::mojom::CacheStorageError::kSuccess) {
DCHECK(response);
*out_result = true;
} else {
*out_result = false;
}
// This counts as matched if an entry was found in the cache which
// also has a non-empty response.
*out_result = !response.is_null() && !response->url_list.empty();
std::move(quit_closure).Run();
}
@ -714,13 +724,16 @@ TEST_F(BackgroundFetchDataManagerTest, NoDuplicateRegistrations) {
origin(), kExampleDeveloperId,
kExampleUniqueId);
std::vector<ServiceWorkerFetchRequest> requests;
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin());
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
blink::mojom::BackgroundFetchFailureReason failure_reason;
// Deactivating the not-yet-created registration should fail.
MarkRegistrationForDeletion(registration_id1, &error);
MarkRegistrationForDeletion(registration_id1, /* check_for_failure= */ true,
&error, &failure_reason);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID);
// Creating the initial registration should succeed.
@ -743,11 +756,13 @@ TEST_F(BackgroundFetchDataManagerTest, NoDuplicateRegistrations) {
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::DUPLICATED_DEVELOPER_ID);
// Deactivating the second registration that failed to be created should fail.
MarkRegistrationForDeletion(registration_id2, &error);
MarkRegistrationForDeletion(registration_id2, /* check_for_failure= */ true,
&error, &failure_reason);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID);
// Deactivating the initial registration should succeed.
MarkRegistrationForDeletion(registration_id1, &error);
MarkRegistrationForDeletion(registration_id1, /* check_for_failure= */ true,
&error, &failure_reason);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
// And now registering the second registration should work fine, since there
@ -772,7 +787,8 @@ TEST_F(BackgroundFetchDataManagerTest, ExceedingQuotaFailsCreation) {
BackgroundFetchRegistrationId registration_id(service_worker_registration_id,
origin(), kExampleDeveloperId,
kExampleUniqueId);
std::vector<ServiceWorkerFetchRequest> requests;
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin());
BackgroundFetchOptions options;
options.download_total = kBackgroundFetchMaxQuotaBytes + 1;
@ -853,7 +869,8 @@ TEST_F(BackgroundFetchDataManagerTest, GetDeveloperIds) {
int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
std::vector<ServiceWorkerFetchRequest> requests(2u);
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin(), 2u);
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
@ -914,7 +931,8 @@ TEST_F(BackgroundFetchDataManagerTest, GetRegistration) {
BackgroundFetchRegistrationId registration_id(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
std::vector<ServiceWorkerFetchRequest> requests(2u);
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin(), 2u);
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
@ -956,7 +974,8 @@ TEST_F(BackgroundFetchDataManagerTest, GetMetadata) {
BackgroundFetchRegistrationId registration_id(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
std::vector<ServiceWorkerFetchRequest> requests(2u);
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin(), 2u);
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
@ -991,7 +1010,8 @@ TEST_F(BackgroundFetchDataManagerTest, LargeIconNotPersisted) {
BackgroundFetchRegistrationId registration_id(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
std::vector<ServiceWorkerFetchRequest> requests(2u);
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin(), 2u);
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
@ -1022,7 +1042,8 @@ TEST_F(BackgroundFetchDataManagerTest, UpdateRegistrationUI) {
BackgroundFetchRegistrationId registration_id(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
std::vector<ServiceWorkerFetchRequest> requests(2u);
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin(), 2u);
BackgroundFetchOptions options;
options.title = kInitialTitle;
blink::mojom::BackgroundFetchError error;
@ -1124,9 +1145,11 @@ TEST_F(BackgroundFetchDataManagerTest, CreateAndDeleteRegistration) {
BackgroundFetchRegistrationId registration_id1(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
std::vector<ServiceWorkerFetchRequest> requests(2u);
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin(), 2u);
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
blink::mojom::BackgroundFetchFailureReason failure_reason;
{
EXPECT_CALL(*this, OnRegistrationCreated(registration_id1, _, _, _, _, _));
@ -1157,8 +1180,10 @@ TEST_F(BackgroundFetchDataManagerTest, CreateAndDeleteRegistration) {
EXPECT_EQ(kExampleDeveloperId, registration.developer_id);
// Deactivating the registration should succeed.
MarkRegistrationForDeletion(registration_id1, &error);
MarkRegistrationForDeletion(registration_id1, /* check_for_failure= */ true,
&error, &failure_reason);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(failure_reason, blink::mojom::BackgroundFetchFailureReason::NONE);
// Verify that the registration cannot be retrieved after deletion
registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
@ -1196,9 +1221,11 @@ TEST_F(BackgroundFetchDataManagerTest, MarkRegistrationForDeletion) {
BackgroundFetchRegistrationId registration_id1(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
std::vector<ServiceWorkerFetchRequest> requests(2u);
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin(), 2u);
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
blink::mojom::BackgroundFetchFailureReason failure_reason;
CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
@ -1219,8 +1246,10 @@ TEST_F(BackgroundFetchDataManagerTest, MarkRegistrationForDeletion) {
}
// Deactivate the first registration.
MarkRegistrationForDeletion(registration_id1, &error);
MarkRegistrationForDeletion(registration_id1, /* check_for_failure= */ true,
&error, &failure_reason);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(failure_reason, blink::mojom::BackgroundFetchFailureReason::NONE);
// The second registration should still exist.
{
@ -1231,6 +1260,63 @@ TEST_F(BackgroundFetchDataManagerTest, MarkRegistrationForDeletion) {
}
}
TEST_F(BackgroundFetchDataManagerTest,
MarkRegistrationForDeletionFailureReason) {
int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
BackgroundFetchRegistrationId registration_id1(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin(), 1u);
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
blink::mojom::BackgroundFetchFailureReason failure_reason;
// Complete the fetch successfully.
{
CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
scoped_refptr<BackgroundFetchRequestInfo> request_info;
PopNextRequest(registration_id1, &error, &request_info);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(),
/* succeeded= */ true);
MarkRequestAsComplete(registration_id1, request_info.get(), &error);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
// Mark the Registration for deletion.
MarkRegistrationForDeletion(registration_id1, /* check_for_failure= */ true,
&error, &failure_reason);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(failure_reason, blink::mojom::BackgroundFetchFailureReason::NONE);
}
BackgroundFetchRegistrationId registration_id2(
sw_id, origin(), kAlternativeDeveloperId, kAlternativeUniqueId);
// Complete the fetch with a BAD_STATUS.
{
CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
scoped_refptr<BackgroundFetchRequestInfo> request_info;
PopNextRequest(registration_id2, &error, &request_info);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get());
MarkRequestAsComplete(registration_id2, request_info.get(), &error);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
// Mark the Registration for deletion.
MarkRegistrationForDeletion(registration_id2, /* check_for_failure= */ true,
&error, &failure_reason);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
// The fetch resulted in a 404.
EXPECT_EQ(failure_reason,
blink::mojom::BackgroundFetchFailureReason::BAD_STATUS);
}
}
TEST_F(BackgroundFetchDataManagerTest, PopNextRequestAndMarkAsComplete) {
int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
@ -1251,7 +1337,8 @@ TEST_F(BackgroundFetchDataManagerTest, PopNextRequestAndMarkAsComplete) {
(ResponseStateStats{0 /* pending_requests */, 0 /* active_requests */,
0 /* completed_requests */}));
std::vector<ServiceWorkerFetchRequest> requests(2u);
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin(), 2u);
BackgroundFetchOptions options;
{
@ -1465,6 +1552,7 @@ TEST_F(BackgroundFetchDataManagerTest, CacheDeleted) {
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
blink::mojom::BackgroundFetchFailureReason failure_reason;
{
EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _, _));
@ -1485,7 +1573,8 @@ TEST_F(BackgroundFetchDataManagerTest, CacheDeleted) {
EXPECT_TRUE(HasCache(kExampleUniqueId));
EXPECT_TRUE(MatchCache(request));
MarkRegistrationForDeletion(registration_id, &error);
MarkRegistrationForDeletion(registration_id, /* check_for_failure= */ true,
&error, &failure_reason);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
DeleteRegistration(registration_id, &error);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
@ -1493,7 +1582,7 @@ TEST_F(BackgroundFetchDataManagerTest, CacheDeleted) {
EXPECT_FALSE(HasCache(kExampleUniqueId));
}
TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesForRegistration) {
TEST_F(BackgroundFetchDataManagerTest, MatchRequests) {
int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
@ -1517,15 +1606,12 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesForRegistration) {
0 /* completed_requests */}));
// Nothing is downloaded yet.
blink::mojom::BackgroundFetchFailureReason failure_reason;
std::vector<BackgroundFetchSettledFetch> settled_fetches;
GetSettledFetchesForRegistration(
registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&failure_reason, &settled_fetches);
MatchRequests(registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, true /* match_all */, &error,
&settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(failure_reason, blink::mojom::BackgroundFetchFailureReason::NONE);
EXPECT_EQ(settled_fetches.size(), 0u);
EXPECT_EQ(settled_fetches.size(), requests.size());
for (size_t i = 0; i < requests.size(); i++) {
scoped_refptr<BackgroundFetchRequestInfo> request_info;
@ -1544,19 +1630,16 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesForRegistration) {
(ResponseStateStats{0 /* pending_requests */, 0 /* active_requests */,
requests.size() /* completed_requests */}));
GetSettledFetchesForRegistration(
registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&failure_reason, &settled_fetches);
MatchRequests(registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, true /* match_all */, &error,
&settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
// We are marking the responses as failed in Download Manager.
EXPECT_EQ(failure_reason,
blink::mojom::BackgroundFetchFailureReason::BAD_STATUS);
EXPECT_EQ(settled_fetches.size(), requests.size());
}
TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) {
TEST_F(BackgroundFetchDataManagerTest, MatchRequestsFromCache) {
int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
@ -1573,16 +1656,13 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) {
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
}
blink::mojom::BackgroundFetchFailureReason failure_reason;
std::vector<BackgroundFetchSettledFetch> settled_fetches;
// Nothing is downloaded yet.
GetSettledFetchesForRegistration(
registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&failure_reason, &settled_fetches);
MatchRequests(registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, true /* match_all */, &error,
&settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(failure_reason, blink::mojom::BackgroundFetchFailureReason::NONE);
EXPECT_EQ(settled_fetches.size(), 0u);
EXPECT_EQ(settled_fetches.size(), requests.size());
scoped_refptr<BackgroundFetchRequestInfo> request_info;
PopNextRequest(registration_id, &error, &request_info);
@ -1593,12 +1673,10 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) {
MarkRequestAsComplete(registration_id, request_info.get(), &error);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
GetSettledFetchesForRegistration(
registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&failure_reason, &settled_fetches);
MatchRequests(registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(failure_reason, blink::mojom::BackgroundFetchFailureReason::NONE);
EXPECT_EQ(settled_fetches.size(), 1u);
PopNextRequest(registration_id, &error, &request_info);
@ -1609,13 +1687,11 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) {
MarkRequestAsComplete(registration_id, request_info.get(), &error);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
GetSettledFetchesForRegistration(
registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&failure_reason, &settled_fetches);
MatchRequests(registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, true /* match_all */, &error,
&settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(failure_reason, blink::mojom::BackgroundFetchFailureReason::NONE);
ASSERT_EQ(settled_fetches.size(), 2u);
ASSERT_EQ(settled_fetches.size(), requests.size());
// Sanity check that the responses are written to / read from the cache.
EXPECT_TRUE(MatchCache(requests[0]));
@ -1627,16 +1703,14 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) {
RestartDataManagerFromPersistentStorage();
GetSettledFetchesForRegistration(
registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&failure_reason, &settled_fetches);
MatchRequests(registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, true /* match_all */, &error,
&settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(failure_reason, blink::mojom::BackgroundFetchFailureReason::NONE);
EXPECT_EQ(settled_fetches.size(), 2u);
EXPECT_EQ(settled_fetches.size(), requests.size());
}
TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesForASpecificRequest) {
TEST_F(BackgroundFetchDataManagerTest, MatchRequestsForASpecificRequest) {
int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
@ -1669,22 +1743,24 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesForASpecificRequest) {
(ResponseStateStats{0 /* pending_requests */, 0 /* active_requests */,
requests.size() /* completed_requests */}));
blink::mojom::BackgroundFetchFailureReason failure_reason;
std::vector<BackgroundFetchSettledFetch> settled_fetches;
GetSettledFetchesForRegistration(
registration_id, requests[0] /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&failure_reason, &settled_fetches);
MatchRequests(registration_id, requests[0] /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&settled_fetches);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
// We are marking the responses as failed in Download Manager.
EXPECT_EQ(failure_reason,
blink::mojom::BackgroundFetchFailureReason::BAD_STATUS);
EXPECT_EQ(settled_fetches.size(), 1u);
// Try matching a non existing request.
ServiceWorkerFetchRequest non_existing_request;
non_existing_request.url = GURL("https://example.com/missing-file.txt");
MatchRequests(registration_id, non_existing_request /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&settled_fetches);
EXPECT_TRUE(settled_fetches.empty());
}
TEST_F(BackgroundFetchDataManagerTest,
GetSettledFetchesForANonMatchingRequest) {
TEST_F(BackgroundFetchDataManagerTest, MatchRequestsForAnIncompleteRequest) {
int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
@ -1717,16 +1793,13 @@ TEST_F(BackgroundFetchDataManagerTest,
(ResponseStateStats{1 /* pending_requests */, 0 /* active_requests */,
requests.size() - 1 /* completed_requests */}));
blink::mojom::BackgroundFetchFailureReason failure_reason;
std::vector<BackgroundFetchSettledFetch> settled_fetches;
GetSettledFetchesForRegistration(
registration_id, requests[2] /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&failure_reason, &settled_fetches);
MatchRequests(registration_id, requests[2] /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&settled_fetches);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(settled_fetches.size(), 1u);
EXPECT_EQ(settled_fetches[0].response->response_type,
network::mojom::FetchResponseType::kError);
ASSERT_EQ(settled_fetches.size(), 1u);
EXPECT_TRUE(settled_fetches[0].response.is_null());
}
TEST_F(BackgroundFetchDataManagerTest, IgnoreMethodAndMatchAll) {
@ -1765,20 +1838,15 @@ TEST_F(BackgroundFetchDataManagerTest, IgnoreMethodAndMatchAll) {
(ResponseStateStats{0 /* pending_requests */, 0 /* active_requests */,
requests.size() /* completed_requests */}));
blink::mojom::BackgroundFetchFailureReason failure_reason;
std::vector<BackgroundFetchSettledFetch> settled_fetches;
blink::mojom::QueryParamsPtr cache_query_params =
blink::mojom::QueryParams::New();
cache_query_params->ignore_method = true;
GetSettledFetchesForRegistration(
registration_id, requests[0] /* request_to_match */,
std::move(cache_query_params), true /* match_all */, &error,
&failure_reason, &settled_fetches);
MatchRequests(registration_id, requests[0] /* request_to_match */,
std::move(cache_query_params), true /* match_all */, &error,
&settled_fetches);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
// We are marking the responses as failed in Download Manager.
EXPECT_EQ(failure_reason,
blink::mojom::BackgroundFetchFailureReason::BAD_STATUS);
// If the ASSERT below fails, the Cache Storage API implementation has likely
// changed to distinguish keys by request data other than just the URL.
// Thank you! Please can you update the 1u below to 2u, or file a bug against
@ -1795,10 +1863,11 @@ TEST_F(BackgroundFetchDataManagerTest, Cleanup) {
BackgroundFetchRegistrationId registration_id(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
// The requests are default-initialized, but valid.
std::vector<ServiceWorkerFetchRequest> requests(2u);
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin(), 2u);
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
blink::mojom::BackgroundFetchFailureReason failure_reason;
EXPECT_EQ(0u,
GetRegistrationUserDataByKeyPrefix(sw_id, kUserDataPrefix).size());
@ -1817,7 +1886,8 @@ TEST_F(BackgroundFetchDataManagerTest, Cleanup) {
.size());
// And deactivate it.
MarkRegistrationForDeletion(registration_id, &error);
MarkRegistrationForDeletion(registration_id, /* check_for_failure= */ true,
&error, &failure_reason);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
RestartDataManagerFromPersistentStorage();
@ -1855,7 +1925,8 @@ TEST_F(BackgroundFetchDataManagerTest, GetInitializationData) {
EXPECT_TRUE(data.empty());
}
std::vector<ServiceWorkerFetchRequest> requests(2u);
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin(), 2u);
BackgroundFetchOptions options;
options.title = kInitialTitle;
options.download_total = 42u;
@ -1952,7 +2023,8 @@ TEST_F(BackgroundFetchDataManagerTest, CreateInParallel) {
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
service_worker_registration_id);
std::vector<ServiceWorkerFetchRequest> requests;
std::vector<ServiceWorkerFetchRequest> requests =
CreateValidRequests(origin());
BackgroundFetchOptions options;
std::vector<blink::mojom::BackgroundFetchError> errors(5);
@ -2041,34 +2113,32 @@ TEST_F(BackgroundFetchDataManagerTest, StorageErrorsReported) {
MarkRequestAsComplete(registration_id, request_info.get(), &error);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
blink::mojom::BackgroundFetchFailureReason failure_reason;
std::vector<BackgroundFetchSettledFetch> settled_fetches;
{
GetSettledFetchesForRegistration(
registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&failure_reason, &settled_fetches);
MatchRequests(registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */,
&error, &settled_fetches);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
}
// Delete an expected entry to get a CachStorageError.
EXPECT_TRUE(MatchCache(requests[0]));
DeleteFromCache(requests[0]);
ASSERT_FALSE(MatchCache(requests[0]));
// Delete all entries to get a CachStorageError.
for (const auto& request : requests) {
DeleteFromCache(request);
ASSERT_FALSE(MatchCache(request));
}
{
base::HistogramTester histogram_tester;
GetSettledFetchesForRegistration(
registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, false /* match_all */, &error,
&failure_reason, &settled_fetches);
MatchRequests(registration_id, base::nullopt /* request_to_match */,
nullptr /* cache_query_params */, true /* match_all */,
&error, &settled_fetches);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::STORAGE_ERROR);
histogram_tester.ExpectBucketCount(
"BackgroundFetch.Storage.GetSettledFetchesTask",
2 /* kCacheStorageError */, 1);
"BackgroundFetch.Storage.MatchRequestsTask", 2 /* kCacheStorageError */,
1);
}
}

@ -326,6 +326,12 @@ class BackgroundFetchServiceTest : public BackgroundFetchTestBase {
}
protected:
ServiceWorkerFetchRequest CreateDefaultRequest() {
return CreateRequestWithProvidedResponse(
"GET", GURL("https://example.com/funny_cat.txt"),
TestResponseBuilder(200).MakeIndefinitelyPending().Build());
}
scoped_refptr<BackgroundFetchContext> context_;
private:
@ -391,8 +397,7 @@ TEST_F(BackgroundFetchServiceTest, FetchInvalidArguments) {
// The |developer_id| must be a non-empty string.
{
BadMessageObserver bad_message_observer;
std::vector<ServiceWorkerFetchRequest> requests;
requests.emplace_back(); // empty, but valid
std::vector<ServiceWorkerFetchRequest> requests = {CreateDefaultRequest()};
blink::mojom::BackgroundFetchError error;
BackgroundFetchRegistration registration;
@ -428,8 +433,7 @@ TEST_F(BackgroundFetchServiceTest, FetchRegistrationProperties) {
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
service_worker_registration_id);
std::vector<ServiceWorkerFetchRequest> requests;
requests.emplace_back(); // empty, but valid
std::vector<ServiceWorkerFetchRequest> requests = {CreateDefaultRequest()};
BackgroundFetchOptions options;
options.icons.push_back(
@ -473,8 +477,7 @@ TEST_F(BackgroundFetchServiceTest, FetchDuplicatedRegistrationFailure) {
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
service_worker_registration_id);
std::vector<ServiceWorkerFetchRequest> requests;
requests.emplace_back(); // empty, but valid
std::vector<ServiceWorkerFetchRequest> requests = {CreateDefaultRequest()};
BackgroundFetchOptions options;
@ -668,23 +671,26 @@ TEST_F(BackgroundFetchServiceTest, FetchFailEventDispatch) {
std::vector<BackgroundFetchSettledFetch> fetches;
MatchAllRequests(service_worker_registration_id, registration.developer_id,
registration.unique_id, &fetches);
ASSERT_EQ(fetches.size(), requests.size());
ASSERT_EQ(fetches.size(), 2u);
// Make sure the 404 request is first, which has a response.
if (!fetches[0].response)
std::swap(fetches[0], fetches[1]);
for (size_t i = 0; i < fetches.size(); ++i) {
ASSERT_EQ(fetches[i].request.url, requests[i].url);
EXPECT_EQ(fetches[i].request.method, requests[i].method);
EXPECT_EQ(fetches[i].response->url_list[0], fetches[i].request.url);
EXPECT_EQ(fetches[i].response->response_type,
network::mojom::FetchResponseType::kDefault);
switch (i) {
case 0:
EXPECT_EQ(fetches[i].response->status_code, 404);
EXPECT_EQ(fetches[i].response->url_list[0], fetches[i].request.url);
EXPECT_EQ(fetches[i].response->response_type,
network::mojom::FetchResponseType::kDefault);
break;
case 1:
EXPECT_EQ(fetches[i].response->status_code, 0);
break;
EXPECT_FALSE(fetches[i].response);
continue;
default:
NOTREACHED();
}
@ -711,8 +717,7 @@ TEST_F(BackgroundFetchServiceTest, UpdateUI) {
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
service_worker_registration_id);
std::vector<ServiceWorkerFetchRequest> requests;
requests.emplace_back(); // empty, but valid
std::vector<ServiceWorkerFetchRequest> requests = {CreateDefaultRequest()};
BackgroundFetchOptions options;
options.title = "1st title";
@ -750,8 +755,7 @@ TEST_F(BackgroundFetchServiceTest, Abort) {
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
service_worker_registration_id);
std::vector<ServiceWorkerFetchRequest> requests;
requests.emplace_back(); // empty, but valid
std::vector<ServiceWorkerFetchRequest> requests = {CreateDefaultRequest()};
BackgroundFetchOptions options;
@ -887,8 +891,7 @@ TEST_F(BackgroundFetchServiceTest, UniqueId) {
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
service_worker_registration_id);
std::vector<ServiceWorkerFetchRequest> requests;
requests.emplace_back(); // empty, but valid
std::vector<ServiceWorkerFetchRequest> requests = {CreateDefaultRequest()};
blink::mojom::BackgroundFetchError error;
@ -994,8 +997,7 @@ TEST_F(BackgroundFetchServiceTest, GetDeveloperIds) {
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
service_worker_registration_id);
std::vector<ServiceWorkerFetchRequest> requests;
requests.emplace_back(); // empty, but valid
std::vector<ServiceWorkerFetchRequest> requests = {CreateDefaultRequest()};
BackgroundFetchOptions options;

@ -13,6 +13,7 @@
#include "content/public/browser/background_fetch_response.h"
#include "content/public/browser/browser_thread.h"
#include "net/http/http_response_headers.h"
#include "services/network/public/cpp/cors/cors.h"
namespace content {
@ -23,7 +24,7 @@ MockBackgroundFetchDelegate::TestResponse::~TestResponse() = default;
MockBackgroundFetchDelegate::TestResponseBuilder::TestResponseBuilder(
int response_code)
: response_(std::make_unique<TestResponse>()) {
response_->succeeded_ = (response_code >= 200 && response_code < 300);
response_->succeeded = network::cors::IsOkStatus(response_code);
response_->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
"HTTP/1.1 " + std::to_string(response_code));
}
@ -48,6 +49,12 @@ MockBackgroundFetchDelegate::TestResponseBuilder::SetResponseData(
return *this;
}
MockBackgroundFetchDelegate::TestResponseBuilder&
MockBackgroundFetchDelegate::TestResponseBuilder::MakeIndefinitelyPending() {
response_->pending = true;
return *this;
}
std::unique_ptr<MockBackgroundFetchDelegate::TestResponse>
MockBackgroundFetchDelegate::TestResponseBuilder::Build() {
return std::move(response_);
@ -95,6 +102,9 @@ void MockBackgroundFetchDelegate::DownloadUrl(
std::unique_ptr<TestResponse> test_response = std::move(url_iter->second);
url_responses_.erase(url_iter);
if (test_response->pending)
return;
PostAbortCheckingTask(
job_unique_id,
base::BindOnce(&BackgroundFetchDelegate::Client::OnDownloadStarted,
@ -118,7 +128,7 @@ void MockBackgroundFetchDelegate::DownloadUrl(
test_response->data.size()));
}
if (test_response->succeeded_) {
if (test_response->succeeded) {
base::FilePath response_path;
if (!temp_directory_.IsValid()) {
CHECK(temp_directory_.CreateUniqueTempDir());

@ -31,7 +31,8 @@ class MockBackgroundFetchDelegate : public BackgroundFetchDelegate {
TestResponse();
~TestResponse();
bool succeeded_;
bool succeeded = false;
bool pending = false;
scoped_refptr<net::HttpResponseHeaders> headers;
std::string data;
@ -52,6 +53,8 @@ class MockBackgroundFetchDelegate : public BackgroundFetchDelegate {
TestResponseBuilder& SetResponseData(std::string data);
TestResponseBuilder& MakeIndefinitelyPending();
// Finalizes the builder and invalidates the underlying response.
std::unique_ptr<TestResponse> Build();

@ -14,6 +14,7 @@
#include "content/browser/background_fetch/background_fetch_data_manager_observer.h"
#include "content/browser/background_fetch/storage/database_helpers.h"
#include "content/browser/background_fetch/storage/image_helpers.h"
#include "content/browser/background_fetch/storage/mark_registration_for_deletion_task.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
@ -343,6 +344,54 @@ void CreateMetadataTask::DidStoreMetadata(
return;
}
// Create cache entries.
cache_manager()->OpenCache(registration_id_.origin(),
CacheStorageOwner::kBackgroundFetch,
registration_id_.unique_id() /* cache_name */,
base::BindOnce(&CreateMetadataTask::DidOpenCache,
weak_factory_.GetWeakPtr()));
}
void CreateMetadataTask::DidOpenCache(CacheStorageCacheHandle handle,
blink::mojom::CacheStorageError error) {
if (error != blink::mojom::CacheStorageError::kSuccess) {
SetStorageErrorAndFinish(BackgroundFetchStorageError::kCacheStorageError);
return;
}
DCHECK(handle.value());
// Create batch PUT operations instead of putting them one-by-one.
std::vector<blink::mojom::BatchOperationPtr> operations;
operations.reserve(requests_.size());
for (auto& request : requests_) {
auto operation = blink::mojom::BatchOperation::New();
operation->operation_type = blink::mojom::OperationType::kPut;
operation->request = std::move(request);
// Empty response.
operation->response = blink::mojom::FetchAPIResponse::New();
operations.push_back(std::move(operation));
}
handle.value()->BatchOperation(
std::move(operations), /* fail_on_duplicates= */ false,
base::BindOnce(&CreateMetadataTask::DidStoreRequests,
weak_factory_.GetWeakPtr(), handle.Clone()),
base::DoNothing());
}
void CreateMetadataTask::DidStoreRequests(
CacheStorageCacheHandle handle,
blink::mojom::CacheStorageVerboseErrorPtr error) {
if (error->value != blink::mojom::CacheStorageError::kSuccess) {
// Delete the metadata in the SWDB.
AddDatabaseTask(std::make_unique<MarkRegistrationForDeletionTask>(
data_manager(), registration_id_, /* check_for_failure= */ false,
base::DoNothing()));
SetStorageErrorAndFinish(BackgroundFetchStorageError::kCacheStorageError);
return;
}
FinishWithError(blink::mojom::BackgroundFetchError::NONE);
}

@ -11,6 +11,7 @@
#include "content/browser/background_fetch/background_fetch.pb.h"
#include "content/browser/background_fetch/storage/database_task.h"
#include "content/browser/cache_storage/cache_storage_cache_handle.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
@ -21,7 +22,8 @@ struct BackgroundFetchRegistration;
namespace background_fetch {
// Creates Background Fetch metadata entries in the database.
// Checks if the registration can be created, then writes the Background
// Fetch metadata in the SW database with corresponding entries in the cache.
class CreateMetadataTask : public DatabaseTask {
public:
using CreateMetadataCallback =
@ -59,6 +61,12 @@ class CreateMetadataTask : public DatabaseTask {
void InitializeMetadataProto();
void DidOpenCache(CacheStorageCacheHandle handle,
blink::mojom::CacheStorageError error);
void DidStoreRequests(CacheStorageCacheHandle handle,
blink::mojom::CacheStorageVerboseErrorPtr error);
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
std::string HistogramName() const override;

@ -500,7 +500,8 @@ void GetInitializationDataTask::FinishWithError(
// TODO(crbug.com/865388): Getting the Developer ID should be possible
// since it is part of the key for when we got the Unique ID.
AddDatabaseTask(std::make_unique<MarkRegistrationForDeletionTask>(
data_manager(), data.second.registration_id, base::DoNothing()));
data_manager(), data.second.registration_id,
/* check_for_failure= */ false, base::DoNothing()));
}
if (data.second.error ==

@ -1,284 +0,0 @@
// Copyright 2018 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/background_fetch/storage/get_settled_fetches_task.h"
#include "base/barrier_closure.h"
#include "content/browser/background_fetch/background_fetch_data_manager.h"
#include "content/browser/background_fetch/storage/database_helpers.h"
#include "content/browser/cache_storage/cache_storage_manager.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "services/network/public/cpp/cors/cors.h"
namespace content {
namespace background_fetch {
GetSettledFetchesTask::GetSettledFetchesTask(
DatabaseTaskHost* host,
BackgroundFetchRegistrationId registration_id,
std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
SettledFetchesCallback callback)
: DatabaseTask(host),
registration_id_(registration_id),
match_params_(std::move(match_params)),
settled_fetches_callback_(std::move(callback)),
weak_factory_(this) {}
GetSettledFetchesTask::~GetSettledFetchesTask() = default;
void GetSettledFetchesTask::Start() {
base::RepeatingClosure barrier_closure = base::BarrierClosure(
2u, base::BindOnce(&GetSettledFetchesTask::GetResponses,
weak_factory_.GetWeakPtr()));
cache_manager()->OpenCache(
registration_id_.origin(), CacheStorageOwner::kBackgroundFetch,
registration_id_.unique_id() /* cache_name */,
base::BindOnce(&GetSettledFetchesTask::DidOpenCache,
weak_factory_.GetWeakPtr(), barrier_closure));
service_worker_context()->GetRegistrationUserDataByKeyPrefix(
registration_id_.service_worker_registration_id(),
{CompletedRequestKeyPrefix(registration_id_.unique_id())},
base::BindOnce(&GetSettledFetchesTask::DidGetCompletedRequests,
weak_factory_.GetWeakPtr(), barrier_closure));
}
void GetSettledFetchesTask::DidOpenCache(
base::OnceClosure done_closure,
CacheStorageCacheHandle handle,
blink::mojom::CacheStorageError error) {
if (error != blink::mojom::CacheStorageError::kSuccess) {
SetStorageError(BackgroundFetchStorageError::kCacheStorageError);
} else {
DCHECK(handle.value());
handle_ = std::move(handle);
}
std::move(done_closure).Run();
}
void GetSettledFetchesTask::DidGetCompletedRequests(
base::OnceClosure done_closure,
const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kOk:
break;
case DatabaseStatus::kFailed:
SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError);
break;
case DatabaseStatus::kNotFound:
failure_reason_ = blink::mojom::BackgroundFetchFailureReason::FETCH_ERROR;
error_ = blink::mojom::BackgroundFetchError::INVALID_ID;
break;
}
completed_requests_.reserve(data.size());
for (const std::string& serialized_completed_request : data) {
completed_requests_.emplace_back();
if (!completed_requests_.back().ParseFromString(
serialized_completed_request)) {
// Service worker database has been corrupted. Abandon fetches.
SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError);
failure_reason_ = blink::mojom::BackgroundFetchFailureReason::
SERVICE_WORKER_UNAVAILABLE;
AbandonFetches(registration_id_.service_worker_registration_id());
break;
}
}
std::move(done_closure).Run();
}
void GetSettledFetchesTask::GetResponses() {
// Handle potential errors.
if (HasStorageError()) {
FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
return;
}
if (error_ != blink::mojom::BackgroundFetchError::NONE) {
FinishWithError(error_);
return;
}
if (completed_requests_.empty()) {
FinishWithError(blink::mojom::BackgroundFetchError::NONE);
return;
}
if (!match_params_->FilterByRequest()) {
// No request to match against has been specified. Process all completed
// requests.
// TODO(crbug.com/863016): Process all requests here, not just the
// completed ones.
base::RepeatingClosure barrier_closure = base::BarrierClosure(
completed_requests_.size(),
base::BindOnce(&GetSettledFetchesTask::FinishWithError,
weak_factory_.GetWeakPtr(),
blink::mojom::BackgroundFetchError::NONE));
settled_fetches_.reserve(completed_requests_.size());
for (const auto& completed_request : completed_requests_) {
settled_fetches_.emplace_back();
settled_fetches_.back().request =
ServiceWorkerUtils::DeserializeFetchRequestFromString(
completed_request.serialized_request());
FillResponse(&settled_fetches_.back(), barrier_closure);
}
return;
}
// Get response(s) only for the relevant fetch.
settled_fetches_.emplace_back();
settled_fetches_.back().request = match_params_->request_to_match();
if (match_params_->match_all()) {
FillResponses(base::BindOnce(&GetSettledFetchesTask::FinishWithError,
weak_factory_.GetWeakPtr(),
blink::mojom::BackgroundFetchError::NONE));
return;
} else {
FillResponse(&settled_fetches_.back(),
base::BindOnce(&GetSettledFetchesTask::FinishWithError,
weak_factory_.GetWeakPtr(),
blink::mojom::BackgroundFetchError::NONE));
return;
}
}
void GetSettledFetchesTask::FillResponse(
BackgroundFetchSettledFetch* settled_fetch,
base::OnceClosure callback) {
DCHECK(settled_fetch);
DCHECK(handle_.value());
auto request =
std::make_unique<ServiceWorkerFetchRequest>(settled_fetch->request);
handle_.value()->Match(std::move(request),
match_params_->cloned_cache_query_params(),
base::BindOnce(&GetSettledFetchesTask::DidMatchRequest,
weak_factory_.GetWeakPtr(),
settled_fetch, std::move(callback)));
}
void GetSettledFetchesTask::FillResponses(base::OnceClosure callback) {
DCHECK(match_params_->match_all());
DCHECK(match_params_->FilterByRequest());
DCHECK(!settled_fetches_.empty());
DCHECK(handle_.value());
// Make a copy.
auto request = std::make_unique<ServiceWorkerFetchRequest>(
match_params_->request_to_match());
handle_.value()->MatchAll(
std::move(request), match_params_->cloned_cache_query_params(),
base::BindOnce(&GetSettledFetchesTask::DidMatchAllResponsesForRequest,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void GetSettledFetchesTask::DidMatchRequest(
BackgroundFetchSettledFetch* settled_fetch,
base::OnceClosure callback,
blink::mojom::CacheStorageError error,
blink::mojom::FetchAPIResponsePtr cache_response) {
DCHECK(settled_fetch);
// Handle error cases.
if (error == blink::mojom::CacheStorageError::kErrorNotFound) {
// This is currently being called once a fetch finishes, or when match() is
// called.
// In the first case, not finding a response is an error state. In the
// second case, it just means the developer passed a non-matching request.
// The if condition below picks the first one.
// TODO(crbug.com/863016): Once we stop sending settled_fetches with
// BackgroundFetch events, this won't be a storage error.
if (!match_params_->FilterByRequest())
SetStorageError(BackgroundFetchStorageError::kCacheStorageError);
} else if (error != blink::mojom::CacheStorageError::kSuccess) {
SetStorageError(BackgroundFetchStorageError::kCacheStorageError);
}
if (!cache_response) {
FillUncachedResponse(settled_fetch, std::move(callback));
return;
}
settled_fetch->response = std::move(cache_response);
std::move(callback).Run();
}
void GetSettledFetchesTask::DidMatchAllResponsesForRequest(
base::OnceClosure callback,
blink::mojom::CacheStorageError error,
std::vector<blink::mojom::FetchAPIResponsePtr> cache_responses) {
if (error != blink::mojom::CacheStorageError::kSuccess &&
error != blink::mojom::CacheStorageError::kErrorNotFound) {
SetStorageError(BackgroundFetchStorageError::kCacheStorageError);
}
if (error != blink::mojom::CacheStorageError::kSuccess) {
DCHECK(!settled_fetches_.empty());
FillUncachedResponse(&settled_fetches_.back(), std::move(callback));
return;
}
settled_fetches_.clear();
settled_fetches_.reserve(cache_responses.size());
for (size_t i = 0; i < cache_responses.size(); ++i) {
settled_fetches_.emplace_back();
settled_fetches_.back().request = match_params_->request_to_match();
settled_fetches_.back().response = std::move(cache_responses[i]);
}
std::move(callback).Run();
}
// TODO(crbug.com/863016): Get rid of this method.
void GetSettledFetchesTask::FillUncachedResponse(
BackgroundFetchSettledFetch* settled_fetch,
base::OnceClosure callback) {
failure_reason_ = blink::mojom::BackgroundFetchFailureReason::FETCH_ERROR;
// TODO(rayankans): Fill unmatched response with error reports.
DCHECK(!settled_fetch->response);
settled_fetch->response = blink::mojom::FetchAPIResponse::New();
settled_fetch->response->response_type =
network::mojom::FetchResponseType::kError;
settled_fetch->response->url_list.push_back(settled_fetch->request.url);
std::move(callback).Run();
}
void GetSettledFetchesTask::FinishWithError(
blink::mojom::BackgroundFetchError error) {
if (HasStorageError())
error = blink::mojom::BackgroundFetchError::STORAGE_ERROR;
ReportStorageError();
if (error == blink::mojom::BackgroundFetchError::NONE) {
for (const auto& settled_fetch : settled_fetches_) {
if (!settled_fetch.response->status_code) {
// A status_code of 0 means no headers were returned.
failure_reason_ =
blink::mojom::BackgroundFetchFailureReason::FETCH_ERROR;
break;
}
if (!network::cors::IsOkStatus(settled_fetch.response->status_code)) {
failure_reason_ =
blink::mojom::BackgroundFetchFailureReason::BAD_STATUS;
break;
}
}
}
std::move(settled_fetches_callback_)
.Run(error, failure_reason_, std::move(settled_fetches_),
{} /* blob_data_handles */);
Finished(); // Destroys |this|.
}
std::string GetSettledFetchesTask::HistogramName() const {
return "GetSettledFetchesTask";
};
} // namespace background_fetch
} // namespace content

@ -1,102 +0,0 @@
// Copyright 2018 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.
#ifndef CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_SETTLED_FETCHES_TASK_H_
#define CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_SETTLED_FETCHES_TASK_H_
#include "base/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "content/browser/background_fetch/background_fetch.pb.h"
#include "content/browser/background_fetch/background_fetch_request_match_params.h"
#include "content/browser/background_fetch/storage/database_task.h"
#include "content/browser/cache_storage/cache_storage_cache_handle.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
namespace content {
class BackgroundFetchRequestMatchParams;
namespace background_fetch {
class GetSettledFetchesTask : public DatabaseTask {
public:
// TODO(nator): Remove BlobDataHandle since we're not using them.
using SettledFetchesCallback = base::OnceCallback<void(
blink::mojom::BackgroundFetchError,
blink::mojom::BackgroundFetchFailureReason,
std::vector<BackgroundFetchSettledFetch>,
std::vector<std::unique_ptr<storage::BlobDataHandle>>)>;
// Gets settled fetches from cache storage, filtered according to
// |match_params|.
GetSettledFetchesTask(
DatabaseTaskHost* host,
BackgroundFetchRegistrationId registration_id,
std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
SettledFetchesCallback callback);
~GetSettledFetchesTask() override;
// DatabaseTask implementation:
void Start() override;
private:
void DidOpenCache(base::OnceClosure done_closure,
CacheStorageCacheHandle handle,
blink::mojom::CacheStorageError error);
void DidGetCompletedRequests(base::OnceClosure done_closure,
const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status);
void GetResponses();
void FillUncachedResponse(BackgroundFetchSettledFetch* settled_fetch,
base::OnceClosure callback);
void FillResponse(BackgroundFetchSettledFetch* settled_fetch,
base::OnceClosure callback);
void FillResponses(base::OnceClosure callback);
void DidMatchRequest(BackgroundFetchSettledFetch* settled_fetch,
base::OnceClosure callback,
blink::mojom::CacheStorageError error,
blink::mojom::FetchAPIResponsePtr cache_response);
void DidMatchAllResponsesForRequest(
base::OnceClosure callback,
blink::mojom::CacheStorageError error,
std::vector<blink::mojom::FetchAPIResponsePtr> cache_responses);
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
std::string HistogramName() const override;
BackgroundFetchRegistrationId registration_id_;
std::unique_ptr<BackgroundFetchRequestMatchParams> match_params_;
SettledFetchesCallback settled_fetches_callback_;
// SettledFetchesCallback params.
std::vector<BackgroundFetchSettledFetch> settled_fetches_;
blink::mojom::BackgroundFetchFailureReason failure_reason_ =
blink::mojom::BackgroundFetchFailureReason::NONE;
// Storage params.
CacheStorageCacheHandle handle_;
std::vector<proto::BackgroundFetchCompletedRequest> completed_requests_;
blink::mojom::BackgroundFetchError error_ =
blink::mojom::BackgroundFetchError::NONE;
base::WeakPtrFactory<GetSettledFetchesTask> weak_factory_; // Keep as last.
DISALLOW_COPY_AND_ASSIGN(GetSettledFetchesTask);
};
} // namespace background_fetch
} // namespace content
#endif // CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_SETTLED_FETCHES_TASK_H_

@ -18,9 +18,11 @@ namespace background_fetch {
MarkRegistrationForDeletionTask::MarkRegistrationForDeletionTask(
DatabaseTaskHost* host,
const BackgroundFetchRegistrationId& registration_id,
HandleBackgroundFetchErrorCallback callback)
bool check_for_failure,
MarkRegistrationForDeletionCallback callback)
: DatabaseTask(host),
registration_id_(registration_id),
check_for_failure_(check_for_failure),
callback_(std::move(callback)),
weak_factory_(this) {}
@ -71,7 +73,6 @@ void MarkRegistrationForDeletionTask::DidGetActiveUniqueId(
weak_factory_.GetWeakPtr()));
} else {
// Service worker database has been corrupted. Abandon fetches.
AbandonFetches(registration_id_.service_worker_registration_id());
SetStorageErrorAndFinish(
BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
@ -94,13 +95,73 @@ void MarkRegistrationForDeletionTask::DidDeactivate(
// |unique_id| as there may still be JavaScript references to it.
ref_counted_unique_ids().emplace(registration_id_.unique_id());
if (check_for_failure_) {
// Check if there is an error in the responses to report.
service_worker_context()->GetRegistrationUserDataByKeyPrefix(
registration_id_.service_worker_registration_id(),
{CompletedRequestKeyPrefix(registration_id_.unique_id())},
base::BindOnce(
&MarkRegistrationForDeletionTask::DidGetCompletedRequests,
weak_factory_.GetWeakPtr()));
} else {
FinishWithError(blink::mojom::BackgroundFetchError::NONE);
}
}
void MarkRegistrationForDeletionTask::DidGetCompletedRequests(
const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kOk:
case DatabaseStatus::kNotFound:
break;
case DatabaseStatus::kFailed:
SetStorageErrorAndFinish(
BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
for (const std::string& serialized_completed_request : data) {
proto::BackgroundFetchCompletedRequest completed_request;
if (!completed_request.ParseFromString(serialized_completed_request)) {
SetStorageErrorAndFinish(
BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
// TODO(rayankans): Delete this after M71 is out of use.
// |succeeded| was deprecated in favor of |failure_reason|.
// This can happen if a browser was updated while a fetch was ongoing.
if (completed_request.has_succeeded()) {
if (!completed_request.succeeded()) {
// The fetch failed, expose the error as FETCH_ERROR.
failure_reason_ =
blink::mojom::BackgroundFetchFailureReason::FETCH_ERROR;
}
}
if (completed_request.failure_reason() !=
proto::BackgroundFetchRegistration::NONE) {
bool did_convert = MojoFailureReasonFromRegistrationProto(
completed_request.failure_reason(), &failure_reason_);
if (!did_convert) {
SetStorageErrorAndFinish(
BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
break;
}
}
FinishWithError(blink::mojom::BackgroundFetchError::NONE);
}
void MarkRegistrationForDeletionTask::FinishWithError(
blink::mojom::BackgroundFetchError error) {
ReportStorageError();
std::move(callback_).Run(error);
if (HasStorageError())
AbandonFetches(registration_id_.service_worker_registration_id());
std::move(callback_).Run(error, failure_reason_);
Finished(); // Destroys |this|.
}

@ -20,10 +20,15 @@ namespace background_fetch {
// completely removed.
class MarkRegistrationForDeletionTask : public background_fetch::DatabaseTask {
public:
using MarkRegistrationForDeletionCallback =
base::OnceCallback<void(blink::mojom::BackgroundFetchError,
blink::mojom::BackgroundFetchFailureReason)>;
MarkRegistrationForDeletionTask(
DatabaseTaskHost* host,
const BackgroundFetchRegistrationId& registration_id,
HandleBackgroundFetchErrorCallback callback);
bool check_for_failure,
MarkRegistrationForDeletionCallback callback);
~MarkRegistrationForDeletionTask() override;
@ -35,12 +40,19 @@ class MarkRegistrationForDeletionTask : public background_fetch::DatabaseTask {
void DidDeactivate(blink::ServiceWorkerStatusCode status);
void DidGetCompletedRequests(const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status);
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
std::string HistogramName() const override;
BackgroundFetchRegistrationId registration_id_;
HandleBackgroundFetchErrorCallback callback_;
bool check_for_failure_;
MarkRegistrationForDeletionCallback callback_;
blink::mojom::BackgroundFetchFailureReason failure_reason_ =
blink::mojom::BackgroundFetchFailureReason::NONE;
base::WeakPtrFactory<MarkRegistrationForDeletionTask>
weak_factory_; // Keep as last.

@ -69,27 +69,26 @@ void MarkRequestCompleteTask::StoreResponse(base::OnceClosure done_closure) {
if (request_info_->GetURLChain().empty()) {
// The URL chain was not provided, so this is a failed response.
DCHECK(!request_info_->IsResultSuccess());
is_response_successful_ = false;
} else {
// TODO(crbug.com/884672): Move cross origin checks to when the response
// headers are available.
BackgroundFetchCrossOriginFilter filter(registration_id_.origin(),
*request_info_);
if (filter.CanPopulateBody())
PopulateResponseBody(response.get());
else
is_response_successful_ = false;
}
if (!IsOK(*request_info_))
is_response_successful_ = false;
// A valid non-empty url is needed if we want to write to the cache.
if (!request_info_->fetch_request().url.is_valid()) {
failure_reason_ = proto::BackgroundFetchRegistration::FETCH_ERROR;
CreateAndStoreCompletedRequest(std::move(done_closure));
return;
}
// TODO(crbug.com/884672): Move cross origin checks to when the response
// headers are available.
BackgroundFetchCrossOriginFilter filter(registration_id_.origin(),
*request_info_);
if (!filter.CanPopulateBody()) {
failure_reason_ = proto::BackgroundFetchRegistration::FETCH_ERROR;
// No point writing the response to the cache since it won't be exposed.
CreateAndStoreCompletedRequest(std::move(done_closure));
return;
}
PopulateResponseBody(response.get());
if (!IsOK(*request_info_))
failure_reason_ = proto::BackgroundFetchRegistration::BAD_STATUS;
int64_t response_size = 0;
if (service_worker_context()->is_incognito()) {
// The blob contains the size.
@ -220,7 +219,7 @@ void MarkRequestCompleteTask::CreateAndStoreCompletedRequest(
ServiceWorkerUtils::SerializeFetchRequestToString(
request_info_->fetch_request()));
completed_request_.set_download_guid(request_info_->download_guid());
completed_request_.set_succeeded(is_response_successful_);
completed_request_.set_failure_reason(failure_reason_);
service_worker_context()->StoreRegistrationUserData(
registration_id_.service_worker_registration_id(),

@ -79,7 +79,8 @@ class MarkRequestCompleteTask : public DatabaseTask {
MarkRequestCompleteCallback callback_;
proto::BackgroundFetchCompletedRequest completed_request_;
bool is_response_successful_ = true;
proto::BackgroundFetchRegistration::BackgroundFetchFailureReason
failure_reason_ = proto::BackgroundFetchRegistration::NONE;
base::WeakPtrFactory<MarkRequestCompleteTask> weak_factory_; // Keep as last.

@ -0,0 +1,116 @@
// Copyright 2018 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/background_fetch/storage/match_requests_task.h"
#include "base/barrier_closure.h"
#include "content/browser/background_fetch/background_fetch_data_manager.h"
#include "content/browser/background_fetch/storage/database_helpers.h"
#include "content/browser/cache_storage/cache_storage_manager.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "services/network/public/cpp/cors/cors.h"
namespace content {
namespace background_fetch {
MatchRequestsTask::MatchRequestsTask(
DatabaseTaskHost* host,
BackgroundFetchRegistrationId registration_id,
std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
SettledFetchesCallback callback)
: DatabaseTask(host),
registration_id_(registration_id),
match_params_(std::move(match_params)),
callback_(std::move(callback)),
weak_factory_(this) {}
MatchRequestsTask::~MatchRequestsTask() = default;
void MatchRequestsTask::Start() {
cache_manager()->OpenCache(registration_id_.origin(),
CacheStorageOwner::kBackgroundFetch,
registration_id_.unique_id() /* cache_name */,
base::BindOnce(&MatchRequestsTask::DidOpenCache,
weak_factory_.GetWeakPtr()));
}
void MatchRequestsTask::DidOpenCache(CacheStorageCacheHandle handle,
blink::mojom::CacheStorageError error) {
if (error != blink::mojom::CacheStorageError::kSuccess) {
SetStorageErrorAndFinish(BackgroundFetchStorageError::kCacheStorageError);
return;
}
handle_ = std::move(handle);
DCHECK(handle_.value());
std::unique_ptr<ServiceWorkerFetchRequest> request;
if (match_params_->FilterByRequest()) {
request = std::make_unique<ServiceWorkerFetchRequest>(
match_params_->request_to_match());
}
handle_.value()->GetAllMatchedEntries(
std::move(request), match_params_->cloned_cache_query_params(),
base::BindOnce(&MatchRequestsTask::DidGetAllMatchedEntries,
weak_factory_.GetWeakPtr()));
}
void MatchRequestsTask::DidGetAllMatchedEntries(
blink::mojom::CacheStorageError error,
std::vector<CacheStorageCache::CacheEntry> entries) {
if (error != blink::mojom::CacheStorageError::kSuccess) {
SetStorageErrorAndFinish(BackgroundFetchStorageError::kCacheStorageError);
return;
}
// If we tried to match without filtering, there should always be entries.
if (entries.empty()) {
if (!match_params_->FilterByRequest())
SetStorageErrorAndFinish(BackgroundFetchStorageError::kCacheStorageError);
else
FinishWithError(blink::mojom::BackgroundFetchError::NONE);
return;
}
size_t size = match_params_->match_all() ? entries.size() : 1u;
settled_fetches_.reserve(size);
for (size_t i = 0; i < size; i++) {
auto& entry = entries[i];
BackgroundFetchSettledFetch settled_fetch;
settled_fetch.request = std::move(*entry.first);
if (entry.second && entry.second->url_list.empty()) {
// We didn't process this empty response, so we should expose it
// as a nullptr.
settled_fetch.response = nullptr;
} else {
settled_fetch.response = std::move(entry.second);
}
settled_fetches_.push_back(std::move(settled_fetch));
}
FinishWithError(blink::mojom::BackgroundFetchError::NONE);
}
void MatchRequestsTask::FinishWithError(
blink::mojom::BackgroundFetchError error) {
if (HasStorageError())
error = blink::mojom::BackgroundFetchError::STORAGE_ERROR;
ReportStorageError();
std::move(callback_).Run(error, std::move(settled_fetches_));
Finished(); // Destroys |this|.
}
std::string MatchRequestsTask::HistogramName() const {
return "MatchRequestsTask";
};
} // namespace background_fetch
} // namespace content

@ -0,0 +1,70 @@
// Copyright 2018 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.
#ifndef CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_MATCH_REQUESTS_TASK_H_
#define CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_MATCH_REQUESTS_TASK_H_
#include "base/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "content/browser/background_fetch/background_fetch.pb.h"
#include "content/browser/background_fetch/background_fetch_request_match_params.h"
#include "content/browser/background_fetch/storage/database_task.h"
#include "content/browser/cache_storage/cache_storage_cache_handle.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
namespace content {
class BackgroundFetchRequestMatchParams;
namespace background_fetch {
class MatchRequestsTask : public DatabaseTask {
public:
using SettledFetchesCallback =
base::OnceCallback<void(blink::mojom::BackgroundFetchError,
std::vector<BackgroundFetchSettledFetch>)>;
// Gets settled fetches from cache storage, filtered according to
// |match_params|.
MatchRequestsTask(
DatabaseTaskHost* host,
BackgroundFetchRegistrationId registration_id,
std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
SettledFetchesCallback callback);
~MatchRequestsTask() override;
// DatabaseTask implementation:
void Start() override;
private:
void DidOpenCache(CacheStorageCacheHandle handle,
blink::mojom::CacheStorageError error);
void DidGetAllMatchedEntries(
blink::mojom::CacheStorageError error,
std::vector<CacheStorageCache::CacheEntry> entries);
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
std::string HistogramName() const override;
BackgroundFetchRegistrationId registration_id_;
std::unique_ptr<BackgroundFetchRequestMatchParams> match_params_;
SettledFetchesCallback callback_;
CacheStorageCacheHandle handle_;
std::vector<BackgroundFetchSettledFetch> settled_fetches_;
base::WeakPtrFactory<MatchRequestsTask> weak_factory_; // Keep as last.
DISALLOW_COPY_AND_ASSIGN(MatchRequestsTask);
};
} // namespace background_fetch
} // namespace content
#endif // CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_MATCH_REQUESTS_TASK_H_

@ -1764,6 +1764,61 @@ void CacheStorageCache::UpdateCacheSizeGotSize(
std::move(callback).Run();
}
void CacheStorageCache::GetAllMatchedEntries(
std::unique_ptr<ServiceWorkerFetchRequest> request,
blink::mojom::QueryParamsPtr options,
CacheEntriesCallback callback) {
if (backend_state_ == BACKEND_CLOSED) {
std::move(callback).Run(
MakeErrorStorage(ErrorStorageType::kKeysBackendClosed), {});
return;
}
scheduler_->ScheduleOperation(base::BindOnce(
&CacheStorageCache::GetAllMatchedEntriesImpl,
weak_ptr_factory_.GetWeakPtr(), std::move(request), std::move(options),
scheduler_->WrapCallbackToRunNext(std::move(callback))));
}
void CacheStorageCache::GetAllMatchedEntriesImpl(
std::unique_ptr<ServiceWorkerFetchRequest> request,
blink::mojom::QueryParamsPtr options,
CacheEntriesCallback callback) {
DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
if (backend_state_ != BACKEND_OPEN) {
std::move(callback).Run(
MakeErrorStorage(
ErrorStorageType::kStorageGetAllMatchedEntriesBackendClosed),
{});
return;
}
QueryCache(
std::move(request), std::move(options),
QUERY_CACHE_REQUESTS | QUERY_CACHE_RESPONSES_WITH_BODIES,
base::BindOnce(&CacheStorageCache::GetAllMatchedEntriesDidQueryCache,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void CacheStorageCache::GetAllMatchedEntriesDidQueryCache(
CacheEntriesCallback callback,
blink::mojom::CacheStorageError error,
std::unique_ptr<QueryCacheResults> query_cache_results) {
if (error != CacheStorageError::kSuccess) {
std::move(callback).Run(error, {});
return;
}
std::vector<CacheEntry> entries;
entries.reserve(query_cache_results->size());
for (auto& result : *query_cache_results) {
entries.emplace_back(std::move(result.request), std::move(result.response));
}
std::move(callback).Run(CacheStorageError::kSuccess, std::move(entries));
}
void CacheStorageCache::Delete(blink::mojom::BatchOperationPtr operation,
ErrorCallback callback) {
DCHECK(BACKEND_OPEN == backend_state_ || initializing_);

@ -62,6 +62,11 @@ class CacheStorageCacheTest;
// will be called so long as the cache object lives.
class CONTENT_EXPORT CacheStorageCache {
public:
using CacheEntry = std::pair<std::unique_ptr<ServiceWorkerFetchRequest>,
blink::mojom::FetchAPIResponsePtr>;
using CacheEntriesCallback =
base::OnceCallback<void(blink::mojom::CacheStorageError,
std::vector<CacheEntry>)>;
using ErrorCallback =
base::OnceCallback<void(blink::mojom::CacheStorageError)>;
using VerboseErrorCallback =
@ -197,6 +202,11 @@ class CONTENT_EXPORT CacheStorageCache {
blink::mojom::FetchAPIResponsePtr response,
ErrorCallback callback);
// Similar to MatchAll, but returns the associated requests as well.
void GetAllMatchedEntries(std::unique_ptr<ServiceWorkerFetchRequest> request,
blink::mojom::QueryParamsPtr match_params,
CacheEntriesCallback callback);
// Async operations in progress will cancel and not run their callbacks.
virtual ~CacheStorageCache();
@ -393,6 +403,16 @@ class CONTENT_EXPORT CacheStorageCache {
base::OnceClosure callback,
int64_t current_cache_size);
// GetAllMatchedEntries callbacks.
void GetAllMatchedEntriesImpl(
std::unique_ptr<ServiceWorkerFetchRequest> request,
blink::mojom::QueryParamsPtr options,
CacheEntriesCallback callback);
void GetAllMatchedEntriesDidQueryCache(
CacheEntriesCallback callback,
blink::mojom::CacheStorageError error,
std::unique_ptr<QueryCacheResults> query_cache_results);
// Returns ERROR_NOT_FOUND if not found. Otherwise deletes and returns OK.
void Delete(blink::mojom::BatchOperationPtr operation,
ErrorCallback callback);

@ -553,6 +553,18 @@ class CacheStorageCacheTest : public testing::Test {
return callback_error_ == CacheStorageError::kSuccess;
}
bool GetAllMatchedEntries(
std::vector<CacheStorageCache::CacheEntry>* cache_entries) {
base::RunLoop loop;
cache_->GetAllMatchedEntries(
nullptr /* request */, nullptr /* options */,
base::BindOnce(&CacheStorageCacheTest::CacheEntriesAndErrorCallback,
base::Unretained(this), loop.QuitClosure(),
cache_entries));
loop.Run();
return callback_error_ == CacheStorageError::kSuccess;
}
bool MatchAll(std::vector<blink::mojom::FetchAPIResponsePtr>* responses) {
return MatchAll(ServiceWorkerFetchRequest(), nullptr, responses);
}
@ -691,6 +703,16 @@ class CacheStorageCacheTest : public testing::Test {
std::move(quit_closure).Run();
}
void CacheEntriesAndErrorCallback(
base::OnceClosure quit_closure,
std::vector<CacheStorageCache::CacheEntry>* cache_entries_out,
CacheStorageError error,
std::vector<CacheStorageCache::CacheEntry> cache_entries) {
callback_error_ = error;
*cache_entries_out = std::move(cache_entries);
std::move(quit_closure).Run();
}
void CloseCallback(base::RunLoop* run_loop) {
EXPECT_FALSE(callback_closed_);
callback_closed_ = true;
@ -1140,6 +1162,25 @@ TEST_P(CacheStorageCacheTestP, Match_IgnoreVary) {
EXPECT_TRUE(Match(body_request_, std::move(match_params)));
}
TEST_P(CacheStorageCacheTestP, GetAllMatchedEntries_RequestsIncluded) {
EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
std::vector<CacheStorageCache::CacheEntry> cache_entries;
EXPECT_TRUE(GetAllMatchedEntries(&cache_entries));
ASSERT_EQ(1u, cache_entries.size());
const auto& request = cache_entries[0].first;
EXPECT_EQ(request->url, body_request_.url);
EXPECT_EQ(request->headers, body_request_.headers);
EXPECT_EQ(request->method, body_request_.method);
auto& response = cache_entries[0].second;
EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateBlobBodyResponse()),
*response));
blink::mojom::BlobPtr blob(std::move(response->blob->blob));
EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_, blob.get()));
}
TEST_P(CacheStorageCacheTestP, Keys_IgnoreSearch) {
EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));

@ -36,7 +36,8 @@ enum class ErrorStorageType {
kDeleteImplBackendClosed = 20,
kKeysImplBackendClosed = 21,
kCreateBackendDidCreateFailed = 22,
kMaxValue = kCreateBackendDidCreateFailed,
kStorageGetAllMatchedEntriesBackendClosed = 23,
kMaxValue = kStorageGetAllMatchedEntriesBackendClosed,
};
blink::mojom::CacheStorageError MakeErrorStorage(ErrorStorageType type);

@ -45,11 +45,14 @@ backgroundFetchTest(async (test, backgroundFetch) => {
assert_equals(type, 'backgroundfetchabort');
assert_equals(results.length, 2);
const completedResult = results[0] || results[1];
// The abort might have gone through before the first result was persisted.
if (results.length === 1) {
assert_true(results[0].url.includes('resources/feature-name.txt'));
assert_equals(results[0].status, 200);
assert_equals(results[0].text, expectedResultText);
if (completedResult) {
assert_true(completedResult.url.includes('resources/feature-name.txt'));
assert_equals(completedResult.status, 200);
assert_equals(completedResult.text, expectedResultText);
}
resolve();

@ -265,8 +265,8 @@ backgroundFetchTest(async (test, backgroundFetch) => {
backgroundFetchTest(async (test, backgroundFetch) => {
const registration = await backgroundFetch.fetch(
'my-id',
['https://example.com', 'http://example.com']);
'my-id',
[location.origin, location.origin.replace('https', 'http')]);
const {type, eventRegistration, results} = await getMessageFromServiceWorker();
@ -274,7 +274,11 @@ backgroundFetchTest(async (test, backgroundFetch) => {
assert_equals(eventRegistration.failureReason, 'fetch-error');
assert_equals(results.length, 2);
assert_true(results[0].url.includes('https://example.com'));
assert_equals(results[1].url, '');
const validResponse = results[0] ? results[0] : results[1];
const nullResponse = !results[0] ? results[0] : results[1];
assert_true(validResponse.url.includes(location.origin));
assert_equals(nullResponse, null);
}, 'Fetches with mixed content should fail.');

@ -2,9 +2,8 @@
importScripts('sw-helpers.js');
async function getFetchResult(record) {
response = await record.responseReady;
if (!response)
return Promise.resolve(null);
const response = await record.responseReady.catch(() => null);
if (!response) return null;
return {
url: response.url,
@ -13,7 +12,7 @@ async function getFetchResult(record) {
};
}
function handleBackgroundFetchUpdateEvent(event) {
function handleBackgroundFetchEvent(event) {
event.waitUntil(
event.registration.matchAll()
.then(records =>
@ -25,6 +24,6 @@ function handleBackgroundFetchUpdateEvent(event) {
}));
}
self.addEventListener('backgroundfetchsuccess', handleBackgroundFetchUpdateEvent);
self.addEventListener('backgroundfetchfail', handleBackgroundFetchUpdateEvent);
self.addEventListener('backgroundfetchabort', handleBackgroundFetchUpdateEvent);
self.addEventListener('backgroundfetchsuccess', handleBackgroundFetchEvent);
self.addEventListener('backgroundfetchfail', handleBackgroundFetchEvent);
self.addEventListener('backgroundfetchabort', handleBackgroundFetchEvent);

@ -24,8 +24,10 @@ ScriptPromise BackgroundFetchRecord::responseReady(ScriptState* script_state) {
ResponseReadyProperty::kResponseReady);
}
if (!response_) {
response_ = Response::Create(ExecutionContext::From(script_state),
nullptr /* FetchResponseData */);
return ScriptPromise::Reject(
script_state,
V8ThrowException::CreateTypeError(script_state->GetIsolate(),
"The response is not available."));
}
DCHECK(response_);
response_ready_property_->Resolve(response_);

@ -238,15 +238,10 @@ void BackgroundFetchRegistration::DidGetMatchingRequests(
HeapVector<Member<BackgroundFetchRecord>> to_return;
to_return.ReserveInitialCapacity(settled_fetches.size());
for (const auto& fetch : settled_fetches) {
if (fetch->response->response_type ==
network::mojom::FetchResponseType::kError) {
// Resolve with undefined.
resolver->Resolve();
return;
}
BackgroundFetchRecord* record = new BackgroundFetchRecord(
Request::Create(script_state, fetch->request),
Response::Create(script_state, *fetch->response));
fetch->response ? Response::Create(script_state, *fetch->response)
: nullptr);
to_return.push_back(record);
}

@ -5341,6 +5341,7 @@ uploading your change for review. These are checked by presubmit scripts.
<int value="20" label="kDeleteImplBackendClosed"/>
<int value="21" label="kKeysImplBackendClosed"/>
<int value="22" label="kCreateBackendDidCreateFailed"/>
<int value="23" label="kStorageGetAllMatchedEntriesBackendClosed"/>
</enum>
<enum name="CacheStorageErrorType">

@ -123140,6 +123140,7 @@ uploading your change for review.
label="MarkRegistrationForDeletion DatabaseTask"/>
<suffix name="MarkRequestCompleteTask"
label="MarkRequestComplete DatabaseTask"/>
<suffix name="MatchRequestsTask" label="MatchRequests DatabaseTask"/>
<suffix name="StartNextPendingRequestTask"
label="StartNextPendingRequest DatabaseTask"/>
<suffix name="UpdateRegistrationUITask"