autofill_xml_parser.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/autofill/core/browser/autofill_xml_parser.h"
6
7#include <stdlib.h>
8#include <string.h>
9
10#include "base/logging.h"
11#include "components/autofill/core/browser/autofill_server_field_info.h"
12#include "third_party/libjingle/source/talk/xmllite/qname.h"
13
14namespace autofill {
15
16AutofillXmlParser::AutofillXmlParser()
17    : succeeded_(true) {
18}
19
20AutofillXmlParser::~AutofillXmlParser() {}
21
22void AutofillXmlParser::CharacterData(
23    buzz::XmlParseContext* context, const char* text, int len) {
24}
25
26void AutofillXmlParser::EndElement(buzz::XmlParseContext* context,
27                                   const char* name) {
28}
29
30void AutofillXmlParser::Error(buzz::XmlParseContext* context,
31                              XML_Error error_code) {
32  succeeded_ = false;
33}
34
35AutofillQueryXmlParser::AutofillQueryXmlParser(
36    std::vector<AutofillServerFieldInfo>* field_infos,
37    UploadRequired* upload_required)
38    : field_infos_(field_infos),
39      upload_required_(upload_required) {
40  DCHECK(upload_required_);
41}
42
43AutofillQueryXmlParser::~AutofillQueryXmlParser() {}
44
45void AutofillQueryXmlParser::StartElement(buzz::XmlParseContext* context,
46                                          const char* name,
47                                          const char** attrs) {
48  buzz::QName qname = context->ResolveQName(name, false);
49  const std::string& element = qname.LocalPart();
50  if (element.compare("autofillqueryresponse") == 0) {
51    // We check for the upload required attribute below, but if it's not
52    // present, we use the default upload rates.
53    *upload_required_ = USE_UPLOAD_RATES;
54
55    // |attrs| is a NULL-terminated list of (attribute, value) pairs.
56    while (*attrs) {
57      buzz::QName attribute_qname = context->ResolveQName(*attrs, true);
58      ++attrs;
59      const std::string& attribute_name = attribute_qname.LocalPart();
60      if (attribute_name.compare("uploadrequired") == 0) {
61        if (strcmp(*attrs, "true") == 0)
62          *upload_required_ = UPLOAD_REQUIRED;
63        else if (strcmp(*attrs, "false") == 0)
64          *upload_required_ = UPLOAD_NOT_REQUIRED;
65      }
66      ++attrs;
67    }
68  } else if (element.compare("field") == 0) {
69    if (!*attrs) {
70      // Missing the "autofilltype" attribute, abort.
71      context->RaiseError(XML_ERROR_ABORTED);
72      return;
73    }
74
75    // Determine the field type from the attribute value.  There should be one
76    // attribute (autofilltype) with an integer value.
77    AutofillServerFieldInfo field_info;
78    field_info.field_type = UNKNOWN_TYPE;
79
80    // |attrs| is a NULL-terminated list of (attribute, value) pairs.
81    while (*attrs) {
82      buzz::QName attribute_qname = context->ResolveQName(*attrs, true);
83      ++attrs;
84      const std::string& attribute_name = attribute_qname.LocalPart();
85      if (attribute_name.compare("autofilltype") == 0) {
86        int value = GetIntValue(context, *attrs);
87        if (value >= 0 && value < MAX_VALID_FIELD_TYPE)
88          field_info.field_type = static_cast<ServerFieldType>(value);
89        else
90          field_info.field_type = NO_SERVER_DATA;
91      } else if (field_info.field_type == FIELD_WITH_DEFAULT_VALUE &&
92                 attribute_name.compare("defaultvalue") == 0) {
93        field_info.default_value = *attrs;
94      }
95      ++attrs;
96    }
97
98    // Record this field type, default value pair.
99    field_infos_->push_back(field_info);
100  }
101}
102
103void AutofillQueryXmlParser::ParseElementDescriptor(
104    buzz::XmlParseContext* context,
105    const char* const* attrs,
106    WebElementDescriptor* element_descriptor) {
107  // If both id and css_selector are set, the first one to appear will take
108  // precedence.
109  // |attrs| is a NULL-terminated list of (attribute, value) pairs.
110  while (*attrs) {
111    buzz::QName attribute_qname = context->ResolveQName(*attrs, true);
112    ++attrs;
113    const std::string& attribute_name = attribute_qname.LocalPart();
114    buzz::QName value_qname = context->ResolveQName(*attrs, true);
115    ++attrs;
116    const std::string& attribute_value = value_qname.LocalPart();
117    if (attribute_name.compare("id") == 0 && !attribute_value.empty()) {
118      element_descriptor->retrieval_method = autofill::WebElementDescriptor::ID;
119      element_descriptor->descriptor = attribute_value;
120      break;
121    } else if (attribute_name.compare("css_selector") == 0 &&
122               !attribute_value.empty()) {
123      element_descriptor->retrieval_method =
124          autofill::WebElementDescriptor::CSS_SELECTOR;
125      element_descriptor->descriptor = attribute_value;
126      break;
127    }
128  }
129}
130
131int AutofillQueryXmlParser::GetIntValue(buzz::XmlParseContext* context,
132                                        const char* attribute) {
133  char* attr_end = NULL;
134  int value = strtol(attribute, &attr_end, 10);
135  if (attr_end != NULL && attr_end == attribute) {
136    context->RaiseError(XML_ERROR_SYNTAX);
137    return 0;
138  }
139  return value;
140}
141
142AutofillUploadXmlParser::AutofillUploadXmlParser(double* positive_upload_rate,
143                                                 double* negative_upload_rate)
144    : succeeded_(false),
145      positive_upload_rate_(positive_upload_rate),
146      negative_upload_rate_(negative_upload_rate) {
147  DCHECK(positive_upload_rate_);
148  DCHECK(negative_upload_rate_);
149}
150
151void AutofillUploadXmlParser::StartElement(buzz::XmlParseContext* context,
152                                           const char* name,
153                                           const char** attrs) {
154  buzz::QName qname = context->ResolveQName(name, false);
155  const std::string &element = qname.LocalPart();
156  if (element.compare("autofilluploadresponse") == 0) {
157    // Loop over all attributes to get the upload rates.
158    while (*attrs) {
159      buzz::QName attribute_qname = context->ResolveQName(attrs[0], true);
160      const std::string &attribute_name = attribute_qname.LocalPart();
161      if (attribute_name.compare("positiveuploadrate") == 0) {
162        *positive_upload_rate_ = GetDoubleValue(context, attrs[1]);
163      } else if (attribute_name.compare("negativeuploadrate") == 0) {
164        *negative_upload_rate_ = GetDoubleValue(context, attrs[1]);
165      }
166      attrs += 2;  // We peeked at attrs[0] and attrs[1], skip past both.
167    }
168  }
169}
170
171double AutofillUploadXmlParser::GetDoubleValue(buzz::XmlParseContext* context,
172                                               const char* attribute) {
173  char* attr_end = NULL;
174  double value = strtod(attribute, &attr_end);
175  if (attr_end != NULL && attr_end == attribute) {
176    context->RaiseError(XML_ERROR_SYNTAX);
177    return 0.0;
178  }
179  return value;
180}
181
182}  // namespace autofill
183