| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "chrome/browser/autofill/credit_card_field.h" | 5 #include "chrome/browser/autofill/credit_card_field.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/string16.h" | 11 #include "base/string16.h" |
| 12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
| 14 #include "chrome/browser/autofill/autofill_ecml.h" | |
| 15 #include "chrome/browser/autofill/autofill_field.h" | 14 #include "chrome/browser/autofill/autofill_field.h" |
| 16 #include "chrome/browser/autofill/autofill_scanner.h" | 15 #include "chrome/browser/autofill/autofill_scanner.h" |
| 17 #include "chrome/browser/autofill/field_types.h" | 16 #include "chrome/browser/autofill/field_types.h" |
| 18 #include "grit/autofill_resources.h" | 17 #include "grit/autofill_resources.h" |
| 19 #include "ui/base/l10n/l10n_util.h" | 18 #include "ui/base/l10n/l10n_util.h" |
| 20 | 19 |
| 21 using autofill::GetEcmlPattern; | |
| 22 | |
| 23 // static | 20 // static |
| 24 FormField* CreditCardField::Parse(AutofillScanner* scanner, | 21 FormField* CreditCardField::Parse(AutofillScanner* scanner) { |
| 25 bool is_ecml) { | |
| 26 if (scanner->IsEnd()) | 22 if (scanner->IsEnd()) |
| 27 return NULL; | 23 return NULL; |
| 28 | 24 |
| 29 scoped_ptr<CreditCardField> credit_card_field(new CreditCardField); | 25 scoped_ptr<CreditCardField> credit_card_field(new CreditCardField); |
| 30 size_t saved_cursor = scanner->SaveCursor(); | 26 size_t saved_cursor = scanner->SaveCursor(); |
| 31 | 27 |
| 32 // Credit card fields can appear in many different orders. | 28 // Credit card fields can appear in many different orders. |
| 33 // We loop until no more credit card related fields are found, see |break| at | 29 // We loop until no more credit card related fields are found, see |break| at |
| 34 // bottom of the loop. | 30 // bottom of the loop. |
| 35 for (int fields = 0; !scanner->IsEnd(); ++fields) { | 31 for (int fields = 0; !scanner->IsEnd(); ++fields) { |
| 36 // Sometimes the cardholder field is just labeled "name". Unfortunately this | 32 // Sometimes the cardholder field is just labeled "name". Unfortunately this |
| 37 // is a dangerously generic word to search for, since it will often match a | 33 // is a dangerously generic word to search for, since it will often match a |
| 38 // name (not cardholder name) field before or after credit card fields. So | 34 // name (not cardholder name) field before or after credit card fields. So |
| 39 // we search for "name" only when we've already parsed at least one other | 35 // we search for "name" only when we've already parsed at least one other |
| 40 // credit card field and haven't yet parsed the expiration date (which | 36 // credit card field and haven't yet parsed the expiration date (which |
| 41 // usually appears at the end). | 37 // usually appears at the end). |
| 42 if (credit_card_field->cardholder_ == NULL) { | 38 if (credit_card_field->cardholder_ == NULL) { |
| 43 string16 name_pattern; | 39 string16 name_pattern; |
| 44 if (is_ecml) { | 40 if (fields == 0 || credit_card_field->expiration_month_) { |
| 45 name_pattern = GetEcmlPattern(kEcmlCardHolder); | 41 // at beginning or end |
| 42 name_pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_NAME_ON_CARD_RE); |
| 46 } else { | 43 } else { |
| 47 if (fields == 0 || credit_card_field->expiration_month_) { | 44 name_pattern = l10n_util::GetStringUTF16( |
| 48 // at beginning or end | 45 IDS_AUTOFILL_NAME_ON_CARD_CONTEXTUAL_RE); |
| 49 name_pattern = l10n_util::GetStringUTF16( | |
| 50 IDS_AUTOFILL_NAME_ON_CARD_RE); | |
| 51 } else { | |
| 52 name_pattern = l10n_util::GetStringUTF16( | |
| 53 IDS_AUTOFILL_NAME_ON_CARD_CONTEXTUAL_RE); | |
| 54 } | |
| 55 } | 46 } |
| 56 | 47 |
| 57 if (ParseField(scanner, name_pattern, &credit_card_field->cardholder_)) | 48 if (ParseField(scanner, name_pattern, &credit_card_field->cardholder_)) |
| 58 continue; | 49 continue; |
| 59 | 50 |
| 60 // As a hard-coded hack for Expedia's billing pages (expedia_checkout.html | 51 // As a hard-coded hack for Expedia's billing pages (expedia_checkout.html |
| 61 // and ExpediaBilling.html in our test suite), recognize separate fields | 52 // and ExpediaBilling.html in our test suite), recognize separate fields |
| 62 // for the cardholder's first and last name if they have the labels "cfnm" | 53 // for the cardholder's first and last name if they have the labels "cfnm" |
| 63 // and "clnm". | 54 // and "clnm". |
| 64 scanner->SaveCursor(); | 55 scanner->SaveCursor(); |
| 65 const AutofillField* first; | 56 const AutofillField* first; |
| 66 if (!is_ecml && ParseField(scanner, ASCIIToUTF16("^cfnm"), &first) && | 57 if (ParseField(scanner, ASCIIToUTF16("^cfnm"), &first) && |
| 67 ParseField(scanner, ASCIIToUTF16("^clnm"), | 58 ParseField(scanner, ASCIIToUTF16("^clnm"), |
| 68 &credit_card_field->cardholder_last_)) { | 59 &credit_card_field->cardholder_last_)) { |
| 69 credit_card_field->cardholder_ = first; | 60 credit_card_field->cardholder_ = first; |
| 70 continue; | 61 continue; |
| 71 } | 62 } |
| 72 scanner->Rewind(); | 63 scanner->Rewind(); |
| 73 } | 64 } |
| 74 | 65 |
| 75 // We look for a card security code before we look for a credit | 66 // We look for a card security code before we look for a credit |
| 76 // card number and match the general term "number". The security code | 67 // card number and match the general term "number". The security code |
| 77 // has a plethora of names; we've seen "verification #", | 68 // has a plethora of names; we've seen "verification #", |
| 78 // "verification number", "card identification number" and others listed | 69 // "verification number", "card identification number" and others listed |
| 79 // in the |pattern| below. | 70 // in the |pattern| below. |
| 80 string16 pattern; | 71 string16 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_CVC_RE); |
| 81 if (is_ecml) | |
| 82 pattern = GetEcmlPattern(kEcmlCardVerification); | |
| 83 else | |
| 84 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_CVC_RE); | |
| 85 | |
| 86 if (!credit_card_field->verification_ && | 72 if (!credit_card_field->verification_ && |
| 87 ParseField(scanner, pattern, &credit_card_field->verification_)) { | 73 ParseField(scanner, pattern, &credit_card_field->verification_)) { |
| 88 continue; | 74 continue; |
| 89 } | 75 } |
| 90 // TODO(jhawkins): Parse the type select control. | 76 // TODO(jhawkins): Parse the type select control. |
| 91 | 77 |
| 92 if (is_ecml) | 78 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_NUMBER_RE); |
| 93 pattern = GetEcmlPattern(kEcmlCardNumber); | |
| 94 else | |
| 95 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_NUMBER_RE); | |
| 96 | |
| 97 if (!credit_card_field->number_ && | 79 if (!credit_card_field->number_ && |
| 98 ParseField(scanner, pattern, &credit_card_field->number_)) { | 80 ParseField(scanner, pattern, &credit_card_field->number_)) { |
| 99 continue; | 81 continue; |
| 100 } | 82 } |
| 101 | 83 |
| 102 if (LowerCaseEqualsASCII(scanner->Cursor()->form_control_type, "month")) { | 84 if (LowerCaseEqualsASCII(scanner->Cursor()->form_control_type, "month")) { |
| 103 credit_card_field->expiration_month_ = scanner->Cursor(); | 85 credit_card_field->expiration_month_ = scanner->Cursor(); |
| 104 scanner->Advance(); | 86 scanner->Advance(); |
| 105 } else { | 87 } else { |
| 106 // "Expiration date" is the most common label here, but some pages have | 88 // "Expiration date" is the most common label here, but some pages have |
| 107 // "Expires", "exp. date" or "exp. month" and "exp. year". We also look | 89 // "Expires", "exp. date" or "exp. month" and "exp. year". We also look |
| 108 // for the field names ccmonth and ccyear, which appear on at least 4 of | 90 // for the field names ccmonth and ccyear, which appear on at least 4 of |
| 109 // our test pages. | 91 // our test pages. |
| 110 // | 92 // |
| 111 // -> On at least one page (The China Shop2.html) we find only the labels | 93 // -> On at least one page (The China Shop2.html) we find only the labels |
| 112 // "month" and "year". So for now we match these words directly; we'll | 94 // "month" and "year". So for now we match these words directly; we'll |
| 113 // see if this turns out to be too general. | 95 // see if this turns out to be too general. |
| 114 // | 96 // |
| 115 // Toolbar Bug 51451: indeed, simply matching "month" is too general for | 97 // Toolbar Bug 51451: indeed, simply matching "month" is too general for |
| 116 // https://rps.fidelity.com/ftgw/rps/RtlCust/CreatePIN/Init. | 98 // https://rps.fidelity.com/ftgw/rps/RtlCust/CreatePIN/Init. |
| 117 // Instead, we match only words beginning with "month". | 99 // Instead, we match only words beginning with "month". |
| 118 if (is_ecml) | 100 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_MONTH_RE); |
| 119 pattern = GetEcmlPattern(kEcmlCardExpireMonth); | |
| 120 else | |
| 121 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_MONTH_RE); | |
| 122 | |
| 123 if ((!credit_card_field->expiration_month_ || | 101 if ((!credit_card_field->expiration_month_ || |
| 124 credit_card_field->expiration_month_->IsEmpty()) && | 102 credit_card_field->expiration_month_->IsEmpty()) && |
| 125 ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT | MATCH_SELECT, | 103 ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT | MATCH_SELECT, |
| 126 &credit_card_field->expiration_month_)) { | 104 &credit_card_field->expiration_month_)) { |
| 127 if (is_ecml) | 105 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_DATE_RE); |
| 128 pattern = GetEcmlPattern(kEcmlCardExpireYear); | |
| 129 else | |
| 130 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_DATE_RE); | |
| 131 | |
| 132 if (!ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT | MATCH_SELECT, | 106 if (!ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT | MATCH_SELECT, |
| 133 &credit_card_field->expiration_year_)) { | 107 &credit_card_field->expiration_year_)) { |
| 134 scanner->RewindTo(saved_cursor); | 108 scanner->RewindTo(saved_cursor); |
| 135 return NULL; | 109 return NULL; |
| 136 } | 110 } |
| 137 continue; | 111 continue; |
| 138 } | 112 } |
| 139 } | 113 } |
| 140 | 114 |
| 141 if (ParseFieldSpecifics(scanner, GetEcmlPattern(kEcmlCardExpireDay), | |
| 142 MATCH_DEFAULT | MATCH_SELECT, NULL)) { | |
| 143 continue; | |
| 144 } | |
| 145 | |
| 146 // Some pages (e.g. ExpediaBilling.html) have a "card description" | 115 // Some pages (e.g. ExpediaBilling.html) have a "card description" |
| 147 // field; we parse this field but ignore it. | 116 // field; we parse this field but ignore it. |
| 148 // We also ignore any other fields within a credit card block that | 117 // We also ignore any other fields within a credit card block that |
| 149 // start with "card", under the assumption that they are related to | 118 // start with "card", under the assumption that they are related to |
| 150 // the credit card section being processed but are uninteresting to us. | 119 // the credit card section being processed but are uninteresting to us. |
| 151 if (ParseField(scanner, | 120 if (ParseField(scanner, |
| 152 l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_IGNORED_RE), | 121 l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_IGNORED_RE), |
| 153 NULL)) { | 122 NULL)) { |
| 154 continue; | 123 continue; |
| 155 } | 124 } |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 if (cardholder_last_ == NULL) | 172 if (cardholder_last_ == NULL) |
| 204 ok = ok && AddClassification(cardholder_, CREDIT_CARD_NAME, map); | 173 ok = ok && AddClassification(cardholder_, CREDIT_CARD_NAME, map); |
| 205 | 174 |
| 206 ok = ok && AddClassification(type_, CREDIT_CARD_TYPE, map); | 175 ok = ok && AddClassification(type_, CREDIT_CARD_TYPE, map); |
| 207 ok = ok && AddClassification(expiration_month_, CREDIT_CARD_EXP_MONTH, map); | 176 ok = ok && AddClassification(expiration_month_, CREDIT_CARD_EXP_MONTH, map); |
| 208 ok = ok && AddClassification(expiration_year_, | 177 ok = ok && AddClassification(expiration_year_, |
| 209 CREDIT_CARD_EXP_4_DIGIT_YEAR, | 178 CREDIT_CARD_EXP_4_DIGIT_YEAR, |
| 210 map); | 179 map); |
| 211 return ok; | 180 return ok; |
| 212 } | 181 } |
| OLD | NEW |