OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/autofill/core/browser/form_structure.h" | 5 #include "components/autofill/core/browser/form_structure.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
13 #include "base/sha1.h" | 13 #include "base/sha1.h" |
14 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
15 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
16 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
17 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
18 #include "base/time/time.h" | 18 #include "base/time/time.h" |
19 #include "components/autofill/content/browser/autocheckout_page_meta_data.h" | |
20 #include "components/autofill/core/browser/autofill_metrics.h" | 19 #include "components/autofill/core/browser/autofill_metrics.h" |
21 #include "components/autofill/core/browser/autofill_type.h" | 20 #include "components/autofill/core/browser/autofill_type.h" |
22 #include "components/autofill/core/browser/autofill_xml_parser.h" | 21 #include "components/autofill/core/browser/autofill_xml_parser.h" |
23 #include "components/autofill/core/browser/field_types.h" | 22 #include "components/autofill/core/browser/field_types.h" |
24 #include "components/autofill/core/browser/form_field.h" | 23 #include "components/autofill/core/browser/form_field.h" |
25 #include "components/autofill/core/common/autofill_constants.h" | 24 #include "components/autofill/core/common/autofill_constants.h" |
26 #include "components/autofill/core/common/form_data.h" | 25 #include "components/autofill/core/common/form_data.h" |
27 #include "components/autofill/core/common/form_data_predictions.h" | 26 #include "components/autofill/core/common/form_data_predictions.h" |
28 #include "components/autofill/core/common/form_field_data.h" | 27 #include "components/autofill/core/common/form_field_data.h" |
29 #include "components/autofill/core/common/form_field_data_predictions.h" | 28 #include "components/autofill/core/common/form_field_data_predictions.h" |
(...skipping 11 matching lines...) Expand all Loading... | |
41 const char kAttributeAutofillType[] = "autofilltype"; | 40 const char kAttributeAutofillType[] = "autofilltype"; |
42 const char kAttributeClientVersion[] = "clientversion"; | 41 const char kAttributeClientVersion[] = "clientversion"; |
43 const char kAttributeDataPresent[] = "datapresent"; | 42 const char kAttributeDataPresent[] = "datapresent"; |
44 const char kAttributeFieldID[] = "fieldid"; | 43 const char kAttributeFieldID[] = "fieldid"; |
45 const char kAttributeFieldType[] = "fieldtype"; | 44 const char kAttributeFieldType[] = "fieldtype"; |
46 const char kAttributeFormSignature[] = "formsignature"; | 45 const char kAttributeFormSignature[] = "formsignature"; |
47 const char kAttributeName[] = "name"; | 46 const char kAttributeName[] = "name"; |
48 const char kAttributeSignature[] = "signature"; | 47 const char kAttributeSignature[] = "signature"; |
49 const char kAttributeUrlprefixSignature[] = "urlprefixsignature"; | 48 const char kAttributeUrlprefixSignature[] = "urlprefixsignature"; |
50 const char kAcceptedFeaturesExperiment[] = "e"; // e=experiments | 49 const char kAcceptedFeaturesExperiment[] = "e"; // e=experiments |
51 const char kAcceptedFeaturesAutocheckoutExperiment[] = "a,e"; // a=autocheckout | |
52 const char kClientVersion[] = "6.1.1715.1442/en (GGLL)"; | 50 const char kClientVersion[] = "6.1.1715.1442/en (GGLL)"; |
53 const char kXMLDeclaration[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; | 51 const char kXMLDeclaration[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; |
54 const char kXMLElementAutofillQuery[] = "autofillquery"; | 52 const char kXMLElementAutofillQuery[] = "autofillquery"; |
55 const char kXMLElementAutofillUpload[] = "autofillupload"; | 53 const char kXMLElementAutofillUpload[] = "autofillupload"; |
56 const char kXMLElementFieldAssignments[] = "fieldassignments"; | 54 const char kXMLElementFieldAssignments[] = "fieldassignments"; |
57 const char kXMLElementField[] = "field"; | 55 const char kXMLElementField[] = "field"; |
58 const char kXMLElementFields[] = "fields"; | 56 const char kXMLElementFields[] = "fields"; |
59 const char kXMLElementForm[] = "form"; | 57 const char kXMLElementForm[] = "form"; |
60 const char kBillingMode[] = "billing"; | 58 const char kBillingMode[] = "billing"; |
61 const char kShippingMode[] = "shipping"; | 59 const char kShippingMode[] = "shipping"; |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
317 if (status != U_ZERO_ERROR) { | 315 if (status != U_ZERO_ERROR) { |
318 DVLOG(1) << "Couldn't strip digits in " << UTF16ToUTF8(input); | 316 DVLOG(1) << "Couldn't strip digits in " << UTF16ToUTF8(input); |
319 return UTF16ToUTF8(input); | 317 return UTF16ToUTF8(input); |
320 } | 318 } |
321 | 319 |
322 return return_string; | 320 return return_string; |
323 } | 321 } |
324 | 322 |
325 } // namespace | 323 } // namespace |
326 | 324 |
327 FormStructure::FormStructure(const FormData& form, | 325 FormStructure::FormStructure(const FormData& form) |
328 const std::string& autocheckout_url_prefix) | |
329 : form_name_(form.name), | 326 : form_name_(form.name), |
330 source_url_(form.origin), | 327 source_url_(form.origin), |
331 target_url_(form.action), | 328 target_url_(form.action), |
332 autofill_count_(0), | 329 autofill_count_(0), |
333 active_field_count_(0), | 330 active_field_count_(0), |
334 upload_required_(USE_UPLOAD_RATES), | 331 upload_required_(USE_UPLOAD_RATES), |
335 server_experiment_id_("no server response"), | 332 server_experiment_id_("no server response"), |
336 has_author_specified_types_(false), | 333 has_author_specified_types_(false) { |
337 autocheckout_url_prefix_(autocheckout_url_prefix), | |
338 filled_by_autocheckout_(false) { | |
339 // Copy the form fields. | 334 // Copy the form fields. |
340 std::map<base::string16, size_t> unique_names; | 335 std::map<base::string16, size_t> unique_names; |
341 for (std::vector<FormFieldData>::const_iterator field = | 336 for (std::vector<FormFieldData>::const_iterator field = |
342 form.fields.begin(); | 337 form.fields.begin(); |
343 field != form.fields.end(); field++) { | 338 field != form.fields.end(); field++) { |
344 | 339 |
345 if (!ShouldSkipField(*field)) { | 340 if (!ShouldSkipField(*field)) { |
346 // Add all supported form fields (including with empty names) to the | 341 // Add all supported form fields (including with empty names) to the |
347 // signature. This is a requirement for Autofill servers. | 342 // signature. This is a requirement for Autofill servers. |
348 form_signature_field_names_.append("&"); | 343 form_signature_field_names_.append("&"); |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
488 encoded_xml->clear(); | 483 encoded_xml->clear(); |
489 encoded_signatures->clear(); | 484 encoded_signatures->clear(); |
490 encoded_signatures->reserve(forms.size()); | 485 encoded_signatures->reserve(forms.size()); |
491 | 486 |
492 // Set up the <autofillquery> element and attributes. | 487 // Set up the <autofillquery> element and attributes. |
493 buzz::XmlElement autofill_request_xml( | 488 buzz::XmlElement autofill_request_xml( |
494 (buzz::QName(kXMLElementAutofillQuery))); | 489 (buzz::QName(kXMLElementAutofillQuery))); |
495 autofill_request_xml.SetAttr(buzz::QName(kAttributeClientVersion), | 490 autofill_request_xml.SetAttr(buzz::QName(kAttributeClientVersion), |
496 kClientVersion); | 491 kClientVersion); |
497 | 492 |
498 // autocheckout_url_prefix tells the Autofill server where the forms in the | |
499 // request came from, and the the Autofill server checks internal status and | |
500 // decide to enable Autocheckout or not and may return Autocheckout related | |
501 // data in the response accordingly. | |
502 // There is no page/frame level object associated with FormStructure that | |
503 // we could extract URL prefix from. But, all the forms should come from the | |
504 // same frame, so they should have the same Autocheckout URL prefix. Thus we | |
505 // use URL prefix from the first form with Autocheckout enabled. | |
506 std::string autocheckout_url_prefix; | |
507 | |
508 // Some badly formatted web sites repeat forms - detect that and encode only | 493 // Some badly formatted web sites repeat forms - detect that and encode only |
509 // one form as returned data would be the same for all the repeated forms. | 494 // one form as returned data would be the same for all the repeated forms. |
510 std::set<std::string> processed_forms; | 495 std::set<std::string> processed_forms; |
511 for (ScopedVector<FormStructure>::const_iterator it = forms.begin(); | 496 for (ScopedVector<FormStructure>::const_iterator it = forms.begin(); |
512 it != forms.end(); | 497 it != forms.end(); |
513 ++it) { | 498 ++it) { |
514 std::string signature((*it)->FormSignature()); | 499 std::string signature((*it)->FormSignature()); |
515 if (processed_forms.find(signature) != processed_forms.end()) | 500 if (processed_forms.find(signature) != processed_forms.end()) |
516 continue; | 501 continue; |
517 processed_forms.insert(signature); | 502 processed_forms.insert(signature); |
518 scoped_ptr<buzz::XmlElement> encompassing_xml_element( | 503 scoped_ptr<buzz::XmlElement> encompassing_xml_element( |
519 new buzz::XmlElement(buzz::QName(kXMLElementForm))); | 504 new buzz::XmlElement(buzz::QName(kXMLElementForm))); |
520 encompassing_xml_element->SetAttr(buzz::QName(kAttributeSignature), | 505 encompassing_xml_element->SetAttr(buzz::QName(kAttributeSignature), |
521 signature); | 506 signature); |
522 | 507 |
523 if (!(*it)->EncodeFormRequest(FormStructure::QUERY, | 508 if (!(*it)->EncodeFormRequest(FormStructure::QUERY, |
524 encompassing_xml_element.get())) | 509 encompassing_xml_element.get())) |
525 continue; // Malformed form, skip it. | 510 continue; // Malformed form, skip it. |
526 | 511 |
527 if ((*it)->IsAutocheckoutEnabled()) { | |
528 if (autocheckout_url_prefix.empty()) { | |
529 autocheckout_url_prefix = (*it)->autocheckout_url_prefix_; | |
530 } else { | |
531 // Making sure all the forms in the request has the same url_prefix. | |
532 DCHECK_EQ(autocheckout_url_prefix, (*it)->autocheckout_url_prefix_); | |
533 } | |
534 } | |
535 | |
536 autofill_request_xml.AddElement(encompassing_xml_element.release()); | 512 autofill_request_xml.AddElement(encompassing_xml_element.release()); |
537 encoded_signatures->push_back(signature); | 513 encoded_signatures->push_back(signature); |
538 } | 514 } |
539 | 515 |
540 if (!encoded_signatures->size()) | 516 if (!encoded_signatures->size()) |
541 return false; | 517 return false; |
542 | 518 |
543 if (autocheckout_url_prefix.empty()) { | 519 autofill_request_xml.SetAttr(buzz::QName(kAttributeAcceptedFeatures), |
544 autofill_request_xml.SetAttr(buzz::QName(kAttributeAcceptedFeatures), | 520 kAcceptedFeaturesExperiment); |
545 kAcceptedFeaturesExperiment); | |
546 } else { | |
547 autofill_request_xml.SetAttr(buzz::QName(kAttributeAcceptedFeatures), | |
548 kAcceptedFeaturesAutocheckoutExperiment); | |
549 autofill_request_xml.SetAttr(buzz::QName(kAttributeUrlprefixSignature), | |
550 Hash64Bit(autocheckout_url_prefix)); | |
551 } | |
552 | 521 |
553 // Obtain the XML structure as a string. | 522 // Obtain the XML structure as a string. |
554 *encoded_xml = kXMLDeclaration; | 523 *encoded_xml = kXMLDeclaration; |
555 *encoded_xml += autofill_request_xml.Str().c_str(); | 524 *encoded_xml += autofill_request_xml.Str().c_str(); |
556 | 525 |
557 return true; | 526 return true; |
558 } | 527 } |
559 | 528 |
560 // static | 529 // static |
561 void FormStructure::ParseQueryResponse( | 530 void FormStructure::ParseQueryResponse( |
562 const std::string& response_xml, | 531 const std::string& response_xml, |
563 const std::vector<FormStructure*>& forms, | 532 const std::vector<FormStructure*>& forms, |
564 autofill::AutocheckoutPageMetaData* page_meta_data, | |
565 const AutofillMetrics& metric_logger) { | 533 const AutofillMetrics& metric_logger) { |
566 metric_logger.LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_RECEIVED); | 534 metric_logger.LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_RECEIVED); |
567 | 535 |
568 // Parse the field types from the server response to the query. | 536 // Parse the field types from the server response to the query. |
569 std::vector<AutofillServerFieldInfo> field_infos; | 537 std::vector<AutofillServerFieldInfo> field_infos; |
570 UploadRequired upload_required; | 538 UploadRequired upload_required; |
571 std::string experiment_id; | 539 std::string experiment_id; |
572 AutofillQueryXmlParser parse_handler(&field_infos, | 540 AutofillQueryXmlParser parse_handler(&field_infos, |
573 &upload_required, | 541 &upload_required, |
574 &experiment_id, | 542 &experiment_id); |
575 page_meta_data); | |
576 buzz::XmlParser parser(&parse_handler); | 543 buzz::XmlParser parser(&parse_handler); |
577 parser.Parse(response_xml.c_str(), response_xml.length(), true); | 544 parser.Parse(response_xml.c_str(), response_xml.length(), true); |
578 if (!parse_handler.succeeded()) | 545 if (!parse_handler.succeeded()) |
579 return; | 546 return; |
580 | 547 |
581 metric_logger.LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_PARSED); | 548 metric_logger.LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_PARSED); |
582 metric_logger.LogServerExperimentIdForQuery(experiment_id); | 549 metric_logger.LogServerExperimentIdForQuery(experiment_id); |
583 | 550 |
584 bool heuristics_detected_fillable_field = false; | 551 bool heuristics_detected_fillable_field = false; |
585 bool query_response_overrode_heuristics = false; | 552 bool query_response_overrode_heuristics = false; |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
685 host = source_url_.host(); | 652 host = source_url_.host(); |
686 } | 653 } |
687 | 654 |
688 std::string form_string = scheme + "://" + host + "&" + | 655 std::string form_string = scheme + "://" + host + "&" + |
689 UTF16ToUTF8(form_name_) + | 656 UTF16ToUTF8(form_name_) + |
690 form_signature_field_names_; | 657 form_signature_field_names_; |
691 | 658 |
692 return Hash64Bit(form_string); | 659 return Hash64Bit(form_string); |
693 } | 660 } |
694 | 661 |
695 bool FormStructure::IsAutocheckoutEnabled() const { | |
696 return !autocheckout_url_prefix_.empty(); | |
697 } | |
698 | |
699 bool FormStructure::ShouldSkipField(const FormFieldData& field) const { | 662 bool FormStructure::ShouldSkipField(const FormFieldData& field) const { |
700 return (field.is_checkable || field.form_control_type == "password") && | 663 return (field.is_checkable || field.form_control_type == "password"); |
701 !IsAutocheckoutEnabled(); | |
702 } | 664 } |
703 | 665 |
704 size_t FormStructure::RequiredFillableFields() const { | 666 size_t FormStructure::RequiredFillableFields() const { |
705 return IsAutocheckoutEnabled() ? 0 : kRequiredAutofillFields; | 667 return kRequiredAutofillFields; |
706 } | 668 } |
Ilya Sherman
2013/08/27 18:57:57
nit: Seems reasonable to inline this method at thi
Raman Kakilate
2013/08/27 21:52:59
Done.
| |
707 | 669 |
708 bool FormStructure::IsAutofillable(bool require_method_post) const { | 670 bool FormStructure::IsAutofillable(bool require_method_post) const { |
709 if (autofill_count() < RequiredFillableFields()) | 671 if (autofill_count() < RequiredFillableFields()) |
710 return false; | 672 return false; |
711 | 673 |
712 return ShouldBeParsed(require_method_post); | 674 return ShouldBeParsed(require_method_post); |
713 } | 675 } |
714 | 676 |
715 void FormStructure::UpdateAutofillCount() { | 677 void FormStructure::UpdateAutofillCount() { |
716 autofill_count_ = 0; | 678 autofill_count_ = 0; |
717 for (std::vector<AutofillField*>::const_iterator iter = begin(); | 679 for (std::vector<AutofillField*>::const_iterator iter = begin(); |
718 iter != end(); ++iter) { | 680 iter != end(); ++iter) { |
719 AutofillField* field = *iter; | 681 AutofillField* field = *iter; |
720 if (field && field->IsFieldFillable()) | 682 if (field && field->IsFieldFillable()) |
721 ++autofill_count_; | 683 ++autofill_count_; |
722 } | 684 } |
723 } | 685 } |
724 | 686 |
725 bool FormStructure::ShouldBeParsed(bool require_method_post) const { | 687 bool FormStructure::ShouldBeParsed(bool require_method_post) const { |
726 if (active_field_count() < RequiredFillableFields()) | 688 if (active_field_count() < RequiredFillableFields()) |
727 return false; | 689 return false; |
728 | 690 |
729 // Rule out http(s)://*/search?... | 691 // Rule out http(s)://*/search?... |
730 // e.g. http://www.google.com/search?q=... | 692 // e.g. http://www.google.com/search?q=... |
731 // http://search.yahoo.com/search?p=... | 693 // http://search.yahoo.com/search?p=... |
732 if (target_url_.path() == "/search") | 694 if (target_url_.path() == "/search") |
733 return false; | 695 return false; |
734 | 696 |
735 if (!IsAutocheckoutEnabled()) { | 697 bool has_text_field = false; |
736 // Make sure there is at least one text field when Autocheckout is | 698 for (std::vector<AutofillField*>::const_iterator it = begin(); |
737 // not enabled. | 699 it != end() && !has_text_field; ++it) { |
738 bool has_text_field = false; | 700 has_text_field |= (*it)->form_control_type != "select-one"; |
739 for (std::vector<AutofillField*>::const_iterator it = begin(); | |
740 it != end() && !has_text_field; ++it) { | |
741 has_text_field |= (*it)->form_control_type != "select-one"; | |
742 } | |
743 if (!has_text_field) | |
744 return false; | |
745 } | 701 } |
702 if (!has_text_field) | |
703 return false; | |
746 | 704 |
747 return !require_method_post || (method_ == POST); | 705 return !require_method_post || (method_ == POST); |
748 } | 706 } |
749 | 707 |
750 bool FormStructure::ShouldBeCrowdsourced() const { | 708 bool FormStructure::ShouldBeCrowdsourced() const { |
751 // Allow all forms in Autocheckout flow to be crowdsourced. | 709 return !has_author_specified_types_ && ShouldBeParsed(true); |
752 return (!has_author_specified_types_ && ShouldBeParsed(true)) || | |
753 IsAutocheckoutEnabled(); | |
754 } | 710 } |
755 | 711 |
756 void FormStructure::UpdateFromCache(const FormStructure& cached_form) { | 712 void FormStructure::UpdateFromCache(const FormStructure& cached_form) { |
757 // Map from field signatures to cached fields. | 713 // Map from field signatures to cached fields. |
758 std::map<std::string, const AutofillField*> cached_fields; | 714 std::map<std::string, const AutofillField*> cached_fields; |
759 for (size_t i = 0; i < cached_form.field_count(); ++i) { | 715 for (size_t i = 0; i < cached_form.field_count(); ++i) { |
760 const AutofillField* field = cached_form.field(i); | 716 const AutofillField* field = cached_form.field(i); |
761 cached_fields[field->FieldSignature()] = field; | 717 cached_fields[field->FieldSignature()] = field; |
762 } | 718 } |
763 | 719 |
(...skipping 11 matching lines...) Expand all Loading... | |
775 field->value = base::string16(); | 731 field->value = base::string16(); |
776 } | 732 } |
777 | 733 |
778 field->set_heuristic_type(cached_field->second->heuristic_type()); | 734 field->set_heuristic_type(cached_field->second->heuristic_type()); |
779 field->set_server_type(cached_field->second->server_type()); | 735 field->set_server_type(cached_field->second->server_type()); |
780 } | 736 } |
781 } | 737 } |
782 | 738 |
783 UpdateAutofillCount(); | 739 UpdateAutofillCount(); |
784 | 740 |
785 filled_by_autocheckout_ = cached_form.filled_by_autocheckout(); | |
786 server_experiment_id_ = cached_form.server_experiment_id(); | 741 server_experiment_id_ = cached_form.server_experiment_id(); |
787 | 742 |
788 // The form signature should match between query and upload requests to the | 743 // The form signature should match between query and upload requests to the |
789 // server. On many websites, form elements are dynamically added, removed, or | 744 // server. On many websites, form elements are dynamically added, removed, or |
790 // rearranged via JavaScript between page load and form submission, so we | 745 // rearranged via JavaScript between page load and form submission, so we |
791 // copy over the |form_signature_field_names_| corresponding to the query | 746 // copy over the |form_signature_field_names_| corresponding to the query |
792 // request. | 747 // request. |
793 DCHECK_EQ(cached_form.form_name_, form_name_); | 748 DCHECK_EQ(cached_form.form_name_, form_name_); |
794 DCHECK_EQ(cached_form.source_url_, source_url_); | 749 DCHECK_EQ(cached_form.source_url_, source_url_); |
795 DCHECK_EQ(cached_form.target_url_, target_url_); | 750 DCHECK_EQ(cached_form.target_url_, target_url_); |
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1250 field != fields_.end(); ++field) { | 1205 field != fields_.end(); ++field) { |
1251 FieldTypeGroup field_type_group = (*field)->Type().group(); | 1206 FieldTypeGroup field_type_group = (*field)->Type().group(); |
1252 if (field_type_group == CREDIT_CARD) | 1207 if (field_type_group == CREDIT_CARD) |
1253 (*field)->set_section((*field)->section() + "-cc"); | 1208 (*field)->set_section((*field)->section() + "-cc"); |
1254 else | 1209 else |
1255 (*field)->set_section((*field)->section() + "-default"); | 1210 (*field)->set_section((*field)->section() + "-default"); |
1256 } | 1211 } |
1257 } | 1212 } |
1258 | 1213 |
1259 } // namespace autofill | 1214 } // namespace autofill |
OLD | NEW |