blob: 6b5640229a2409dae8b225df6b3c39a72c0be581 [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.
#ifndef SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_WEB_BUNDLE_PARSER_H_
#define SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_WEB_BUNDLE_PARSER_H_
#include <memory>
#include <optional>
#include "base/containers/flat_map.h"
#include "base/files/file.h"
#include "base/functional/callback.h"
#include "components/web_package/mojom/web_bundle_parser.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
#include "url/gurl.h"
namespace data_decoder {
// This interface specifies the requirements how a
// `web_package::mojom::BundleDataSource` should be created.
class DataSourceCreatingStrategy {
public:
virtual ~DataSourceCreatingStrategy() {}
// Checks if the connection can be established. E.g. if the source of the
// data is readable, etc.
virtual base::expected<void, std::string> ExpectReady() const = 0;
// Creates DataSource. The WebBundleParserFactory is used to bind the
// appropriate receiver on the side of the data decoder process.
// The return result will be used to create a parser.
virtual mojo::PendingRemote<web_package::mojom::BundleDataSource>
CreateDataSource(web_package::mojom::WebBundleParserFactory* binder) = 0;
// Closes the underlying source of data (e.g. file). The callback must
// be called when the source of data is closed.
virtual void Close(base::OnceClosure callback) = 0;
};
// This class is used for safe parsing of the Web Bundles. Even though it
// internally uses parsing in the data decoder process by means of
// mojo and IPC, the aim of this class is to isolate users from any knowledge
// about mojo and IPC.
//
// Every parsing method will try to reestablish the IPC connection (if
// necessary) before returning an error.
//
// It is safe to delete this object from within the callbacks passed to its
// methods.
class SafeWebBundleParser {
public:
// Returns the strategy that lets the provided signed web bundle file
// be a data source for parsing.
static std::unique_ptr<DataSourceCreatingStrategy> GetFileStrategy(
base::File file);
SafeWebBundleParser(
std::optional<GURL> base_url,
std::unique_ptr<DataSourceCreatingStrategy> data_source_creator);
SafeWebBundleParser(const SafeWebBundleParser&) = delete;
SafeWebBundleParser& operator=(const SafeWebBundleParser&) = delete;
// Remaining callbacks on flight will be dropped.
~SafeWebBundleParser();
// Parses the integrity block of a Signed Web Bundle. See
// `web_package::mojom::WebBundleParser::ParseIntegrityBlock` for
// details. This method fails when it's called before the previous call
// finishes.
void ParseIntegrityBlock(
web_package::mojom::WebBundleParser::ParseIntegrityBlockCallback
callback);
// Parses metadata of a (Signed) Web Bundle. If `offset` is specified, then
// parsing of the metadata starts at that offset. If `offset` is not set, then
// parsing either starts at offset 0 for non-random-access data sources, or at
// a position based on the `length` field of the Web Bundle for random access
// data sources. See `web_package::mojom::WebBundleParser::ParseMetadata` for
// details. This method fails when it's called before the previous call
// finishes.
void ParseMetadata(
std::optional<uint64_t> offset,
web_package::mojom::WebBundleParser::ParseMetadataCallback callback);
// Parses a response from a (Signed) Web Bundle. See
// `web_package::mojom::WebBundleParser::ParseResponse` for details.
void ParseResponse(
uint64_t response_offset,
uint64_t response_length,
web_package::mojom::WebBundleParser::ParseResponseCallback callback);
// Closes the data source this class is reading from by calling
// `DataSourceCreatingStrategy::Close`.
// One can use this function to know the point after which the source file
// is closed and can be removed.
// If the caller doesn't care when the file is closed, then it is fine
// to destroy the instance of this class without calling this function.
// The callback will not be called if the instance of this class
// is destroyed.
void Close(base::OnceClosure callback);
private:
web_package::mojom::WebBundleParserFactory* GetFactory();
void OnDisconnect();
void OnIntegrityBlockParsed(
web_package::mojom::BundleIntegrityBlockPtr integrity_block,
web_package::mojom::BundleIntegrityBlockParseErrorPtr error);
void OnMetadataParsed(web_package::mojom::BundleMetadataPtr metadata,
web_package::mojom::BundleMetadataParseErrorPtr error);
void OnResponseParsed(size_t callback_id,
web_package::mojom::BundleResponsePtr response,
web_package::mojom::BundleResponseParseErrorPtr error);
base::expected<void, std::string> ConnectIfNecessary();
void CloseDataSourceCreator();
void ReplyClosed();
struct Connection {
Connection();
~Connection();
DataDecoder data_decoder_;
mojo::Remote<web_package::mojom::WebBundleParserFactory> factory_;
mojo::Remote<web_package::mojom::WebBundleParser> parser_;
};
bool is_connected() const { return connection_.get(); }
std::unique_ptr<Connection> connection_;
std::unique_ptr<DataSourceCreatingStrategy> data_source_creator_;
web_package::mojom::WebBundleParser::ParseIntegrityBlockCallback
integrity_block_callback_;
web_package::mojom::WebBundleParser::ParseMetadataCallback metadata_callback_;
base::flat_map<size_t,
web_package::mojom::WebBundleParser::ParseResponseCallback>
response_callbacks_;
base::OnceClosure close_callback_;
size_t response_callback_next_id_ = 0;
std::optional<GURL> base_url_;
base::WeakPtrFactory<SafeWebBundleParser> weak_factory_{this};
};
} // namespace data_decoder
#endif // SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_WEB_BUNDLE_PARSER_H_