Chromium Code Reviews| Index: chrome/utility/media_router/dial_device_description_parser_impl.cc |
| diff --git a/chrome/utility/media_router/dial_device_description_parser_impl.cc b/chrome/utility/media_router/dial_device_description_parser_impl.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..65061fd7a4c542b0ca6758fa45fc824f85cce9f3 |
| --- /dev/null |
| +++ b/chrome/utility/media_router/dial_device_description_parser_impl.cc |
| @@ -0,0 +1,130 @@ |
| +// Copyright 2017 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 "chrome/utility/media_router/dial_device_description_parser_impl.h" |
| + |
| +#include <libxml/parser.h> |
| +#include <libxml/tree.h> |
| +#include <libxml/xpath.h> |
| + |
| +#include "base/strings/string_util.h" |
| +#include "mojo/public/cpp/bindings/strong_binding.h" |
| +#include "third_party/libxml/chromium/libxml_utils.h" |
| + |
| +namespace { |
| + |
| +static std::string Validate( |
| + const media_router::DialDeviceDescription& description) { |
| + if (description.unique_id.empty()) { |
| + return "Missing uniqueId"; |
| + } |
| + if (description.friendly_name.empty()) { |
| + return "Missing friendlyName"; |
| + } |
| + return ""; |
| +} |
| + |
| +// If friendly name does not exist, fall back to use model name + last 4 |
| +// digits of UUID as friendly name. |
| +void ComputeFriendlyName(media_router::DialDeviceDescription* out) { |
| + if (!out->friendly_name.empty()) |
|
mark a. foltz
2017/03/21 01:39:21
For clarity I would move this check back out to th
zhaobin
2017/03/21 03:15:38
Done.
|
| + return; |
| + |
| + auto model_name = out->model_name; |
| + auto unique_id = out->unique_id; |
| + |
| + if (!model_name.empty() && unique_id.length() >= 4) { |
| + out->friendly_name = |
| + model_name + "[" + unique_id.substr(unique_id.length() - 4) + "]"; |
|
mark a. foltz
2017/03/21 01:39:21
Nit: Can you add a space before [
zhaobin
2017/03/21 03:15:38
Done.
|
| + } |
| +} |
| + |
| +// Replaces "<element_name>content</element_name>" with |
| +// "<element_name>***</element_name>" |
| +void Scrub(const std::string& element_name, std::string& xml_text) { |
| + size_t pos = xml_text.find("<" + element_name + ">"); |
| + size_t end_pos = xml_text.find("</" + element_name + ">"); |
| + size_t start_pos = pos + element_name.length() + 2; |
| + |
| + if (pos != std::string::npos && end_pos != std::string::npos) |
|
mark a. foltz
2017/03/21 01:39:22
&& end_pos > start_pos
zhaobin
2017/03/21 03:15:38
Done.
|
| + xml_text.replace(start_pos, end_pos - start_pos, "***"); |
| +} |
| + |
| +} // namespace |
| + |
| +namespace media_router { |
| + |
| +DialDeviceDescriptionParserImpl::DialDeviceDescriptionParserImpl() = default; |
| +DialDeviceDescriptionParserImpl::~DialDeviceDescriptionParserImpl() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| +} |
| + |
| +// static |
| +void DialDeviceDescriptionParserImpl::Create( |
| + chrome::mojom::DialDeviceDescriptionParserRequest request) { |
| + mojo::MakeStrongBinding(base::MakeUnique<DialDeviceDescriptionParserImpl>(), |
| + std::move(request)); |
| +} |
| + |
| +void DialDeviceDescriptionParserImpl::ParseDialDeviceDescription( |
| + const std::string& device_description_xml_data, |
| + const ParseDialDeviceDescriptionCallback& callback) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(!callback.is_null()); |
| + |
| + media_router::DialDeviceDescription device_description; |
| + bool result = Parse(device_description_xml_data, &device_description); |
| + std::string logging_xml = ScrubXmlForLogging(device_description_xml_data); |
| + |
| + callback.Run(result, device_description, logging_xml); |
| +} |
| + |
| +bool DialDeviceDescriptionParserImpl::Parse( |
| + const std::string& xml, |
| + media_router::DialDeviceDescription* out) { |
| + DCHECK(out); |
| + |
| + XmlReader xml_reader; |
| + if (!xml_reader.Load(xml)) |
| + return false; |
| + |
| + while (xml_reader.Read()) { |
| + xml_reader.SkipToElement(); |
| + std::string node_name(xml_reader.NodeName()); |
| + |
| + if (node_name == "UDN") { |
| + if (!xml_reader.ReadElementContent(&out->unique_id)) |
| + return false; |
| + } else if (node_name == "friendlyName") { |
| + if (!xml_reader.ReadElementContent(&out->friendly_name)) |
| + return false; |
| + } else if (node_name == "modelName") { |
| + if (!xml_reader.ReadElementContent(&out->model_name)) |
| + return false; |
| + } else if (node_name == "deviceType") { |
| + if (!xml_reader.ReadElementContent(&out->device_type)) |
| + return false; |
| + } |
| + } |
| + |
| + ComputeFriendlyName(out); |
| + |
| + std::string error = Validate(*out); |
| + if (!error.empty()) { |
| + DLOG(WARNING) << "Device description failed to validate: " << error; |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +std::string DialDeviceDescriptionParserImpl::ScrubXmlForLogging( |
| + const std::string& xml_text) { |
| + std::string scrubbed_xml(xml_text); |
| + Scrub("UDN", scrubbed_xml); |
| + Scrub("serialNumber", scrubbed_xml); |
| + return scrubbed_xml; |
| +} |
| + |
| +} // namespace media_router |