17dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
27dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
37dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// found in the LICENSE file.
47dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
57dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/profile_resetter/brandcode_config_fetcher.h"
67dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/strings/utf_string_conversions.h"
87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/browser_process.h"
97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/profile_resetter/brandcoded_default_settings.h"
107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "libxml/parser.h"
117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "net/base/load_flags.h"
127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "net/http/http_response_headers.h"
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "net/url_request/url_fetcher.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "net/url_request/url_request_status.h"
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace {
177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst int kDownloadTimeoutSec = 10;
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst char kPostXml[] =
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch"<request version=\"1.3.17.0\" protocol=\"3.0\" testsource=\"dev\" "
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    "shell_version=\"1.2.3.5\">\n"
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch"  <os platform=\"win\" version=\"6.1\" sp=\"\" arch=\"x86\" />\n"
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch"  <app\n"
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch"    appid=\"{8A69D345-D564-463C-AFF1-A69D9E530F96}\"\n"
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch"    version=\"0.0.0.0\"\n"
277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch"      >\n"
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch"    <updatecheck />\n"
297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch"    <data name=\"install\" "
3058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    "index=\"__BRANDCODE_PLACEHOLDER__\" />\n"
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch"  </app>\n"
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch"</request>";
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// Returns the query to the server which can be used to retrieve the config.
3558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// |brand| is a brand code, it mustn't be empty.
3658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochstd::string GetUploadData(const std::string& brand) {
3758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  DCHECK(!brand.empty());
3858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  std::string data(kPostXml);
3958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  const std::string placeholder("__BRANDCODE_PLACEHOLDER__");
4058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  size_t placeholder_pos = data.find(placeholder);
4158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  DCHECK(placeholder_pos != std::string::npos);
4258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  data.replace(placeholder_pos, placeholder.size(), brand);
4358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  return data;
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Extracts json master prefs from xml.
477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass XmlConfigParser {
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch public:
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  XmlConfigParser();
507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ~XmlConfigParser();
517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Returns the content of /response/app/data tag.
537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  static void Parse(const std::string& input_buffer,
547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    std::string* output_buffer);
557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch private:
577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  static XmlConfigParser* FromContext(void* ctx);
587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  static std::string XMLCharToString(const xmlChar* value);
597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  static void StartElementImpl(void* ctx,
607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                               const xmlChar* name,
617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                               const xmlChar** atts);
627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  static void EndElementImpl(void* ctx, const xmlChar* name);
637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  static void CharactersImpl(void* ctx, const xmlChar* ch, int len);
647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool IsParsingData() const;
667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Extracted json file.
687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::string master_prefs_;
697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Current stack of the elements being parsed.
717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::vector<std::string> elements_;
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(XmlConfigParser);
747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch};
757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
767dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochXmlConfigParser::XmlConfigParser() {}
777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
787dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochXmlConfigParser::~XmlConfigParser() {}
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid XmlConfigParser::Parse(const std::string& input_buffer,
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            std::string* output_buffer) {
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  using logging::LOG_WARNING;
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(output_buffer);
857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  xmlSAXHandler sax_handler = {};
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sax_handler.startElement = &XmlConfigParser::StartElementImpl;
877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sax_handler.endElement = &XmlConfigParser::EndElementImpl;
887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sax_handler.characters = &XmlConfigParser::CharactersImpl;
897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  XmlConfigParser parser;
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int error = xmlSAXUserParseMemory(&sax_handler,
917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    &parser,
927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    input_buffer.c_str(),
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    input_buffer.size());
947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (error) {
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    VLOG(LOG_WARNING) << "Error parsing brandcoded master prefs, err=" << error;
967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  } else {
977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    output_buffer->swap(parser.master_prefs_);
987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochXmlConfigParser* XmlConfigParser::FromContext(void* ctx) {
1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return static_cast<XmlConfigParser*>(ctx);
1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstd::string XmlConfigParser::XMLCharToString(const xmlChar* value) {
1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return std::string(reinterpret_cast<const char*>(value));
1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid XmlConfigParser::StartElementImpl(void* ctx,
1107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                       const xmlChar* name,
1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                       const xmlChar** atts) {
1127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::string node_name(XMLCharToString(name));
1137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  XmlConfigParser* context = FromContext(ctx);
1147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  context->elements_.push_back(node_name);
1157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (context->IsParsingData())
1167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    context->master_prefs_.clear();
1177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid XmlConfigParser::EndElementImpl(void* ctx, const xmlChar* name) {
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  XmlConfigParser* context = FromContext(ctx);
1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  context->elements_.pop_back();
1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid XmlConfigParser::CharactersImpl(void* ctx, const xmlChar* ch, int len) {
1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  XmlConfigParser* context = FromContext(ctx);
1267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (context->IsParsingData()) {
1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    context->master_prefs_ +=
1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        std::string(reinterpret_cast<const char*>(ch), len);
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool XmlConfigParser::IsParsingData() const {
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const std::string data_path[] = {"response", "app", "data"};
1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return elements_.size() == arraysize(data_path) &&
1357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch         std::equal(elements_.begin(), elements_.end(), data_path);
1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} // namespace
1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochBrandcodeConfigFetcher::BrandcodeConfigFetcher(const FetchCallback& callback,
14158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch                                               const GURL& url,
14258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch                                               const std::string& brandcode)
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    : fetch_callback_(callback) {
14458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  DCHECK(!brandcode.empty());
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  config_fetcher_.reset(net::URLFetcher::Create(0 /* ID used for testing */,
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                                url,
1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                                net::URLFetcher::POST,
1487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                                this));
1497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  config_fetcher_->SetRequestContext(
1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      g_browser_process->system_request_context());
15158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  config_fetcher_->SetUploadData("text/xml", GetUploadData(brandcode));
1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  config_fetcher_->AddExtraRequestHeader("Accept: text/xml");
1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  config_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                net::LOAD_DO_NOT_SAVE_COOKIES |
1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                net::LOAD_DISABLE_CACHE);
1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  config_fetcher_->Start();
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Abort the download attempt if it takes too long.
1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  download_timer_.Start(FROM_HERE,
1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        base::TimeDelta::FromSeconds(kDownloadTimeoutSec),
1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        this,
1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        &BrandcodeConfigFetcher::OnDownloadTimeout);
1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochBrandcodeConfigFetcher::~BrandcodeConfigFetcher() {}
1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid BrandcodeConfigFetcher::SetCallback(const FetchCallback& callback) {
1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  fetch_callback_ = callback;
1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid BrandcodeConfigFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
1717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (source != config_fetcher_.get()) {
1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    NOTREACHED() << "Callback from foreign URL fetcher";
1737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::string response_string;
1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::string mime_type;
1777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (config_fetcher_ &&
1787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      config_fetcher_->GetStatus().is_success() &&
1797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      config_fetcher_->GetResponseCode() == 200 &&
1807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      config_fetcher_->GetResponseHeaders()->GetMimeType(&mime_type) &&
1817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      mime_type == "text/xml" &&
1827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      config_fetcher_->GetResponseAsString(&response_string)) {
1837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    std::string master_prefs;
1847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    XmlConfigParser::Parse(response_string, &master_prefs);
1857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    default_settings_.reset(new BrandcodedDefaultSettings(master_prefs));
1867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  config_fetcher_.reset();
1887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  download_timer_.Stop();
1897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  fetch_callback_.Run();
1907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid BrandcodeConfigFetcher::OnDownloadTimeout() {
1937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (config_fetcher_) {
1947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    config_fetcher_.reset();
1957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    fetch_callback_.Run();
1967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
198