Commit e2f6955f authored by thestig's avatar thestig Committed by Commit bot

Autofill: Better recognize credit card type fields.

BUG=464002, 466685, 469012

Review URL: https://codereview.chromium.org/1030073003

Cr-Commit-Position: refs/heads/master@{#322325}
parent e823d885
This diff is collapsed.
This diff is collapsed.
...@@ -18,7 +18,7 @@ UNKNOWN_TYPE | identificationValue | CPF/CNPJ | | salutation_1-default ...@@ -18,7 +18,7 @@ UNKNOWN_TYPE | identificationValue | CPF/CNPJ | | salutation_1-default
CREDIT_CARD_EXP_MONTH | accountExpiryMonth | Expiration Date | - | salutation_1-cc CREDIT_CARD_EXP_MONTH | accountExpiryMonth | Expiration Date | - | salutation_1-cc
CREDIT_CARD_EXP_4_DIGIT_YEAR | accountExpiryYear | Expiration Date | - | salutation_1-cc CREDIT_CARD_EXP_4_DIGIT_YEAR | accountExpiryYear | Expiration Date | - | salutation_1-cc
CREDIT_CARD_VERIFICATION_CODE | accountVerification | Verification Number * | | salutation_1-cc CREDIT_CARD_VERIFICATION_CODE | accountVerification | Verification Number * | | salutation_1-cc
CREDIT_CARD_TYPE | accountBrandDropDown | Card Brand | | salutation_1-cc UNKNOWN_TYPE | accountBrandDropDown | Card Brand | | salutation_1-default
CREDIT_CARD_NUMBER | cardNumber | Card Number | | salutation_1-cc CREDIT_CARD_NUMBER | cardNumber | Card Number | | salutation_1-cc
CREDIT_CARD_NAME | ccHolder | Card holder | | salutation_1-cc CREDIT_CARD_NAME | ccHolder | Card holder | | salutation_1-cc
CREDIT_CARD_EXP_MONTH | accountExpiryMonth | Expiration Date | - | salutation_1-cc CREDIT_CARD_EXP_MONTH | accountExpiryMonth | Expiration Date | - | salutation_1-cc
......
CREDIT_CARD_NAME | paymentMethodForm.newCreditCardCustomerName | Name on card* | | paymentMethodForm.newCreditCardCustomerName_1-cc
CREDIT_CARD_NUMBER | paymentMethodForm.cardNumber | Card number* | | paymentMethodForm.newCreditCardCustomerName_1-cc
CREDIT_CARD_VERIFICATION_CODE | paymentMethodForm.cardVerificationNumber | Security code* | | paymentMethodForm.newCreditCardCustomerName_1-cc
CREDIT_CARD_EXP_MONTH | paymentMethodForm.expirationMonth | 04 | | paymentMethodForm.newCreditCardCustomerName_1-cc
CREDIT_CARD_EXP_4_DIGIT_YEAR | paymentMethodForm.expirationYear | 2018 | | paymentMethodForm.newCreditCardCustomerName_1-cc
ADDRESS_HOME_ZIP | paymentMethodForm.zip | Card billing ZIP Code* | | paymentMethodForm.newCreditCardCustomerName_1-default
UNKNOWN_TYPE | paymentMethodForm.custCode | Customer code | | paymentMethodForm.newCreditCardCustomerName_1-default
CREDIT_CARD_TYPE | cardissuer | Card Issuer | | cardissuer_1-cc
CREDIT_CARD_NUMBER | cardnumber | Your cardnumber | | cardissuer_1-cc
CREDIT_CARD_EXP_MONTH | expire_month | Expiration Date | | cardissuer_1-cc
CREDIT_CARD_EXP_4_DIGIT_YEAR | expire_year | | | cardissuer_1-cc
NAME_FIRST | firstname | First Name * | | cardissuer_1-default
NAME_LAST | lastname | Last Name * | | cardissuer_1-default
ADDRESS_HOME_LINE1 | address1 | Address * | | cardissuer_1-default
ADDRESS_HOME_LINE2 | unit | Unit # | | cardissuer_1-default
ADDRESS_HOME_LINE3 | address2 | Address Line 2 | | cardissuer_1-default
ADDRESS_HOME_CITY | city | City * | | cardissuer_1-default
ADDRESS_HOME_STATE | state | State * | | cardissuer_1-default
ADDRESS_HOME_ZIP | zip | State * | | cardissuer_1-default
ADDRESS_HOME_COUNTRY | country | Country * | us | cardissuer_1-default
UNKNOWN_TYPE | phonenumber | Mobile Phone* | | cardissuer_1-default
...@@ -248,26 +248,10 @@ bool FillYearSelectControl(const base::string16& value, ...@@ -248,26 +248,10 @@ bool FillYearSelectControl(const base::string16& value,
// given |field|. // given |field|.
bool FillCreditCardTypeSelectControl(const base::string16& value, bool FillCreditCardTypeSelectControl(const base::string16& value,
FormFieldData* field) { FormFieldData* field) {
// Try stripping off spaces. size_t idx;
base::string16 value_stripped; if (AutofillField::FindValueInSelectControl(*field, value, &idx)) {
base::RemoveChars(base::StringToLowerASCII(value), base::kWhitespaceUTF16, field->value = field->option_values[idx];
&value_stripped); return true;
for (size_t i = 0; i < field->option_values.size(); ++i) {
base::string16 option_value_lowercase;
base::RemoveChars(base::StringToLowerASCII(field->option_values[i]),
base::kWhitespaceUTF16, &option_value_lowercase);
base::string16 option_contents_lowercase;
base::RemoveChars(base::StringToLowerASCII(field->option_contents[i]),
base::kWhitespaceUTF16, &option_contents_lowercase);
// Perform a case-insensitive comparison; but fill the form with the
// original text, not the lowercased version.
if (value_stripped == option_value_lowercase ||
value_stripped == option_contents_lowercase) {
field->value = field->option_values[i];
return true;
}
} }
// For American Express, also try filling as "AmEx". // For American Express, also try filling as "AmEx".
...@@ -541,4 +525,32 @@ base::string16 AutofillField::GetPhoneNumberValue( ...@@ -541,4 +525,32 @@ base::string16 AutofillField::GetPhoneNumberValue(
return number; return number;
} }
// static
bool AutofillField::FindValueInSelectControl(const FormFieldData& field,
const base::string16& value,
size_t* index) {
// TODO(thestig): Improve this. See http://crbug.com/470726)
// Try stripping off spaces.
base::string16 value_stripped;
base::RemoveChars(base::StringToLowerASCII(value), base::kWhitespaceUTF16,
&value_stripped);
for (size_t i = 0; i < field.option_values.size(); ++i) {
base::string16 option_value_lowercase;
base::RemoveChars(base::StringToLowerASCII(field.option_values[i]),
base::kWhitespaceUTF16, &option_value_lowercase);
base::string16 option_contents_lowercase;
base::RemoveChars(base::StringToLowerASCII(field.option_contents[i]),
base::kWhitespaceUTF16, &option_contents_lowercase);
// Perform a case-insensitive comparison.
if (value_stripped == option_value_lowercase ||
value_stripped == option_contents_lowercase) {
if (index)
*index = i;
return true;
}
}
return false;
}
} // namespace autofill } // namespace autofill
...@@ -89,6 +89,13 @@ class AutofillField : public FormFieldData { ...@@ -89,6 +89,13 @@ class AutofillField : public FormFieldData {
const base::string16& number, const base::string16& number,
const FormFieldData& field_data); const FormFieldData& field_data);
// Returns true if the select |field| contains an option that matches |value|.
// If the return value is true and |index| is non-NULL, write the index of the
// matching option into |index|.
static bool FindValueInSelectControl(const FormFieldData& field,
const base::string16& value,
size_t* index);
private: private:
// The unique name of this field, generated by Autofill. // The unique name of this field, generated by Autofill.
base::string16 unique_name_; base::string16 unique_name_;
......
...@@ -149,8 +149,6 @@ const char kCardCvcRe[] = ...@@ -149,8 +149,6 @@ const char kCardCvcRe[] =
"verification|card identification|security code|card code" "verification|card identification|security code|card code"
"|cvn|cvv|cvc|csc|cvd|cid|ccv" "|cvn|cvv|cvc|csc|cvd|cid|ccv"
"|\\bcid\\b"; "|\\bcid\\b";
const char kCardTypeRe[] =
"(card|cc|payment).?type|payment.?method|card.*brand";
// "Expiration date" is the most common label here, but some pages have // "Expiration date" is the most common label here, but some pages have
// "Expires", "exp. date" or "exp. month" and "exp. year". We also look // "Expires", "exp. date" or "exp. month" and "exp. year". We also look
...@@ -197,8 +195,6 @@ const char kExpirationDateRe[] = ...@@ -197,8 +195,6 @@ const char kExpirationDateRe[] =
"|有効期限" // ja-JP "|有効期限" // ja-JP
"|validade" // pt-BR, pt-PT "|validade" // pt-BR, pt-PT
"|Срок действия карты"; // ru "|Срок действия карты"; // ru
const char kCardIgnoredRe[] =
"^card";
const char kGiftCardRe[] = const char kGiftCardRe[] =
"gift.?card"; "gift.?card";
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include "components/autofill/core/browser/autofill_regexes.h" #include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_scanner.h" #include "components/autofill/core/browser/autofill_scanner.h"
#include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/field_types.h"
#include "grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
namespace autofill { namespace autofill {
...@@ -60,7 +62,7 @@ scoped_ptr<FormField> CreditCardField::Parse(AutofillScanner* scanner) { ...@@ -60,7 +62,7 @@ scoped_ptr<FormField> CreditCardField::Parse(AutofillScanner* scanner) {
// Credit card fields can appear in many different orders. // Credit card fields can appear in many different orders.
// We loop until no more credit card related fields are found, see |break| at // We loop until no more credit card related fields are found, see |break| at
// bottom of the loop. // the bottom of the loop.
for (int fields = 0; !scanner->IsEnd(); ++fields) { for (int fields = 0; !scanner->IsEnd(); ++fields) {
// Ignore gift card fields. // Ignore gift card fields.
if (ParseField(scanner, base::UTF8ToUTF16(kGiftCardRe), nullptr)) if (ParseField(scanner, base::UTF8ToUTF16(kGiftCardRe), nullptr))
...@@ -89,11 +91,10 @@ scoped_ptr<FormField> CreditCardField::Parse(AutofillScanner* scanner) { ...@@ -89,11 +91,10 @@ scoped_ptr<FormField> CreditCardField::Parse(AutofillScanner* scanner) {
} }
// Check for a credit card type (Visa, MasterCard, etc.) field. // Check for a credit card type (Visa, MasterCard, etc.) field.
if (!credit_card_field->type_ && // All CC type fields encountered so far have been of type select.
ParseFieldSpecifics(scanner, if (!credit_card_field->type_ && LikelyCardTypeSelectField(scanner)) {
base::UTF8ToUTF16(kCardTypeRe), credit_card_field->type_ = scanner->Cursor();
MATCH_DEFAULT | MATCH_SELECT, scanner->Advance();
&credit_card_field->type_)) {
continue; continue;
} }
...@@ -150,14 +151,6 @@ scoped_ptr<FormField> CreditCardField::Parse(AutofillScanner* scanner) { ...@@ -150,14 +151,6 @@ scoped_ptr<FormField> CreditCardField::Parse(AutofillScanner* scanner) {
return nullptr; return nullptr;
} }
// Some pages (e.g. ExpediaBilling.html) have a "card description"
// field; we parse this field but ignore it.
// We also ignore any other fields within a credit card block that
// start with "card", under the assumption that they are related to
// the credit card section being processed but are uninteresting to us.
if (ParseField(scanner, base::UTF8ToUTF16(kCardIgnoredRe), nullptr))
continue;
break; break;
} }
...@@ -247,6 +240,23 @@ bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner) { ...@@ -247,6 +240,23 @@ bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner) {
FindConsecutiveStrings(years_to_check, field->option_contents)); FindConsecutiveStrings(years_to_check, field->option_contents));
} }
// static
bool CreditCardField::LikelyCardTypeSelectField(AutofillScanner* scanner) {
if (scanner->IsEnd())
return false;
AutofillField* field = scanner->Cursor();
if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT))
return false;
return AutofillField::FindValueInSelectControl(
*field, l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_VISA),
nullptr) ||
AutofillField::FindValueInSelectControl(
*field, l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_MASTERCARD),
nullptr);
}
CreditCardField::CreditCardField() CreditCardField::CreditCardField()
: cardholder_(nullptr), : cardholder_(nullptr),
cardholder_last_(nullptr), cardholder_last_(nullptr),
......
...@@ -40,6 +40,10 @@ class CreditCardField : public FormField { ...@@ -40,6 +40,10 @@ class CreditCardField : public FormField {
// the next few years. // the next few years.
static bool LikelyCardYearSelectField(AutofillScanner* scanner); static bool LikelyCardYearSelectField(AutofillScanner* scanner);
// Returns true if |scanner| points to a <select> field that contains credit
// card type options.
static bool LikelyCardTypeSelectField(AutofillScanner* scanner);
CreditCardField(); CreditCardField();
// Parses the expiration month/year/date fields. Returns true if it finds // Parses the expiration month/year/date fields. Returns true if it finds
......
...@@ -117,10 +117,6 @@ TEST_F(CreditCardFieldTest, ParseFullCreditCard) { ...@@ -117,10 +117,6 @@ TEST_F(CreditCardFieldTest, ParseFullCreditCard) {
FormFieldData field; FormFieldData field;
field.form_control_type = "text"; field.form_control_type = "text";
field.label = ASCIIToUTF16("Card Type");
field.name = ASCIIToUTF16("card_type");
list_.push_back(new AutofillField(field, ASCIIToUTF16("type")));
field.label = ASCIIToUTF16("Name on Card"); field.label = ASCIIToUTF16("Name on Card");
field.name = ASCIIToUTF16("name_on_card"); field.name = ASCIIToUTF16("name_on_card");
list_.push_back(new AutofillField(field, ASCIIToUTF16("name"))); list_.push_back(new AutofillField(field, ASCIIToUTF16("name")));
...@@ -141,6 +137,13 @@ TEST_F(CreditCardFieldTest, ParseFullCreditCard) { ...@@ -141,6 +137,13 @@ TEST_F(CreditCardFieldTest, ParseFullCreditCard) {
field.name = ASCIIToUTF16("verification"); field.name = ASCIIToUTF16("verification");
list_.push_back(new AutofillField(field, ASCIIToUTF16("cvc"))); list_.push_back(new AutofillField(field, ASCIIToUTF16("cvc")));
field.form_control_type = "select-one";
field.label = ASCIIToUTF16("Card Type");
field.name = ASCIIToUTF16("card_type");
field.option_contents.push_back(ASCIIToUTF16("visa"));
field.option_values.push_back(ASCIIToUTF16("visa"));
list_.push_back(new AutofillField(field, ASCIIToUTF16("type")));
Parse(); Parse();
ASSERT_NE(nullptr, field_.get()); ASSERT_NE(nullptr, field_.get());
EXPECT_TRUE(ClassifyField()); EXPECT_TRUE(ClassifyField());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment