blob: 92b326308f214c5dd277d927d1aba62674e9447e [file] [log] [blame]
// Copyright 2019 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 "services/data_decoder/public/cpp/safe_bundled_exchanges_parser.h"
#include "base/bind.h"
#include "services/data_decoder/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace data_decoder {
namespace {
constexpr char kConnectionError[] =
"Cannot connect to the remote parser service";
} // namespace
SafeBundledExchangesParser::SafeBundledExchangesParser(
service_manager::Connector* connector) {
if (connector) {
connector->Connect(mojom::kServiceName,
factory_.BindNewPipeAndPassReceiver());
}
}
SafeBundledExchangesParser::~SafeBundledExchangesParser() = default;
base::File::Error SafeBundledExchangesParser::OpenFile(base::File file) {
DCHECK(disconnected_);
DCHECK(factory_.is_connected());
if (!file.IsValid())
return file.error_details();
factory_->GetParserForFile(parser_.BindNewPipeAndPassReceiver(),
std::move(file));
parser_.set_disconnect_handler(base::BindOnce(
&SafeBundledExchangesParser::OnDisconnect, base::Unretained(this)));
disconnected_ = false;
return base::File::FILE_OK;
}
void SafeBundledExchangesParser::OpenDataSource(
mojo::PendingRemote<mojom::BundleDataSource> data_source) {
DCHECK(disconnected_);
DCHECK(factory_.is_connected());
factory_->GetParserForDataSource(parser_.BindNewPipeAndPassReceiver(),
std::move(data_source));
parser_.set_disconnect_handler(base::BindOnce(
&SafeBundledExchangesParser::OnDisconnect, base::Unretained(this)));
disconnected_ = false;
}
void SafeBundledExchangesParser::ParseMetadata(
mojom::BundledExchangesParser::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, mojom::BundleMetadataParseError::New(
mojom::BundleParseErrorType::kParserInternalError,
GURL() /* fallback_url */, kConnectionError));
return;
}
metadata_callback_ = std::move(callback);
parser_->ParseMetadata(base::BindOnce(
&SafeBundledExchangesParser::OnMetadataParsed, base::Unretained(this)));
}
void SafeBundledExchangesParser::ParseResponse(
uint64_t response_offset,
uint64_t response_length,
mojom::BundledExchangesParser::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, mojom::BundleResponseParseError::New(
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(&SafeBundledExchangesParser::OnResponseParsed,
base::Unretained(this), callback_id));
}
void SafeBundledExchangesParser::OnDisconnect() {
disconnected_ = true;
if (!metadata_callback_.is_null())
std::move(metadata_callback_)
.Run(nullptr, mojom::BundleMetadataParseError::New(
mojom::BundleParseErrorType::kParserInternalError,
GURL() /* fallback_url */, kConnectionError));
for (auto& callback : response_callbacks_)
std::move(callback.second)
.Run(nullptr, mojom::BundleResponseParseError::New(
mojom::BundleParseErrorType::kParserInternalError,
kConnectionError));
response_callbacks_.clear();
}
void SafeBundledExchangesParser::OnMetadataParsed(
mojom::BundleMetadataPtr metadata,
mojom::BundleMetadataParseErrorPtr error) {
DCHECK(!metadata_callback_.is_null());
std::move(metadata_callback_).Run(std::move(metadata), std::move(error));
}
void SafeBundledExchangesParser::OnResponseParsed(
size_t callback_id,
mojom::BundleResponsePtr response,
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));
}
void SafeBundledExchangesParser::SetBundledExchangesParserFactoryForTesting(
mojo::Remote<mojom::BundledExchangesParserFactory> factory) {
factory_ = std::move(factory);
}
} // namespace data_decoder