Extracting advance element details from Autofill server XML response.
BUG=
Review URL: https://chromiumcodereview.appspot.com/12051017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@178625 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/autofill/autofill_xml_parser.cc b/chrome/browser/autofill/autofill_xml_parser.cc
index b2e4c04c..ea1a605 100644
--- a/chrome/browser/autofill/autofill_xml_parser.cc
+++ b/chrome/browser/autofill/autofill_xml_parser.cc
@@ -15,6 +15,8 @@
: succeeded_(true) {
}
+AutofillXmlParser::~AutofillXmlParser() {}
+
void AutofillXmlParser::CharacterData(
buzz::XmlParseContext* context, const char* text, int len) {
}
@@ -41,6 +43,8 @@
DCHECK(experiment_id_);
}
+AutofillQueryXmlParser::~AutofillQueryXmlParser() {}
+
void AutofillQueryXmlParser::StartElement(buzz::XmlParseContext* context,
const char* name,
const char** attrs) {
@@ -112,6 +116,32 @@
total_pages_ = GetIntValue(context, *attrs);
++attrs;
}
+ } else if (element.compare("page_advance_button") == 0) {
+ // |attrs| is a NULL-terminated list of (attribute, value) pairs.
+ // If both id and css_selector are set, the first one to appear will take
+ // precedence.
+ while (*attrs) {
+ buzz::QName attribute_qname = context->ResolveQName(*attrs, true);
+ ++attrs;
+ const std::string& attribute_name = attribute_qname.LocalPart();
+ buzz::QName value_qname = context->ResolveQName(*attrs, true);
+ ++attrs;
+ const std::string& attribute_value = value_qname.LocalPart();
+ if (attribute_name.compare("id") == 0 && !attribute_value.empty()) {
+ proceed_element_descriptor_.reset(new autofill::WebElementDescriptor());
+ proceed_element_descriptor_->retrieval_method =
+ autofill::WebElementDescriptor::ID;
+ proceed_element_descriptor_->descriptor = attribute_value;
+ break;
+ } else if (attribute_name.compare("css_selector") == 0 &&
+ !attribute_value.empty()) {
+ proceed_element_descriptor_.reset(new autofill::WebElementDescriptor());
+ proceed_element_descriptor_->retrieval_method =
+ autofill::WebElementDescriptor::CSS_SELECTOR;
+ proceed_element_descriptor_->descriptor = attribute_value;
+ break;
+ }
+ }
}
}
diff --git a/chrome/browser/autofill/autofill_xml_parser.h b/chrome/browser/autofill/autofill_xml_parser.h
index 484478c6..efa8c0e 100644
--- a/chrome/browser/autofill/autofill_xml_parser.h
+++ b/chrome/browser/autofill/autofill_xml_parser.h
@@ -10,9 +10,11 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
#include "chrome/browser/autofill/autofill_server_field_info.h"
#include "chrome/browser/autofill/field_types.h"
#include "chrome/browser/autofill/form_structure.h"
+#include "chrome/common/autofill/web_element_descriptor.h"
#include "third_party/libjingle/source/talk/xmllite/xmlparser.h"
// The base class that contains common functionality between
@@ -20,6 +22,7 @@
class AutofillXmlParser : public buzz::XmlParseHandler {
public:
AutofillXmlParser();
+ virtual ~AutofillXmlParser();
// Returns true if no parsing errors were encountered.
bool succeeded() const { return succeeded_; }
@@ -70,11 +73,18 @@
AutofillQueryXmlParser(std::vector<AutofillServerFieldInfo>* field_infos,
UploadRequired* upload_required,
std::string* experiment_id);
+ virtual ~AutofillQueryXmlParser();
int current_page_number() const { return current_page_number_; }
int total_pages() const { return total_pages_; }
+ // Returns the proceed element for multipage Autofill flows if the current
+ // page is part of such a flow or NULL otherwise.
+ const autofill::WebElementDescriptor* proceed_element_descriptor() const {
+ return proceed_element_descriptor_.get();
+ }
+
private:
// A callback for the beginning of a new <element>, called by Expat.
// |context| is a parsing context used to resolve element/attribute names.
@@ -103,6 +113,9 @@
// Total number of pages in multipage autofill flow.
int total_pages_;
+ // Proceed element for multipage Autofill flow.
+ scoped_ptr<autofill::WebElementDescriptor> proceed_element_descriptor_;
+
// The server experiment to which this query response belongs.
// For the default server implementation, this is empty.
std::string* experiment_id_;
diff --git a/chrome/browser/autofill/autofill_xml_parser_unittest.cc b/chrome/browser/autofill/autofill_xml_parser_unittest.cc
index 616fa9be..19cca97 100644
--- a/chrome/browser/autofill/autofill_xml_parser_unittest.cc
+++ b/chrome/browser/autofill/autofill_xml_parser_unittest.cc
@@ -168,7 +168,9 @@
std::string xml = "<autofillqueryresponse>"
"<field autofilltype=\"55\"/>"
- "<autofill_flow page_no=\"1\" total_pages=\"10\"/>"
+ "<autofill_flow page_no=\"1\" total_pages=\"10\">"
+ "<page_advance_button id=\"foo\"/>"
+ "</autofill_flow>"
"</autofillqueryresponse>";
scoped_ptr<AutofillQueryXmlParser> parse_handler(
@@ -180,6 +182,60 @@
EXPECT_EQ(1U, field_infos.size());
EXPECT_EQ(1, parse_handler->current_page_number());
EXPECT_EQ(10, parse_handler->total_pages());
+ EXPECT_EQ("foo", parse_handler->proceed_element_descriptor()->descriptor);
+ EXPECT_EQ(autofill::WebElementDescriptor::ID,
+ parse_handler->proceed_element_descriptor()->retrieval_method);
+
+ // Clear |field_infos| for the next test;
+ field_infos.clear();
+
+ // Test css_selector as page_advance_button.
+ xml = "<autofillqueryresponse>"
+ "<field autofilltype=\"55\"/>"
+ "<autofill_flow page_no=\"1\" total_pages=\"10\">"
+ "<page_advance_button css_selector=\"[name="foo"]\"/>"
+ "</autofill_flow>"
+ "</autofillqueryresponse>";
+
+ parse_handler.reset(new AutofillQueryXmlParser(&field_infos,
+ &upload_required,
+ &experiment_id));
+ parser.reset(new buzz::XmlParser(parse_handler.get()));
+ parser->Parse(xml.c_str(), xml.length(), true);
+ EXPECT_TRUE(parse_handler->succeeded());
+ EXPECT_EQ(1U, field_infos.size());
+ EXPECT_EQ(1, parse_handler->current_page_number());
+ EXPECT_EQ(10, parse_handler->total_pages());
+ EXPECT_EQ("[name=\"foo\"]",
+ parse_handler->proceed_element_descriptor()->descriptor);
+ EXPECT_EQ(autofill::WebElementDescriptor::CSS_SELECTOR,
+ parse_handler->proceed_element_descriptor()->retrieval_method);
+
+ // Clear |field_infos| for the next test;
+ field_infos.clear();
+
+ // Test first attribute is always the one set.
+ xml = "<autofillqueryresponse>"
+ "<field autofilltype=\"55\"/>"
+ "<autofill_flow page_no=\"1\" total_pages=\"10\">"
+ "<page_advance_button css_selector=\"[name="foo"]\""
+ " id=\"foo\"/>"
+ "</autofill_flow>"
+ "</autofillqueryresponse>";
+
+ parse_handler.reset(new AutofillQueryXmlParser(&field_infos,
+ &upload_required,
+ &experiment_id));
+ parser.reset(new buzz::XmlParser(parse_handler.get()));
+ parser->Parse(xml.c_str(), xml.length(), true);
+ EXPECT_TRUE(parse_handler->succeeded());
+ EXPECT_EQ(1U, field_infos.size());
+ EXPECT_EQ(1, parse_handler->current_page_number());
+ EXPECT_EQ(10, parse_handler->total_pages());
+ EXPECT_EQ("[name=\"foo\"]",
+ parse_handler->proceed_element_descriptor()->descriptor);
+ EXPECT_EQ(autofill::WebElementDescriptor::CSS_SELECTOR,
+ parse_handler->proceed_element_descriptor()->retrieval_method);
}
// Test badly formed XML queries.
diff --git a/chrome/browser/autofill/form_structure.cc b/chrome/browser/autofill/form_structure.cc
index 7c89eb8..28d3535c9 100644
--- a/chrome/browser/autofill/form_structure.cc
+++ b/chrome/browser/autofill/form_structure.cc
@@ -446,6 +446,11 @@
form->server_experiment_id_ = experiment_id;
form->current_page_number_ = parse_handler.current_page_number();
form->total_pages_ = parse_handler.total_pages();
+ if (parse_handler.proceed_element_descriptor()) {
+ form->proceed_element_descriptor_.reset(
+ new autofill::WebElementDescriptor(
+ *parse_handler.proceed_element_descriptor()));
+ }
for (std::vector<AutofillField*>::iterator field = form->fields_.begin();
field != form->fields_.end(); ++field, ++current_info) {
diff --git a/chrome/browser/autofill/form_structure.h b/chrome/browser/autofill/form_structure.h
index 118dc5d..72485af 100644
--- a/chrome/browser/autofill/form_structure.h
+++ b/chrome/browser/autofill/form_structure.h
@@ -9,10 +9,12 @@
#include <vector>
#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "chrome/browser/autofill/autofill_field.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/field_types.h"
+#include "chrome/common/autofill/web_element_descriptor.h"
#include "googleurl/src/gurl.h"
struct FormData;
@@ -132,6 +134,12 @@
// autofillable flow.
bool IsInAutofillableFlow() const;
+ // Returns the proceed element for multipage Autofill flows if the current
+ // page is part of such a flow or NULL otherwise.
+ const autofill::WebElementDescriptor* proceed_element_descriptor() const {
+ return proceed_element_descriptor_.get();
+ }
+
const AutofillField* field(size_t index) const;
AutofillField* field(size_t index);
size_t field_count() const;
@@ -228,6 +236,9 @@
// to any autofill flow, it is set to -1.
int total_pages_;
+ // Proceed element for multipage Autofill flow.
+ scoped_ptr<autofill::WebElementDescriptor> proceed_element_descriptor_;
+
// Whether the form includes any field types explicitly specified by the site
// author, via the |autocompletetype| attribute.
bool has_author_specified_types_;