blob: 28a914f3e37260331a85abeabd6fe76862dc0b39 [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_DATA_DECODER_H_
#define SERVICES_DATA_DECODER_PUBLIC_CPP_DATA_DECODER_H_
#include <optional>
#include <string>
#include "base/functional/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "base/values.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/http/structured_headers.h"
#include "services/data_decoder/public/cpp/service_provider.h"
#include "services/data_decoder/public/mojom/data_decoder_service.mojom.h"
#include "services/data_decoder/public/mojom/xml_parser.mojom.h"
namespace mojo_base {
class BigBuffer;
}
namespace data_decoder {
// IMPORTANT: Before adding something, please consider if there is a viable
// memory-safe implementation; the data decoder is already a grab bag of random
// stuff and process startup time can be a major performance tax, especially on
// mobile.
//
// Encapsulates an exclusive connection to an isolated instance of the Data
// Decoder service, allowing an owner to perform a series of related decoding
// operations using the same isolated instance. The application must provide
// an instance of |ServiceProvider| via |ServiceProvider::Set()| prior to using
// this class.
//
// In general, instance reuse should only be considered after weighing the cost
// of new service processes vs the security and privacy value of increased
// isolation.
//
// Finally, there is no guarantee that a single DataDecoder instance will
// perform all out-of-process operations within the same service process; if
// idle for long periods of time, the service process may be killed and only
// restarted once needed again.
//
// Tests can construct an data_decoder::test::InProcessDataDecoderService to
// ensure that all DataDecoders constructed during its lifetime will connect to
// that instance rather than launching a separate process.
class DataDecoder {
public:
// Creates a DataDecoder with an implementation-defined default timeout.
DataDecoder();
// Creates a DataDecoder with the specified timeout.
explicit DataDecoder(base::TimeDelta idle_timeout);
DataDecoder(const DataDecoder&) = delete;
DataDecoder& operator=(const DataDecoder&) = delete;
~DataDecoder();
using ValueOrError = base::expected<base::Value, std::string>;
template <typename T>
using ResultCallback =
base::OnceCallback<void(base::expected<T, std::string>)>;
using StructuredHeaderParseItemCallback =
ResultCallback<net::structured_headers::ParameterizedItem>;
using StructuredHeaderParseListCallback =
ResultCallback<net::structured_headers::List>;
using StructuredHeaderParseDictionaryCallback =
ResultCallback<net::structured_headers::Dictionary>;
using ValueParseCallback = ResultCallback<base::Value>;
using GzipperCallback = ResultCallback<mojo_base::BigBuffer>;
using ValidationCallback =
ResultCallback<payments::facilitated::mojom::PixQrCodeType>;
using CancellationFlag = base::RefCountedData<bool>;
// Returns a raw interface to the service instance. This launches an instance
// of the service process if possible on the current platform, or returns a
// connection to the in-process instance of in a test environment using
// InProcessDataDecoderService.
mojom::DataDecoderService* GetService();
// Parses the potentially unsafe JSON string in |json| using this
// DataDecoder's service instance or some other platform-specific decoding
// facility. The parser conforms to RFC 8259.
//
// Note that |callback| will only be called if the parsing operation succeeds
// or fails before this DataDecoder is destroyed.
void ParseJson(const std::string& json, ValueParseCallback callback);
// Parses the potentially unsafe JSON string in |json|. This static helper
// uses a dedicated instance of the Data Decoder service on applicable
// platforms.
static void ParseJsonIsolated(const std::string& json,
ValueParseCallback callback);
// Parses the potentially unsafe string in |header| as a structured header
// item using this DataDecoder's service instance or some other
// platform-specific decoding facility.
//
// Note that |callback| will only be called if the parsing operation succeeds
// or fails before this DataDecoder is destroyed.
void ParseStructuredHeaderItem(const std::string& header,
StructuredHeaderParseItemCallback callback);
// Parses the potentially unsafe string in |header| as a structured header
// item. This static helper uses a dedicated instance of the Data Decoder
// service on applicable platforms.
static void ParseStructuredHeaderItemIsolated(
const std::string& header,
StructuredHeaderParseItemCallback callback);
// Parses the potentially unsafe string in |header| as a structured header
// list using this DataDecoder's service instance or some other
// platform-specific decoding facility.
//
// Note that |callback| will only be called if the parsing operation succeeds
// or fails before this DataDecoder is destroyed.
void ParseStructuredHeaderList(const std::string& header,
StructuredHeaderParseListCallback callback);
// Parses the potentially unsafe string in |header| as a structured header
// list. This static helper uses a dedicated instance of the Data Decoder
// service on applicable platforms.
static void ParseStructuredHeaderListIsolated(
const std::string& header,
StructuredHeaderParseListCallback callback);
// Parses the potentially unsafe string in `header` as a structured header
// dictionary using this DataDecoder's service instance or some other
// platform-specific decoding facility.
//
// Note that `callback` will only be called if the parsing operation succeeds
// or fails before this DataDecoder is destroyed.
void ParseStructuredHeaderDictionary(
const std::string& header,
StructuredHeaderParseDictionaryCallback callback);
// Parses the potentially unsafe string in `header` as a structured header
// dictionary. This static helper uses a dedicated instance of the Data
// Decoder service on applicable platforms.
static void ParseStructuredHeaderDictionaryIsolated(
const std::string& header,
StructuredHeaderParseDictionaryCallback callback);
// Parses the potentially unsafe XML string in |xml| using this
// DataDecoder's service instance. The Value provided to the callback
// is a structured tree representing the XML document. See
// ../mojom/xml_parser.mojom for details on the structure, and
// safe_xml_parser.h for utilities to access parsed data.
//
// Note that |callback| will only be called if the parsing operation succeeds
// or fails before this DataDecoder is destroyed.
void ParseXml(const std::string& xml,
mojom::XmlParser::WhitespaceBehavior whitespace_behavior,
ValueParseCallback callback);
// Parses the potentially unsafe XML string in |xml|. This static helper
// uses a dedicated instance of the Data Decoder service on applicable
// platforms.
static void ParseXmlIsolated(
const std::string& xml,
mojom::XmlParser::WhitespaceBehavior whitespace_behavior,
ValueParseCallback callback);
// Deflates potentially unsafe |data| using this DataDecoder's service
// instance. This will use raw DEFLATE, i.e. no headers are outputted.
//
// Note that |callback| will only be called if the parsing operation succeeds
// or fails before this DataDecoder is destroyed.
void Deflate(base::span<const uint8_t> data, GzipperCallback callback);
// Inflates potentially unsafe |data| using this DataDecoder's service
// instance. |data| must have been deflated raw, i.e. with no headers. If the
// uncompressed data exceeds |max_uncompressed_size|, returns empty.
//
// Note that |callback| will only be called if the parsing operation succeeds
// or fails before this DataDecoder is destroyed.
void Inflate(base::span<const uint8_t> data,
uint64_t max_uncompressed_size,
GzipperCallback callback);
// Compresses potentially unsafe |data| using this DataDecoder's service
// instance.
//
// Note that |callback| will only be called if the parsing operation succeeds
// or fails before this DataDecoder is destroyed.
void GzipCompress(base::span<const uint8_t> data, GzipperCallback callback);
// Uncompresses potentially unsafe |data| using this DataDecoder's service
// instance.
//
// Note that |callback| will only be called if the parsing operation succeeds
// or fails before this DataDecoder is destroyed.
void GzipUncompress(base::span<const uint8_t> data, GzipperCallback callback);
// Parses the potentially unsafe CBOR bytes in |cbor| using this
// DataDecoder's service instance or some other platform-specific decoding
// facility. The parser conforms to RFC 7049, except a few limitations:
// - Does not support null or undefined values.
// - Integers must fit in the 'int' type.
// - The keys in Maps must be a string or byte-string.
// - If at least one Map key is invalid, an error will be returned.
//
// Note that |callback| will only be called if the parsing operation succeeds
// or fails before this DataDecoder is destroyed.
void ParseCbor(base::span<const uint8_t> cbor, ValueParseCallback callback);
// Validates the format of the potentially unsafe `pix_code`.
void ValidatePixCode(const std::string& pix_code,
ValidationCallback callback);
private:
// The amount of idle time to tolerate on a DataDecoder instance. If the
// instance is unused for this period of time, the underlying service process
// (if any) may be killed and only restarted once needed again.
// On platforms (like iOS) or environments (like some unit tests) where
// out-of-process services are not used, this has no effect.
base::TimeDelta idle_timeout_;
// This instance's connection to the service. This connection is lazily
// established and may be reset after long periods of idle time.
mojo::Remote<mojom::DataDecoderService> service_;
// Cancellation flag for any outstanding requests. When a request is
// started, it takes a reference to this flag. Upon the destruction of this
// instance, the flag is set to `true`. Any outstanding requests should check
// this flag, and if it is `true`, they should not run the callback, per
// the API guarantees above.
scoped_refptr<CancellationFlag> cancel_requests_;
};
} // namespace data_decoder
#endif // SERVICES_DATA_DECODER_PUBLIC_CPP_DATA_DECODER_H_