blob: 9de9c3f16509c5f9db27cf1f7ebf944faade91a0 [file] [log] [blame]
// Copyright 2016 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/blob_storage/blob_dispatcher_host.h"
#include <algorithm>
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "content/browser/bad_message.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/common/fileapi/webblob_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_features.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "url/gurl.h"
using storage::BlobStorageContext;
namespace content {
namespace {
// These are used for UMA stats, don't change.
enum RefcountOperation {
BDH_DECREMENT = 0,
BDH_INCREMENT,
BDH_TRACING_ENUM_LAST
};
} // namespace
BlobDispatcherHost::BlobDispatcherHost(
int process_id,
scoped_refptr<ChromeBlobStorageContext> blob_storage_context)
: BrowserMessageFilter(BlobMsgStart),
process_id_(process_id),
blob_storage_context_(std::move(blob_storage_context)) {}
BlobDispatcherHost::~BlobDispatcherHost() {
ClearHostFromBlobStorageContext();
}
void BlobDispatcherHost::OnChannelClosing() {
ClearHostFromBlobStorageContext();
public_blob_urls_.clear();
}
bool BlobDispatcherHost::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(BlobDispatcherHost, message)
IPC_MESSAGE_HANDLER(BlobHostMsg_RegisterPublicURL, OnRegisterPublicBlobURL)
IPC_MESSAGE_HANDLER(BlobHostMsg_RevokePublicURL, OnRevokePublicBlobURL)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void BlobDispatcherHost::OnRegisterPublicBlobURL(const GURL& public_url,
const std::string& uuid) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
ChildProcessSecurityPolicyImpl* security_policy =
ChildProcessSecurityPolicyImpl::GetInstance();
// Blob urls have embedded origins. A frame should only be creating blob URLs
// in the origin of its current document. Make sure that the origin advertised
// on the URL is allowed to be rendered in this process.
if (!public_url.SchemeIsBlob() ||
!security_policy->CanCommitURL(process_id_, public_url)) {
DVLOG(1) << "BlobDispatcherHost::OnRegisterPublicBlobURL("
<< public_url.spec() << ", " << uuid
<< "): Invalid or prohibited URL.";
bad_message::ReceivedBadMessage(this, bad_message::BDH_DISALLOWED_ORIGIN);
return;
}
if (uuid.empty()) {
bad_message::ReceivedBadMessage(this,
bad_message::BDH_INVALID_URL_OPERATION);
return;
}
BlobStorageContext* context = this->context();
if (context->registry().IsURLMapped(public_url)) {
DVLOG(1) << "BlobDispatcherHost::OnRegisterPublicBlobURL("
<< public_url.spec() << ", " << uuid << "): Invalid url or uuid.";
UMA_HISTOGRAM_ENUMERATION("Storage.Blob.InvalidURLRegister", BDH_INCREMENT,
BDH_TRACING_ENUM_LAST);
return;
}
context->RegisterPublicBlobURL(public_url, uuid);
public_blob_urls_.insert(public_url);
}
void BlobDispatcherHost::OnRevokePublicBlobURL(const GURL& public_url) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!public_url.is_valid()) {
bad_message::ReceivedBadMessage(this,
bad_message::BDH_INVALID_URL_OPERATION);
return;
}
if (!IsUrlRegisteredInHost(public_url)) {
DVLOG(1) << "BlobDispatcherHost::OnRevokePublicBlobURL("
<< public_url.spec() << "): Unknown URL.";
UMA_HISTOGRAM_ENUMERATION("Storage.Blob.InvalidURLRegister", BDH_DECREMENT,
BDH_TRACING_ENUM_LAST);
return;
}
context()->RevokePublicBlobURL(public_url);
public_blob_urls_.erase(public_url);
}
storage::BlobStorageContext* BlobDispatcherHost::context() {
return blob_storage_context_->context();
}
bool BlobDispatcherHost::IsUrlRegisteredInHost(const GURL& blob_url) {
return base::ContainsKey(public_blob_urls_, blob_url);
}
void BlobDispatcherHost::ClearHostFromBlobStorageContext() {
BlobStorageContext* context = this->context();
for (const auto& url : public_blob_urls_) {
context->RevokePublicBlobURL(url);
}
}
} // namespace content