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

Parse XML using the DataDecoder service in BrandcodeConfigFetcher.

Using libxml directly in the browser process is strongly discouraged.

Bug: 699306
Change-Id: I82a976bfa578cc89e855079aadcfed95abdffe95
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1890819Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Commit-Queue: Robert Sesek <rsesek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#711217}
parent 2b64a6ce
......@@ -8,14 +8,15 @@
#include <vector>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile_resetter/brandcoded_default_settings.h"
#include "libxml/parser.h"
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/data_decoder/public/cpp/safe_xml_parser.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
......@@ -46,98 +47,6 @@ std::string GetUploadData(const std::string& brand) {
return data;
}
// Extracts json master prefs from xml.
class XmlConfigParser {
public:
XmlConfigParser();
~XmlConfigParser();
// Returns the content of /response/app/data tag.
static void Parse(const std::string& input_buffer,
std::string* output_buffer);
private:
static XmlConfigParser* FromContext(void* ctx);
static std::string XMLCharToString(const xmlChar* value);
static void StartElementImpl(void* ctx,
const xmlChar* name,
const xmlChar** atts);
static void EndElementImpl(void* ctx, const xmlChar* name);
static void CharactersImpl(void* ctx, const xmlChar* ch, int len);
bool IsParsingData() const;
// Extracted json file.
std::string master_prefs_;
// Current stack of the elements being parsed.
std::vector<std::string> elements_;
DISALLOW_COPY_AND_ASSIGN(XmlConfigParser);
};
XmlConfigParser::XmlConfigParser() {}
XmlConfigParser::~XmlConfigParser() {}
void XmlConfigParser::Parse(const std::string& input_buffer,
std::string* output_buffer) {
using logging::LOG_WARNING;
DCHECK(output_buffer);
xmlSAXHandler sax_handler = {};
sax_handler.startElement = &XmlConfigParser::StartElementImpl;
sax_handler.endElement = &XmlConfigParser::EndElementImpl;
sax_handler.characters = &XmlConfigParser::CharactersImpl;
XmlConfigParser parser;
int error = xmlSAXUserParseMemory(&sax_handler,
&parser,
input_buffer.c_str(),
input_buffer.size());
if (error) {
VLOG(LOG_WARNING) << "Error parsing brandcoded master prefs, err=" << error;
} else {
output_buffer->swap(parser.master_prefs_);
}
}
XmlConfigParser* XmlConfigParser::FromContext(void* ctx) {
return static_cast<XmlConfigParser*>(ctx);
}
std::string XmlConfigParser::XMLCharToString(const xmlChar* value) {
return std::string(reinterpret_cast<const char*>(value));
}
void XmlConfigParser::StartElementImpl(void* ctx,
const xmlChar* name,
const xmlChar** atts) {
std::string node_name(XMLCharToString(name));
XmlConfigParser* context = FromContext(ctx);
context->elements_.push_back(node_name);
if (context->IsParsingData())
context->master_prefs_.clear();
}
void XmlConfigParser::EndElementImpl(void* ctx, const xmlChar* name) {
XmlConfigParser* context = FromContext(ctx);
context->elements_.pop_back();
}
void XmlConfigParser::CharactersImpl(void* ctx, const xmlChar* ch, int len) {
XmlConfigParser* context = FromContext(ctx);
if (context->IsParsingData()) {
context->master_prefs_ +=
std::string(reinterpret_cast<const char*>(ch), len);
}
}
bool XmlConfigParser::IsParsingData() const {
const std::string data_path[] = {"response", "app", "data"};
return elements_.size() == base::size(data_path) &&
std::equal(elements_.begin(), elements_.end(), data_path);
}
} // namespace
BrandcodeConfigFetcher::BrandcodeConfigFetcher(
......@@ -200,13 +109,43 @@ void BrandcodeConfigFetcher::OnSimpleLoaderComplete(
std::unique_ptr<std::string> response_body) {
if (response_body && simple_url_loader_->ResponseInfo() &&
simple_url_loader_->ResponseInfo()->mime_type == "text/xml") {
std::string master_prefs;
XmlConfigParser::Parse(*response_body, &master_prefs);
default_settings_.reset(new BrandcodedDefaultSettings(master_prefs));
data_decoder::DataDecoder::ParseXmlIsolated(
*response_body,
base::BindOnce(&BrandcodeConfigFetcher::OnXmlConfigParsed,
base::Unretained(this)));
} else {
std::move(fetch_callback_).Run();
}
simple_url_loader_.reset();
download_timer_.Stop();
std::move(fetch_callback_).Run();
}
void BrandcodeConfigFetcher::OnXmlConfigParsed(
data_decoder::DataDecoder::ValueOrError value_or_error) {
// The |fetch_callback_| is called in the case of either success or
// failure. The difference is whether |default_settings_| is populated.
base::ScopedClosureRunner scoped_closure(std::move(fetch_callback_));
if (!value_or_error.value)
return;
const base::Value* node = &value_or_error.value.value();
if (!data_decoder::IsXmlElementNamed(*node, "response"))
return;
// Descend this tag path to find the node containing the JSON data.
const char* kDataPath[] = {"app", "data"};
for (const auto* tag : kDataPath) {
node = data_decoder::GetXmlElementChildWithTag(*node, tag);
if (!node)
return;
}
// Extract the text JSON data from the "data" node to specify the new
// settings.
std::string master_prefs;
if (node && data_decoder::GetXmlElementText(*node, &master_prefs))
default_settings_.reset(new BrandcodedDefaultSettings(master_prefs));
}
void BrandcodeConfigFetcher::OnDownloadTimeout() {
......
......@@ -12,6 +12,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/timer/timer.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
class BrandcodedDefaultSettings;
class GURL;
......@@ -46,6 +47,8 @@ class BrandcodeConfigFetcher {
private:
void OnSimpleLoaderComplete(std::unique_ptr<std::string> response_body);
void OnXmlConfigParsed(
data_decoder::DataDecoder::ValueOrError value_or_error);
void OnDownloadTimeout();
......
......@@ -53,6 +53,7 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/test/test_url_loader_factory.h"
#include "services/network/test/test_utils.h"
......@@ -205,6 +206,7 @@ class ConfigParserTest : public testing::Test {
content::BrowserTaskEnvironment task_environment_;
network::TestURLLoaderFactory test_url_loader_factory_;
data_decoder::test::InProcessDataDecoder data_decoder_;
};
ConfigParserTest::ConfigParserTest()
......
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