blob: 4f537cd9c799439892470ea19fc1ff2a2725bebd [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/quota/quota_manager_host.h"
#include <stdint.h>
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/numerics/safe_conversions.h"
#include "content/browser/quota/quota_change_dispatcher.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_client.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "storage/browser/quota/quota_manager.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
#include "url/origin.h"
namespace content {
QuotaManagerHost::QuotaManagerHost(
int process_id,
int render_frame_id,
const blink::StorageKey& storage_key,
storage::QuotaManager* quota_manager,
QuotaPermissionContext* permission_context,
scoped_refptr<QuotaChangeDispatcher> quota_change_dispatcher)
: process_id_(process_id),
render_frame_id_(render_frame_id),
storage_key_(storage_key),
quota_manager_(quota_manager),
permission_context_(permission_context),
quota_change_dispatcher_(std::move(quota_change_dispatcher)) {
DCHECK(quota_manager);
// TODO(sashab): Work out the conditions for permission_context to be set and
// add a DCHECK for it here.
}
void QuotaManagerHost::AddChangeListener(
mojo::PendingRemote<blink::mojom::QuotaChangeListener> mojo_listener,
AddChangeListenerCallback callback) {
if (quota_change_dispatcher_) {
quota_change_dispatcher_->AddChangeListener(storage_key_,
std::move(mojo_listener));
}
std::move(callback).Run();
}
void QuotaManagerHost::QueryStorageUsageAndQuota(
blink::mojom::StorageType storage_type,
QueryStorageUsageAndQuotaCallback callback) {
quota_manager_->GetUsageAndQuotaWithBreakdown(
storage_key_, storage_type,
base::BindOnce(&QuotaManagerHost::DidQueryStorageUsageAndQuota,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void QuotaManagerHost::RequestStorageQuota(
blink::mojom::StorageType storage_type,
uint64_t requested_size,
blink::mojom::QuotaManagerHost::RequestStorageQuotaCallback callback) {
if (storage_type != blink::mojom::StorageType::kTemporary &&
storage_type != blink::mojom::StorageType::kPersistent) {
mojo::ReportBadMessage("Unsupported storage type specified.");
return;
}
if (render_frame_id_ == MSG_ROUTING_NONE) {
mojo::ReportBadMessage(
"Requests may show permission UI and are not allowed from workers.");
return;
}
if (storage_key_.origin().opaque()) {
mojo::ReportBadMessage("Opaque origins may not request storage quota.");
return;
}
DCHECK(storage_type == blink::mojom::StorageType::kTemporary ||
storage_type == blink::mojom::StorageType::kPersistent);
if (storage_type == blink::mojom::StorageType::kPersistent) {
quota_manager_->GetUsageAndQuotaForWebApps(
storage_key_, storage_type,
base::BindOnce(&QuotaManagerHost::DidGetPersistentUsageAndQuota,
weak_factory_.GetWeakPtr(), storage_type, requested_size,
std::move(callback)));
} else {
quota_manager_->GetUsageAndQuotaForWebApps(
storage_key_, storage_type,
base::BindOnce(&QuotaManagerHost::DidGetTemporaryUsageAndQuota,
weak_factory_.GetWeakPtr(), requested_size,
std::move(callback)));
}
}
void QuotaManagerHost::DidQueryStorageUsageAndQuota(
QueryStorageUsageAndQuotaCallback callback,
blink::mojom::QuotaStatusCode status,
int64_t usage,
int64_t quota,
blink::mojom::UsageBreakdownPtr usage_breakdown) {
std::move(callback).Run(status, usage, quota, std::move(usage_breakdown));
}
void QuotaManagerHost::DidGetPersistentUsageAndQuota(
blink::mojom::StorageType storage_type,
uint64_t requested_quota,
RequestStorageQuotaCallback callback,
blink::mojom::QuotaStatusCode status,
int64_t current_usage,
int64_t current_quota) {
if (status != blink::mojom::QuotaStatusCode::kOk) {
std::move(callback).Run(status, 0, 0);
return;
}
// If we have enough quota for the requested storage, we can just let it go.
// Convert the requested size from uint64_t to int64_t since the quota backend
// requires int64_t values.
// TODO(nhiroki): The backend should accept uint64_t values.
int64_t requested_quota_signed =
base::saturated_cast<int64_t>(requested_quota);
if (quota_manager_->IsStorageUnlimited(storage_key_, storage_type) ||
requested_quota_signed <= current_quota) {
std::move(callback).Run(blink::mojom::QuotaStatusCode::kOk, current_usage,
requested_quota);
return;
}
// Otherwise we need to consult with the permission context and possibly show
// a prompt.
DCHECK(permission_context_);
StorageQuotaParams params;
params.render_frame_id = render_frame_id_;
params.origin_url = storage_key_.origin().GetURL();
params.storage_type = storage_type;
params.requested_size = requested_quota;
permission_context_->RequestQuotaPermission(
params, process_id_,
base::BindOnce(&QuotaManagerHost::DidGetPermissionResponse,
weak_factory_.GetWeakPtr(), requested_quota, current_usage,
current_quota, std::move(callback)));
}
void QuotaManagerHost::DidGetPermissionResponse(
uint64_t requested_quota,
int64_t current_usage,
int64_t current_quota,
RequestStorageQuotaCallback callback,
QuotaPermissionContext::QuotaPermissionResponse response) {
// If user didn't allow the new quota, just return the current quota.
if (response != QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW) {
std::move(callback).Run(blink::mojom::QuotaStatusCode::kOk, current_usage,
current_quota);
return;
}
// Otherwise, return the new quota.
quota_manager_->SetPersistentHostQuota(
storage_key_.origin().host(), requested_quota,
base::BindOnce(&QuotaManagerHost::DidSetHostQuota,
weak_factory_.GetWeakPtr(), current_usage,
std::move(callback)));
}
void QuotaManagerHost::DidSetHostQuota(int64_t current_usage,
RequestStorageQuotaCallback callback,
blink::mojom::QuotaStatusCode status,
int64_t new_quota) {
std::move(callback).Run(status, current_usage, new_quota);
}
void QuotaManagerHost::DidGetTemporaryUsageAndQuota(
int64_t requested_quota,
RequestStorageQuotaCallback callback,
blink::mojom::QuotaStatusCode status,
int64_t usage,
int64_t quota) {
std::move(callback).Run(status, usage, std::min(requested_quota, quota));
}
QuotaManagerHost::~QuotaManagerHost() = default;
} // namespace content