Commit b2cb6eca authored by Robert Sesek's avatar Robert Sesek Committed by Commit Bot

Add XML parsing interfaces to the new DataDecoder API.

Bug: 977637
Change-Id: I46198e40724c0985c2a59b7ac7ebeb1479f286d2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1888714Reviewed-by: default avatarKen Rockot <rockot@google.com>
Commit-Queue: Robert Sesek <rsesek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#710656}
parent 011e523c
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "services/data_decoder/public/mojom/json_parser.mojom.h" #include "services/data_decoder/public/mojom/json_parser.mojom.h"
#include "services/data_decoder/public/mojom/xml_parser.mojom.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
#include "base/json/json_reader.h" #include "base/json/json_reader.h"
...@@ -28,52 +29,57 @@ namespace { ...@@ -28,52 +29,57 @@ namespace {
constexpr base::TimeDelta kServiceProcessIdleTimeout{ constexpr base::TimeDelta kServiceProcessIdleTimeout{
base::TimeDelta::FromSeconds(5)}; base::TimeDelta::FromSeconds(5)};
#if !defined(OS_ANDROID) // Encapsulates an in-process data decoder parsing request. This provides shared
// Encapsulates an in-process JSON parsing request. This provides shared
// ownership of the caller's callback so that it may be invoked exactly once by // ownership of the caller's callback so that it may be invoked exactly once by
// *either* the successful response handler *or* the JsonParser's disconnection // *either* the successful response handler *or* the parsers's disconnection
// handler. This also owns a Remote<mojom::JsonParser> which is kept alive for // handler. This also owns a Remote<T> which is kept alive for the duration of
// the duration of the request. // the request.
class ValueParseRequest : public base::RefCounted<ValueParseRequest> { template <typename T>
class ValueParseRequest : public base::RefCounted<ValueParseRequest<T>> {
public: public:
explicit ValueParseRequest(DataDecoder::ValueParseCallback callback) explicit ValueParseRequest(DataDecoder::ValueParseCallback callback)
: callback_(std::move(callback)) {} : callback_(std::move(callback)) {}
mojo::Remote<mojom::JsonParser>& json_parser() { return json_parser_; } mojo::Remote<T>& remote() { return remote_; }
DataDecoder::ValueParseCallback& callback() { return callback_; } DataDecoder::ValueParseCallback& callback() { return callback_; }
// Creates a pipe and binds it to the remote(), and sets up the
// disconnect handler to invoke callback() with an error.
mojo::PendingReceiver<T> BindRemote() {
auto receiver = remote_.BindNewPipeAndPassReceiver();
remote_.set_disconnect_handler(
base::BindOnce(&ValueParseRequest::OnRemoteDisconnected, this));
return receiver;
}
// Handles a successful parse from the service.
void OnServiceValueOrError(base::Optional<base::Value> value,
const base::Optional<std::string>& error) {
DataDecoder::ValueOrError result;
if (value)
result.value = std::move(value);
else
result.error = error.value_or("unknown error");
std::move(callback()).Run(std::move(result));
}
private: private:
friend class base::RefCounted<ValueParseRequest>; friend class base::RefCounted<ValueParseRequest>;
~ValueParseRequest() = default; ~ValueParseRequest() = default;
mojo::Remote<mojom::JsonParser> json_parser_; void OnRemoteDisconnected() {
std::move(callback())
.Run(DataDecoder::ValueOrError::Error(
"Data Decoder terminated unexpectedly"));
}
mojo::Remote<T> remote_;
DataDecoder::ValueParseCallback callback_; DataDecoder::ValueParseCallback callback_;
DISALLOW_COPY_AND_ASSIGN(ValueParseRequest); DISALLOW_COPY_AND_ASSIGN(ValueParseRequest);
}; };
// Handles a successful JSON parse from the service.
void OnServiceValueOrError(scoped_refptr<ValueParseRequest> request,
base::Optional<base::Value> value,
const base::Optional<std::string>& error) {
DataDecoder::ValueOrError result;
if (value)
result.value = std::move(value);
else
result.error = error.value_or("unknown error");
std::move(request->callback()).Run(std::move(result));
}
// Handles unexpected disconnection from the service during a JSON parse
// request. This typically means the service crashed.
void OnJsonParserDisconnected(scoped_refptr<ValueParseRequest> request) {
std::move(request->callback())
.Run(DataDecoder::ValueOrError::Error(
"Data Decoder terminated unexpectedly"));
}
#endif // !defined(OS_ANDROID)
} // namespace } // namespace
DataDecoder::ValueOrError::ValueOrError() = default; DataDecoder::ValueOrError::ValueOrError() = default;
...@@ -145,13 +151,13 @@ void DataDecoder::ParseJson(const std::string& json, ...@@ -145,13 +151,13 @@ void DataDecoder::ParseJson(const std::string& json,
}, },
std::move(callback))); std::move(callback)));
#else #else
auto request = base::MakeRefCounted<ValueParseRequest>(std::move(callback)); auto request = base::MakeRefCounted<ValueParseRequest<mojom::JsonParser>>(
GetService()->BindJsonParser( std::move(callback));
request->json_parser().BindNewPipeAndPassReceiver()); GetService()->BindJsonParser(request->BindRemote());
request->json_parser().set_disconnect_handler( request->remote()->Parse(
base::BindOnce(&OnJsonParserDisconnected, request)); json, base::BindOnce(
request->json_parser()->Parse( &ValueParseRequest<mojom::JsonParser>::OnServiceValueOrError,
json, base::BindOnce(&OnServiceValueOrError, request)); request));
#endif #endif
} }
...@@ -172,4 +178,32 @@ void DataDecoder::ParseJsonIsolated(const std::string& json, ...@@ -172,4 +178,32 @@ void DataDecoder::ParseJsonIsolated(const std::string& json,
std::move(decoder), std::move(callback))); std::move(decoder), std::move(callback)));
} }
void DataDecoder::ParseXml(const std::string& xml,
ValueParseCallback callback) {
auto request = base::MakeRefCounted<ValueParseRequest<mojom::XmlParser>>(
std::move(callback));
GetService()->BindXmlParser(request->BindRemote());
request->remote()->Parse(
xml, base::BindOnce(
&ValueParseRequest<mojom::XmlParser>::OnServiceValueOrError,
request));
}
// static
void DataDecoder::ParseXmlIsolated(const std::string& xml,
ValueParseCallback callback) {
auto decoder = std::make_unique<DataDecoder>();
auto* raw_decoder = decoder.get();
// We bind the DataDecoder's ownership into the result callback to ensure that
// it stays alive until the operation is complete.
raw_decoder->ParseXml(
xml, base::BindOnce(
[](std::unique_ptr<DataDecoder>, ValueParseCallback callback,
ValueOrError result) {
std::move(callback).Run(std::move(result));
},
std::move(decoder), std::move(callback)));
}
} // namespace data_decoder } // namespace data_decoder
...@@ -45,9 +45,9 @@ class DataDecoder { ...@@ -45,9 +45,9 @@ class DataDecoder {
DataDecoder(); DataDecoder();
~DataDecoder(); ~DataDecoder();
// The result of a |ParseJson()| or |ParseJsonIsolated()| call. Exactly one of // The result of a Parse*() call that can return either a Value or an error
// either |value| or |error| will have a value when returned by either // string. Exactly one of either |value| or |error| will have a value when
// operation. // returned by either operation.
struct ValueOrError { struct ValueOrError {
ValueOrError(); ValueOrError();
ValueOrError(ValueOrError&&); ValueOrError(ValueOrError&&);
...@@ -60,6 +60,8 @@ class DataDecoder { ...@@ -60,6 +60,8 @@ class DataDecoder {
base::Optional<std::string> error; base::Optional<std::string> error;
}; };
using ValueParseCallback = base::OnceCallback<void(ValueOrError)>;
// Returns a raw interface to the service instance. This launches an instance // 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 // 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 // connection to the in-process instance of in a test environment using
...@@ -72,7 +74,6 @@ class DataDecoder { ...@@ -72,7 +74,6 @@ class DataDecoder {
// //
// Note that |callback| will only be called if the parsing operation succeeds // Note that |callback| will only be called if the parsing operation succeeds
// or fails before this DataDecoder is destroyed. // or fails before this DataDecoder is destroyed.
using ValueParseCallback = base::OnceCallback<void(ValueOrError)>;
void ParseJson(const std::string& json, ValueParseCallback callback); void ParseJson(const std::string& json, ValueParseCallback callback);
// Parses the potentially unsafe JSON string in |json|. This static helper // Parses the potentially unsafe JSON string in |json|. This static helper
...@@ -81,6 +82,22 @@ class DataDecoder { ...@@ -81,6 +82,22 @@ class DataDecoder {
static void ParseJsonIsolated(const std::string& json, static void ParseJsonIsolated(const std::string& json,
ValueParseCallback callback); ValueParseCallback 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, 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,
ValueParseCallback callback);
private: private:
// This instance's connection to the service. This connection is lazily // This instance's connection to the service. This connection is lazily
// established and may be reset after long periods of idle time. // established and may be reset after long periods of idle time.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment