summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorthestig <thestig@chromium.org>2015-04-03 16:59:54 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-04 00:00:24 +0000
commit49946212049e5744449e5222de7d1d114de97e9d (patch)
tree7f2aee3a41415864b03d3db94948bf6a3ff7245e
parent32fde13971e4af00a608bc0286331a5d9b2f1213 (diff)
downloadchromium_src-49946212049e5744449e5222de7d1d114de97e9d.zip
chromium_src-49946212049e5744449e5222de7d1d114de97e9d.tar.gz
chromium_src-49946212049e5744449e5222de7d1d114de97e9d.tar.bz2
Autofill: Recognize more credit card date fields.
BUG=471831 Review URL: https://codereview.chromium.org/1048363002 Cr-Commit-Position: refs/heads/master@{#323853}
-rw-r--r--chrome/test/data/autofill/heuristics/input/bug_471831.html95
-rw-r--r--chrome/test/data/autofill/heuristics/output/bug_471831.out7
-rw-r--r--components/autofill/core/browser/autofill_regex_constants.cc.utf87
-rw-r--r--components/autofill/core/browser/autofill_regex_constants.h1
-rw-r--r--components/autofill/core/browser/credit_card_field.cc52
-rw-r--r--components/autofill/core/browser/credit_card_field_unittest.cc31
6 files changed, 182 insertions, 11 deletions
diff --git a/chrome/test/data/autofill/heuristics/input/bug_471831.html b/chrome/test/data/autofill/heuristics/input/bug_471831.html
new file mode 100644
index 0000000..e9298e1
--- /dev/null
+++ b/chrome/test/data/autofill/heuristics/input/bug_471831.html
@@ -0,0 +1,95 @@
+<div class="layoutView paymentView" style="opacity: 1; height: 291px; transition: none; -webkit-transition: none; transform: translateX(0px); overflow: inherit;">
+ <div class="layoutSubview" style="height: 55px; transform: translateY(0px); opacity: 1; transition: none; -webkit-transition: none;">
+ <div class="emailInput input">
+ <input class="control" id="email" type="email" x-autocompletetype="email" autocompletetype="email" autocorrect="off" spellcheck="off" autocapitalize="off" placeholder="Email"><span class="spinnerContainer" style="display: none;">
+ <div class="svgSpinner" style="width: 14px; height: 15px;">
+ </div></span>
+ <div class="svg icon" style="width: 30px; height: 30px;">
+ </div>
+ </div>
+ </div>
+ <div class="layoutSubview" style="height: 43px; transform: translateY(55px); opacity: 1; transition: none; -webkit-transition: none;">
+ <div class="segmentedControl paymentMethodsSegmentedControl small">
+ <div class="content"><a class="segmentedControl paymentMethodsSegmentedControlItem0 card selected" data-index="0" style="width: 115px;"><span><span>Card</span></span></a><a class="segmentedControl paymentMethodsSegmentedControlItem1 bitcoin" data-index="1" style="width: 114px;"><span><span>Bitcoin</span></span></a>
+ </div>
+ </div>
+ </div>
+ <div class="layoutSubview" style="height: 158px; transform: translateY(98px); opacity: 1; transition: none; -webkit-transition: none;">
+ <div class="contentSwitcher">
+ <div class="inner">
+ <div class="content">
+ <div class="layoutView cardView" style="opacity: 1; transform: translateX(0px); display: block; transition: none; -webkit-transition: none; height: 158px;">
+ <div class="layoutSubview" style="height: 91px; transform: translateY(0px); opacity: 1; transition: none; -webkit-transition: none;">
+ <div class="cardPaymentView">
+ <div class="cardNumberInput input top">
+ <input class="control" id="card_number" type="tel" x-autocompletetype="cc-number" autocompletetype="cc-number" autocorrect="off" spellcheck="off" autocapitalize="off" placeholder="Card number">
+ <div class="svg icon" style="width: 30px; height: 30px;">
+ </div>
+ </div>
+ <div class="cardExpiresInput input left bottom">
+ <input class="control" id="cc-exp" type="text" x-autocompletetype="off" autocompletetype="off" autocorrect="off" spellcheck="off" autocapitalize="off" placeholder="MM / YY">
+ <div class="svg icon" style="width: 30px; height: 30px;">
+ </div>
+ <select id="cc-exp-year" x-autocompletetype="cc-exp-year" autocompletetype="cc-exp-year" autocorrect="off" spellcheck="off" autocapitalize="off" tabindex="-1" style="position: absolute; left: -10000px;"><option>Year</option><option value="2014">2014</option><option value="2015">2015</option><option value="2016">2016</option><option value="2017">2017</option><option value="2018">2018</option><option value="2019">2019</option><option value="2020">2020</option><option value="2021">2021</option><option value="2022">2022</option><option value="2023">2023</option><option value="2024">2024</option></select>
+ <select id="cc-exp-month" x-autocompletetype="cc-exp-month" autocompletetype="cc-exp-month" autocorrect="off" spellcheck="off" autocapitalize="off" tabindex="-1" style="position: absolute; left: -10000px;"><option>Month</option><option value="01">January</option><option value="02">February</option><option value="03">March</option><option value="04">April</option><option value="05">May</option><option value="06">June</option><option value="07">July</option><option value="08">August</option><option value="09">September</option><option value="10">October</option><option value="11">November</option><option value="12">December</option></select>
+ </div>
+ <div class="cardCVCInput input right bottom">
+ <input class="control" id="cc-csc" type="tel" autocomplete="off" autocorrect="off" spellcheck="off" autocapitalize="off" placeholder="CVC" maxlength="4">
+ <div class="svg icon" style="width: 30px; height: 30px;">
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="layoutSubview" style="height: 67px; transform: translateY(91px); opacity: 1; transition: none; -webkit-transition: none;">
+ <div class="rememberMe"><a class="stripeLink"></a>
+ <div class="labelWithCheckbox">
+ <div class="inner"><a class="checkbox checkbox-remember-me" href="#"><span class="tick"></span><span class="focusRing"></span></a><label>Remember me</label>
+ </div>
+ </div>
+ <div class="expandedContainer">
+ <div class="expanded" style="opacity: 0; transform: rotateX(-60deg); display: none;"><p>For security, please enter your <strong>mobile phone number</strong>:</p>
+ <div class="telInput input">
+ <input class="control" type="tel" x-autocompletetype="phone-full" autocompletetype="phone-full" autocorrect="off" spellcheck="off" autocapitalize="off" name="phone" placeholder="(555) 123-1234"><span class="flag"><img src="/v3/images/flags/US.png" style="opacity: 1; transform: scale(1); transition: none; -webkit-transition: none;"></span>
+ <div class="svg icon" style="width: 30px; height: 30px;">
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="layoutSubview" style="display: none; opacity: 0; height: 69px; transform: translateY(158px); transition: none; -webkit-transition: none;">
+ <div class="labelWithCheckbox">
+ <div class="inner"><a class="checkbox checked" href="#"><span class="tick"></span><span class="focusRing"></span></a><label>Keep me logged in</label>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="layoutView bitcoinLayoutView" style="display: none; height: 8px;">
+ <div class="layoutSubview" style="height: 8px; transform: translateY(0px); opacity: 1; transition: none; -webkit-transition: none;">
+ <div class="carouselView">
+ <div class="labelView">To complete your payment, please send bitcoins to the address below:</div>
+ </div>
+ </div>
+ <div class="layoutSubview" style="height: 0px; transform: translateY(8px); opacity: 1; transition: none; -webkit-transition: none;">
+ <div class="bitcoinAddressView">
+ <div class="amount"><span class="arrowContainer"><span class="arrow"></span></span>
+ <div class="svg icon" style="width: 30px; height: 30px;"></div>
+ <span class="btcPrice"></span><span class="originalPrice"></span>
+ <div class="tick bitcoinSuccessTick circle" style="display: none; transform: scale(0.01);">
+ <div class="svg" style="width: 20px; height: 21px; transform: scale(1.8);"></div>
+ </div>
+ <div class="bitcoinLoadingView"><canvas class="loadingView" style="display: none;"></canvas></div>
+ </div>
+ <div class="addressContainer">
+ <div class="address"><p class="stringAddress"><span></span></p>
+ <div class="buttons"><a class="openWalletButton"><span>Open Wallet</span></a><a class="scanButton"><span>Scan</span><span class="qrCode"></span></a></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/chrome/test/data/autofill/heuristics/output/bug_471831.out b/chrome/test/data/autofill/heuristics/output/bug_471831.out
new file mode 100644
index 0000000..2eabd5a
--- /dev/null
+++ b/chrome/test/data/autofill/heuristics/output/bug_471831.out
@@ -0,0 +1,7 @@
+EMAIL_ADDRESS | email | Email | | email_1-default
+CREDIT_CARD_NUMBER | card_number | Card number | | email_1-cc
+CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR | cc-exp | MM / YY | | email_1-cc
+UNKNOWN_TYPE | cc-exp-year | CardBitcoin | Year | email_1-default
+UNKNOWN_TYPE | cc-exp-month | CardBitcoin | Month | email_1-default
+UNKNOWN_TYPE | cc-csc | CVC | | email_1-default
+PHONE_HOME_WHOLE_NUMBER | phone | (555) 123-1234 | | email_1-default
diff --git a/components/autofill/core/browser/autofill_regex_constants.cc.utf8 b/components/autofill/core/browser/autofill_regex_constants.cc.utf8
index ac1d119..a4c4594 100644
--- a/components/autofill/core/browser/autofill_regex_constants.cc.utf8
+++ b/components/autofill/core/browser/autofill_regex_constants.cc.utf8
@@ -182,10 +182,11 @@ const char kExpirationYearRe[] =
"|Срок действия карты" // ru
"|年|有效期"; // zh-CN
-// This regex is a little bit nasty, but it is simply requiring exactly two
-// adjacent y's.
+// The "yy" portion of the regex is just looking for two adjacent y's.
const char kExpirationDate2DigitYearRe[] =
- "exp.*date.*[^y]yy([^y]|$)";
+ "(exp.*date.*|mm\\s*[-/]\\s*)[^y]yy([^y]|$)";
+const char kExpirationDate4DigitYearRe[] =
+ "^mm\\s*[-/]\\syyyy$";
const char kExpirationDateRe[] =
"expir|exp.*date"
"|gueltig|gültig" // de-DE
diff --git a/components/autofill/core/browser/autofill_regex_constants.h b/components/autofill/core/browser/autofill_regex_constants.h
index 8135a9d..7f5ce1a 100644
--- a/components/autofill/core/browser/autofill_regex_constants.h
+++ b/components/autofill/core/browser/autofill_regex_constants.h
@@ -30,6 +30,7 @@ extern const char kCardTypeRe[];
extern const char kExpirationMonthRe[];
extern const char kExpirationYearRe[];
extern const char kExpirationDate2DigitYearRe[];
+extern const char kExpirationDate4DigitYearRe[];
extern const char kExpirationDateRe[];
extern const char kCardIgnoredRe[];
extern const char kGiftCardRe[];
diff --git a/components/autofill/core/browser/credit_card_field.cc b/components/autofill/core/browser/credit_card_field.cc
index 3403b04..7d48bd5 100644
--- a/components/autofill/core/browser/credit_card_field.cc
+++ b/components/autofill/core/browser/credit_card_field.cc
@@ -50,6 +50,28 @@ bool FindConsecutiveStrings(const std::vector<base::string16>& regex_needles,
return false;
}
+// Returns true if a field that has |max_length| can fit the data for a field of
+// |type|.
+bool FieldCanFitDataForFieldType(int max_length, ServerFieldType type) {
+ if (max_length == 0)
+ return true;
+
+ switch (type) {
+ case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: {
+ static int kMinimum2YearCcExpLength = strlen("12/14");
+ return max_length >= kMinimum2YearCcExpLength;
+ }
+ case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: {
+ static int kMinimum4YearCcExpLength = strlen("12/2014");
+ return max_length >= kMinimum4YearCcExpLength;
+ }
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+
} // namespace
// static
@@ -377,17 +399,17 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner) {
}
// If that fails, try to parse a combined expiration field.
- // Look for a 2-digit year first.
// We allow <select> fields, because they're used e.g. on qvc.com.
scanner->RewindTo(month_year_saved_cursor);
- static int kMinimum2YearCcExpLength = strlen("12/14");
- int current_field_max_length = scanner->Cursor()->max_length;
- if (current_field_max_length > 0 &&
- current_field_max_length < kMinimum2YearCcExpLength) {
+ // Bail out if the field cannot fit a 2-digit year expiration date.
+ const int current_field_max_length = scanner->Cursor()->max_length;
+ if (!FieldCanFitDataForFieldType(current_field_max_length,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR)) {
return false;
}
+ // Try to look for a 2-digit year expiration date.
if (ParseFieldSpecifics(scanner,
base::UTF8ToUTF16(kExpirationDate2DigitYearRe),
kMatchTelAndSelect,
@@ -397,19 +419,33 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner) {
return true;
}
+ // Try to look for a generic expiration date field. (2 or 4 digit year)
if (ParseFieldSpecifics(scanner,
base::UTF8ToUTF16(kExpirationDateRe),
kMatchTelAndSelect,
&expiration_date_)) {
- static int kMinimum4YearCcExpLength = strlen("12/2014");
- if (current_field_max_length > 0 &&
- current_field_max_length < kMinimum4YearCcExpLength) {
+ // If such a field exists, but it cannot fit a 4-digit year expiration
+ // date, then the likely possibility is that it is a 2-digit year expiration
+ // date.
+ if (!FieldCanFitDataForFieldType(current_field_max_length,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR)) {
exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR;
}
expiration_month_ = nullptr;
return true;
}
+ // Try to look for a 4-digit year expiration date.
+ if (FieldCanFitDataForFieldType(current_field_max_length,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) &&
+ ParseFieldSpecifics(scanner,
+ base::UTF8ToUTF16(kExpirationDate4DigitYearRe),
+ kMatchTelAndSelect,
+ &expiration_date_)) {
+ expiration_month_ = nullptr;
+ return true;
+ }
+
return false;
}
diff --git a/components/autofill/core/browser/credit_card_field_unittest.cc b/components/autofill/core/browser/credit_card_field_unittest.cc
index ba54b56..1297175 100644
--- a/components/autofill/core/browser/credit_card_field_unittest.cc
+++ b/components/autofill/core/browser/credit_card_field_unittest.cc
@@ -339,6 +339,37 @@ TEST_F(CreditCardFieldTest, ParseExpField2DigitYearDueToMaxLength) {
field_type_map_[ASCIIToUTF16("exp3")]);
}
+TEST_F(CreditCardFieldTest, ParseExpField4DigitYear) {
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("Name on Card");
+ field.name = ASCIIToUTF16("name_on_card");
+ list_.push_back(new AutofillField(field, ASCIIToUTF16("name1")));
+
+ field.label = ASCIIToUTF16("Card Number");
+ field.name = ASCIIToUTF16("card_number");
+ list_.push_back(new AutofillField(field, ASCIIToUTF16("number2")));
+
+ field.label = ASCIIToUTF16("MM / YYYY");
+ field.name = ASCIIToUTF16("cc_exp");
+ list_.push_back(new AutofillField(field, ASCIIToUTF16("exp3")));
+
+ Parse();
+ ASSERT_NE(nullptr, field_.get());
+ EXPECT_TRUE(ClassifyField());
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
+ EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("number2")) != field_type_map_.end());
+ EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number2")]);
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("exp3")) != field_type_map_.end());
+ EXPECT_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
+ field_type_map_[ASCIIToUTF16("exp3")]);
+}
+
TEST_F(CreditCardFieldTest, ParseCreditCardHolderNameWithCCFullName) {
FormFieldData field;
field.form_control_type = "text";