[go: nahoru, domu]

blob: c1d74726e34cd2daef36244e0e83538d7093998e [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/data_decoder/public/cpp/safe_web_bundle_parser.h"
#include "base/bind.h"
namespace data_decoder {
namespace {
constexpr char kConnectionError[] =
"Cannot connect to the remote parser service";
} // namespace
SafeWebBundleParser::SafeWebBundleParser() = default;
SafeWebBundleParser::~SafeWebBundleParser() = default;
base::File::Error SafeWebBundleParser::OpenFile(base::File file) {
DCHECK(disconnected_);
if (!file.IsValid())
return file.error_details();
GetFactory()->GetParserForFile(parser_.BindNewPipeAndPassReceiver(),
std::move(file));
parser_.set_disconnect_handler(base::BindOnce(
&SafeWebBundleParser::OnDisconnect, base::Unretained(this)));
disconnected_ = false;
return base::File::FILE_OK;
}
void SafeWebBundleParser::OpenDataSource(
mojo::PendingRemote<web_package::mojom::BundleDataSource> data_source) {
DCHECK(disconnected_);
GetFactory()->GetParserForDataSource(parser_.BindNewPipeAndPassReceiver(),
std::move(data_source));
parser_.set_disconnect_handler(base::BindOnce(
&SafeWebBundleParser::OnDisconnect, base::Unretained(this)));
disconnected_ = false;
}
void SafeWebBundleParser::ParseIntegrityBlock(
web_package::mojom::WebBundleParser::ParseIntegrityBlockCallback callback) {
// This method is designed to be called once. So, allowing only once
// simultaneous request is fine enough.
if (disconnected_ || !integrity_block_callback_.is_null()) {
std::move(callback).Run(
nullptr,
web_package::mojom::BundleIntegrityBlockParseError::New(
web_package::mojom::BundleParseErrorType::kParserInternalError,
kConnectionError));
return;
}
integrity_block_callback_ = std::move(callback);
parser_->ParseIntegrityBlock(base::BindOnce(
&SafeWebBundleParser::OnIntegrityBlockParsed, base::Unretained(this)));
}
void SafeWebBundleParser::ParseMetadata(
int64_t offset,
web_package::mojom::WebBundleParser::ParseMetadataCallback callback) {
// This method is designed to be called once. So, allowing only once
// simultaneous request is fine enough.
if (disconnected_ || !metadata_callback_.is_null()) {
std::move(callback).Run(
nullptr,
web_package::mojom::BundleMetadataParseError::New(
web_package::mojom::BundleParseErrorType::kParserInternalError,
kConnectionError));
return;
}
metadata_callback_ = std::move(callback);
parser_->ParseMetadata(offset,
base::BindOnce(&SafeWebBundleParser::OnMetadataParsed,
base::Unretained(this)));
}
void SafeWebBundleParser::ParseResponse(
uint64_t response_offset,
uint64_t response_length,
web_package::mojom::WebBundleParser::ParseResponseCallback callback) {
// This method allows simultaneous multiple requests. But if the unique ID
// overflows, and the previous request that owns the same ID hasn't finished,
// we just make the new request fail with kConnectionError.
if (disconnected_ ||
response_callbacks_.contains(response_callback_next_id_)) {
std::move(callback).Run(
nullptr,
web_package::mojom::BundleResponseParseError::New(
web_package::mojom::BundleParseErrorType::kParserInternalError,
kConnectionError));
return;
}
size_t callback_id = response_callback_next_id_++;
response_callbacks_[callback_id] = std::move(callback);
parser_->ParseResponse(response_offset, response_length,
base::BindOnce(&SafeWebBundleParser::OnResponseParsed,
base::Unretained(this), callback_id));
}
web_package::mojom::WebBundleParserFactory* SafeWebBundleParser::GetFactory() {
if (!factory_) {
data_decoder_.GetService()->BindWebBundleParserFactory(
factory_.BindNewPipeAndPassReceiver());
factory_.reset_on_disconnect();
}
return factory_.get();
}
void SafeWebBundleParser::SetDisconnectCallback(base::OnceClosure callback) {
DCHECK(!disconnect_callback_);
disconnect_callback_ = std::move(callback);
}
void SafeWebBundleParser::OnDisconnect() {
disconnected_ = true;
if (!integrity_block_callback_.is_null()) {
std::move(integrity_block_callback_)
.Run(nullptr,
web_package::mojom::BundleIntegrityBlockParseError::New(
web_package::mojom::BundleParseErrorType::kParserInternalError,
kConnectionError));
}
if (!metadata_callback_.is_null()) {
std::move(metadata_callback_)
.Run(nullptr,
web_package::mojom::BundleMetadataParseError::New(
web_package::mojom::BundleParseErrorType::kParserInternalError,
kConnectionError));
}
for (auto& callback : response_callbacks_) {
std::move(callback.second)
.Run(nullptr,
web_package::mojom::BundleResponseParseError::New(
web_package::mojom::BundleParseErrorType::kParserInternalError,
kConnectionError));
}
response_callbacks_.clear();
if (disconnect_callback_)
std::move(disconnect_callback_).Run();
}
void SafeWebBundleParser::OnIntegrityBlockParsed(
web_package::mojom::BundleIntegrityBlockPtr integrity_block,
web_package::mojom::BundleIntegrityBlockParseErrorPtr error) {
DCHECK(!integrity_block_callback_.is_null());
std::move(integrity_block_callback_)
.Run(std::move(integrity_block), std::move(error));
}
void SafeWebBundleParser::OnMetadataParsed(
web_package::mojom::BundleMetadataPtr metadata,
web_package::mojom::BundleMetadataParseErrorPtr error) {
DCHECK(!metadata_callback_.is_null());
std::move(metadata_callback_).Run(std::move(metadata), std::move(error));
}
void SafeWebBundleParser::OnResponseParsed(
size_t callback_id,
web_package::mojom::BundleResponsePtr response,
web_package::mojom::BundleResponseParseErrorPtr error) {
auto it = response_callbacks_.find(callback_id);
DCHECK(it != response_callbacks_.end());
auto callback = std::move(it->second);
response_callbacks_.erase(it);
std::move(callback).Run(std::move(response), std::move(error));
}
} // namespace data_decoder