autofill_xml_parser.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
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 "base/strings/string_number_conversions.h" 12#include "components/autofill/content/browser/autocheckout_page_meta_data.h" 13#include "components/autofill/core/browser/autofill_server_field_info.h" 14#include "third_party/libjingle/source/talk/xmllite/qname.h" 15 16namespace autofill { 17 18AutofillXmlParser::AutofillXmlParser() 19 : succeeded_(true) { 20} 21 22AutofillXmlParser::~AutofillXmlParser() {} 23 24void AutofillXmlParser::CharacterData( 25 buzz::XmlParseContext* context, const char* text, int len) { 26} 27 28void AutofillXmlParser::EndElement(buzz::XmlParseContext* context, 29 const char* name) { 30} 31 32void AutofillXmlParser::Error(buzz::XmlParseContext* context, 33 XML_Error error_code) { 34 succeeded_ = false; 35} 36 37AutofillQueryXmlParser::AutofillQueryXmlParser( 38 std::vector<AutofillServerFieldInfo>* field_infos, 39 UploadRequired* upload_required, 40 std::string* experiment_id, 41 AutocheckoutPageMetaData* page_meta_data) 42 : field_infos_(field_infos), 43 upload_required_(upload_required), 44 experiment_id_(experiment_id), 45 page_meta_data_(page_meta_data), 46 current_click_element_(NULL), 47 current_page_number_for_page_types_(0), 48 is_in_type_section_(false) { 49 DCHECK(upload_required_); 50 DCHECK(experiment_id_); 51 DCHECK(page_meta_data_); 52} 53 54AutofillQueryXmlParser::~AutofillQueryXmlParser() {} 55 56void AutofillQueryXmlParser::StartElement(buzz::XmlParseContext* context, 57 const char* name, 58 const char** attrs) { 59 buzz::QName qname = context->ResolveQName(name, false); 60 const std::string& element = qname.LocalPart(); 61 if (element.compare("autofillqueryresponse") == 0) { 62 // We check for the upload required attribute below, but if it's not 63 // present, we use the default upload rates. Likewise, by default we assume 64 // an empty experiment id. 65 *upload_required_ = USE_UPLOAD_RATES; 66 *experiment_id_ = std::string(); 67 68 // |attrs| is a NULL-terminated list of (attribute, value) pairs. 69 while (*attrs) { 70 buzz::QName attribute_qname = context->ResolveQName(*attrs, true); 71 ++attrs; 72 const std::string& attribute_name = attribute_qname.LocalPart(); 73 if (attribute_name.compare("uploadrequired") == 0) { 74 if (strcmp(*attrs, "true") == 0) 75 *upload_required_ = UPLOAD_REQUIRED; 76 else if (strcmp(*attrs, "false") == 0) 77 *upload_required_ = UPLOAD_NOT_REQUIRED; 78 } else if (attribute_name.compare("experimentid") == 0) { 79 *experiment_id_ = *attrs; 80 } 81 ++attrs; 82 } 83 } else if (element.compare("field") == 0) { 84 if (!*attrs) { 85 // Missing the "autofilltype" attribute, abort. 86 context->RaiseError(XML_ERROR_ABORTED); 87 return; 88 } 89 90 // Determine the field type from the attribute value. There should be one 91 // attribute (autofilltype) with an integer value. 92 AutofillServerFieldInfo field_info; 93 field_info.field_type = UNKNOWN_TYPE; 94 95 // |attrs| is a NULL-terminated list of (attribute, value) pairs. 96 while (*attrs) { 97 buzz::QName attribute_qname = context->ResolveQName(*attrs, true); 98 ++attrs; 99 const std::string& attribute_name = attribute_qname.LocalPart(); 100 if (attribute_name.compare("autofilltype") == 0) { 101 int value = GetIntValue(context, *attrs); 102 if (value >= 0 && value < MAX_VALID_FIELD_TYPE) 103 field_info.field_type = static_cast<AutofillFieldType>(value); 104 else 105 field_info.field_type = NO_SERVER_DATA; 106 } else if (field_info.field_type == FIELD_WITH_DEFAULT_VALUE && 107 attribute_name.compare("defaultvalue") == 0) { 108 field_info.default_value = *attrs; 109 } 110 ++attrs; 111 } 112 113 // Record this field type, default value pair. 114 field_infos_->push_back(field_info); 115 } else if (element.compare("autofill_flow") == 0) { 116 // |attrs| is a NULL-terminated list of (attribute, value) pairs. 117 while (*attrs) { 118 buzz::QName attribute_qname = context->ResolveQName(*attrs, true); 119 ++attrs; 120 const std::string& attribute_name = attribute_qname.LocalPart(); 121 if (attribute_name.compare("page_no") == 0) 122 page_meta_data_->current_page_number = GetIntValue(context, *attrs); 123 else if (attribute_name.compare("total_pages") == 0) 124 page_meta_data_->total_pages = GetIntValue(context, *attrs); 125 else if (attribute_name.compare("ignore_ajax") == 0) 126 page_meta_data_->ignore_ajax = strcmp(*attrs, "false") != 0; 127 ++attrs; 128 } 129 } else if (element.compare("page_advance_button") == 0) { 130 page_meta_data_->proceed_element_descriptor = WebElementDescriptor(); 131 ParseElementDescriptor(context, 132 attrs, 133 &page_meta_data_->proceed_element_descriptor); 134 } else if (element.compare("click_elements_before_formfill") == 0) { 135 page_meta_data_->click_elements_before_form_fill.push_back( 136 WebElementDescriptor()); 137 current_click_element_ = &page_meta_data_->click_elements_before_form_fill. 138 back(); 139 } else if (element.compare("click_elements_after_formfill") == 0) { 140 page_meta_data_->click_elements_after_form_fill.push_back( 141 WebElementDescriptor()); 142 current_click_element_ = &page_meta_data_->click_elements_after_form_fill. 143 back(); 144 } else if (element.compare("web_element") == 0) { 145 ParseElementDescriptor(context, attrs, current_click_element_); 146 } else if (element.compare("flow_page") == 0) { 147 while (*attrs) { 148 buzz::QName attribute_qname = context->ResolveQName(*attrs, true); 149 ++attrs; 150 const std::string& attribute_name = attribute_qname.LocalPart(); 151 if (attribute_name.compare("page_no") == 0) 152 current_page_number_for_page_types_ = GetIntValue(context, *attrs); 153 ++attrs; 154 } 155 } else if (element.compare("type") == 0) { 156 is_in_type_section_ = true; 157 } 158} 159 160void AutofillQueryXmlParser::ParseElementDescriptor( 161 buzz::XmlParseContext* context, 162 const char* const* attrs, 163 WebElementDescriptor* element_descriptor) { 164 // If both id and css_selector are set, the first one to appear will take 165 // precedence. 166 // |attrs| is a NULL-terminated list of (attribute, value) pairs. 167 while (*attrs) { 168 buzz::QName attribute_qname = context->ResolveQName(*attrs, true); 169 ++attrs; 170 const std::string& attribute_name = attribute_qname.LocalPart(); 171 buzz::QName value_qname = context->ResolveQName(*attrs, true); 172 ++attrs; 173 const std::string& attribute_value = value_qname.LocalPart(); 174 if (attribute_name.compare("id") == 0 && !attribute_value.empty()) { 175 element_descriptor->retrieval_method = autofill::WebElementDescriptor::ID; 176 element_descriptor->descriptor = attribute_value; 177 break; 178 } else if (attribute_name.compare("css_selector") == 0 && 179 !attribute_value.empty()) { 180 element_descriptor->retrieval_method = 181 autofill::WebElementDescriptor::CSS_SELECTOR; 182 element_descriptor->descriptor = attribute_value; 183 break; 184 } 185 } 186} 187 188void AutofillQueryXmlParser::EndElement(buzz::XmlParseContext* context, 189 const char* name) { 190 is_in_type_section_ = false; 191} 192 193void AutofillQueryXmlParser::CharacterData( 194 buzz::XmlParseContext* context, const char* text, int len) { 195 if (!is_in_type_section_) 196 return; 197 198 int type = -1; 199 base::StringToInt(std::string(text, len), &type); 200 if (type >= AUTOCHECKOUT_STEP_MIN_VALUE && 201 type <= AUTOCHECKOUT_STEP_MAX_VALUE) { 202 AutocheckoutStepType step_type = 203 static_cast<AutocheckoutStepType>(type); 204 page_meta_data_->page_types[current_page_number_for_page_types_] 205 .push_back(step_type); 206 } 207} 208 209int AutofillQueryXmlParser::GetIntValue(buzz::XmlParseContext* context, 210 const char* attribute) { 211 char* attr_end = NULL; 212 int value = strtol(attribute, &attr_end, 10); 213 if (attr_end != NULL && attr_end == attribute) { 214 context->RaiseError(XML_ERROR_SYNTAX); 215 return 0; 216 } 217 return value; 218} 219 220AutofillUploadXmlParser::AutofillUploadXmlParser(double* positive_upload_rate, 221 double* negative_upload_rate) 222 : succeeded_(false), 223 positive_upload_rate_(positive_upload_rate), 224 negative_upload_rate_(negative_upload_rate) { 225 DCHECK(positive_upload_rate_); 226 DCHECK(negative_upload_rate_); 227} 228 229void AutofillUploadXmlParser::StartElement(buzz::XmlParseContext* context, 230 const char* name, 231 const char** attrs) { 232 buzz::QName qname = context->ResolveQName(name, false); 233 const std::string &element = qname.LocalPart(); 234 if (element.compare("autofilluploadresponse") == 0) { 235 // Loop over all attributes to get the upload rates. 236 while (*attrs) { 237 buzz::QName attribute_qname = context->ResolveQName(attrs[0], true); 238 const std::string &attribute_name = attribute_qname.LocalPart(); 239 if (attribute_name.compare("positiveuploadrate") == 0) { 240 *positive_upload_rate_ = GetDoubleValue(context, attrs[1]); 241 } else if (attribute_name.compare("negativeuploadrate") == 0) { 242 *negative_upload_rate_ = GetDoubleValue(context, attrs[1]); 243 } 244 attrs += 2; // We peeked at attrs[0] and attrs[1], skip past both. 245 } 246 } 247} 248 249double AutofillUploadXmlParser::GetDoubleValue(buzz::XmlParseContext* context, 250 const char* attribute) { 251 char* attr_end = NULL; 252 double value = strtod(attribute, &attr_end); 253 if (attr_end != NULL && attr_end == attribute) { 254 context->RaiseError(XML_ERROR_SYNTAX); 255 return 0.0; 256 } 257 return value; 258} 259 260} // namespace autofill 261