blob: 3203b201b99f6f35e4a0a3b2a9c73c463e4bc8ce [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/background_fetch/storage/create_registration_task.h"
#include <utility>
#include "base/strings/string_number_conversions.h"
#include "content/browser/background_fetch/storage/database_helpers.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/common/service_worker/service_worker_status_code.h"
namespace content {
namespace background_fetch {
std::string RequestKey(const std::string& unique_id, int request_index) {
// Allows looking up a request by registration id and index within that.
return RequestKeyPrefix(unique_id) + base::IntToString(request_index);
}
CreateRegistrationTask::CreateRegistrationTask(
BackgroundFetchDataManager* data_manager,
const BackgroundFetchRegistrationId& registration_id,
const std::vector<ServiceWorkerFetchRequest>& requests,
const BackgroundFetchOptions& options,
CreateRegistrationCallback callback)
: DatabaseTask(data_manager),
registration_id_(registration_id),
requests_(requests),
options_(options),
callback_(std::move(callback)),
weak_factory_(this) {}
CreateRegistrationTask::~CreateRegistrationTask() = default;
void CreateRegistrationTask::Start() {
service_worker_context()->GetRegistrationUserData(
registration_id_.service_worker_registration_id(),
{ActiveRegistrationUniqueIdKey(registration_id_.developer_id())},
base::BindOnce(&CreateRegistrationTask::DidGetUniqueId,
weak_factory_.GetWeakPtr()));
}
void CreateRegistrationTask::DidGetUniqueId(
const std::vector<std::string>& data,
ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kNotFound:
StoreMetadata();
return;
case DatabaseStatus::kOk:
// Can't create a registration since there is already an active
// registration with the same |developer_id|. It must be deactivated
// (completed/failed/aborted) first.
std::move(callback_).Run(
blink::mojom::BackgroundFetchError::DUPLICATED_DEVELOPER_ID,
nullptr /* registration */);
Finished(); // Destroys |this|.
return;
case DatabaseStatus::kFailed:
std::move(callback_).Run(
blink::mojom::BackgroundFetchError::STORAGE_ERROR,
nullptr /* registration */);
Finished(); // Destroys |this|.
return;
}
}
proto::BackgroundFetchMetadata CreateRegistrationTask::CreateMetadataProto()
const {
proto::BackgroundFetchMetadata metadata_proto;
// Set BackgroundFetchRegistration fields.
// Upload/Download stats default to correct initial values.
auto* registration_proto = metadata_proto.mutable_registration();
registration_proto->set_unique_id(registration_->unique_id);
registration_proto->set_developer_id(registration_->developer_id);
// Set Options fields.
auto* options_proto = metadata_proto.mutable_options();
options_proto->set_title(options_.title);
options_proto->set_download_total(options_.download_total);
for (const auto& icon : options_.icons) {
auto* icon_definition_proto = options_proto->add_icons();
icon_definition_proto->set_src(icon.src);
icon_definition_proto->set_sizes(icon.sizes);
icon_definition_proto->set_type(icon.type);
}
// Set other metadata fields.
metadata_proto.set_origin(registration_id_.origin().Serialize());
metadata_proto.set_creation_microseconds_since_unix_epoch(
(base::Time::Now() - base::Time::UnixEpoch()).InMicroseconds());
metadata_proto.set_ui_title(options_.title);
return metadata_proto;
}
void CreateRegistrationTask::StoreMetadata() {
DCHECK(!registration_);
DCHECK(!registration_id_.origin().unique());
registration_ = std::make_unique<BackgroundFetchRegistration>();
registration_->developer_id = registration_id_.developer_id();
registration_->unique_id = registration_id_.unique_id();
// TODO(crbug.com/774054): Uploads are not yet supported.
registration_->upload_total = 0;
registration_->uploaded = 0;
registration_->download_total = options_.download_total;
registration_->downloaded = 0;
std::vector<std::pair<std::string, std::string>> entries;
entries.reserve(requests_.size() * 2 + 1);
const proto::BackgroundFetchMetadata metadata_proto = CreateMetadataProto();
std::string serialized_metadata_proto;
if (!metadata_proto.SerializeToString(&serialized_metadata_proto)) {
// TODO(crbug.com/780025): Log failures to UMA.
std::move(callback_).Run(blink::mojom::BackgroundFetchError::STORAGE_ERROR,
nullptr /* registration */);
Finished(); // Destroys |this|.
return;
}
entries.emplace_back(
ActiveRegistrationUniqueIdKey(registration_id_.developer_id()),
registration_id_.unique_id());
entries.emplace_back(RegistrationKey(registration_id_.unique_id()),
std::move(serialized_metadata_proto));
// Signed integers are used for request indexes to avoid unsigned gotchas.
for (int i = 0; i < base::checked_cast<int>(requests_.size()); i++) {
// TODO(crbug.com/757760): Serialize actual values for these entries.
entries.emplace_back(RequestKey(registration_id_.unique_id(), i),
"TODO: Serialize FetchAPIRequest as value");
entries.emplace_back(
PendingRequestKey(
metadata_proto.creation_microseconds_since_unix_epoch(),
registration_id_.unique_id(), i),
std::string());
}
service_worker_context()->StoreRegistrationUserData(
registration_id_.service_worker_registration_id(),
registration_id_.origin().GetURL(), entries,
base::BindOnce(&CreateRegistrationTask::DidStoreMetadata,
weak_factory_.GetWeakPtr()));
}
void CreateRegistrationTask::DidStoreMetadata(ServiceWorkerStatusCode status) {
DCHECK(registration_);
switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kOk:
break;
case DatabaseStatus::kFailed:
case DatabaseStatus::kNotFound:
std::move(callback_).Run(
blink::mojom::BackgroundFetchError::STORAGE_ERROR,
nullptr /* registration */);
Finished(); // Destroys |this|.
return;
}
std::move(callback_).Run(blink::mojom::BackgroundFetchError::NONE,
std::move(registration_));
Finished(); // Destroys |this|.
}
} // namespace background_fetch
} // namespace content