Home | History | Annotate | Download | only in browser
      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 
     16 namespace autofill {
     17 
     18 AutofillXmlParser::AutofillXmlParser()
     19     : succeeded_(true) {
     20 }
     21 
     22 AutofillXmlParser::~AutofillXmlParser() {}
     23 
     24 void AutofillXmlParser::CharacterData(
     25     buzz::XmlParseContext* context, const char* text, int len) {
     26 }
     27 
     28 void AutofillXmlParser::EndElement(buzz::XmlParseContext* context,
     29                                    const char* name) {
     30 }
     31 
     32 void AutofillXmlParser::Error(buzz::XmlParseContext* context,
     33                               XML_Error error_code) {
     34   succeeded_ = false;
     35 }
     36 
     37 AutofillQueryXmlParser::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 
     54 AutofillQueryXmlParser::~AutofillQueryXmlParser() {}
     55 
     56 void 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<ServerFieldType>(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 
    160 void 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 
    188 void AutofillQueryXmlParser::EndElement(buzz::XmlParseContext* context,
    189                                    const char* name) {
    190   is_in_type_section_ = false;
    191 }
    192 
    193 void 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 
    209 int 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 
    220 AutofillUploadXmlParser::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 
    229 void 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 
    249 double 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