summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/base.gyp3
-rw-r--r--base/sha1.cc202
-rw-r--r--base/sha1.h24
-rw-r--r--base/sha1_unittest.cc56
-rw-r--r--chrome/DEPS3
-rw-r--r--chrome/browser/autofill/autofill_field.cc37
-rw-r--r--chrome/browser/autofill/autofill_field.h25
-rw-r--r--chrome/browser/autofill/autofill_manager.cc20
-rw-r--r--chrome/browser/autofill/autofill_manager.h6
-rw-r--r--chrome/browser/autofill/field_types.h85
-rw-r--r--chrome/browser/autofill/form_structure.cc154
-rw-r--r--chrome/browser/autofill/form_structure.h63
-rw-r--r--chrome/browser/webdata/web_database_unittest.cc28
-rwxr-xr-xchrome/chrome.gyp6
-rw-r--r--chrome/common/render_messages.h8
-rw-r--r--webkit/glue/form_field.cc2
-rw-r--r--webkit/glue/form_field.h3
-rw-r--r--webkit/glue/form_field_values.cc11
-rw-r--r--webkit/glue/form_field_values.h3
19 files changed, 723 insertions, 16 deletions
diff --git a/base/base.gyp b/base/base.gyp
index b79568d..47d2438 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -267,6 +267,8 @@
'scoped_vector.h',
'setproctitle_linux.c',
'setproctitle_linux.h',
+ 'sha1.cc',
+ 'sha1.h',
'sha2.cc',
'sha2.h',
'shared_memory.h',
@@ -606,6 +608,7 @@
'scoped_ptr_unittest.cc',
'scoped_temp_dir_unittest.cc',
'scoped_variant_win_unittest.cc',
+ 'sha1_unittest.cc',
'sha2_unittest.cc',
'shared_memory_unittest.cc',
'simple_thread_unittest.cc',
diff --git a/base/sha1.cc b/base/sha1.cc
new file mode 100644
index 0000000..620dd56
--- /dev/null
+++ b/base/sha1.cc
@@ -0,0 +1,202 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sha1.h"
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Implementation of SHA-1. Only handles data in byte-sized blocks,
+// which simplifies the code a fair bit.
+
+// This file also contains an HMAC implementation using SHA-1
+
+// Identifier names follow notation in FIPS PUB 180-3, where you'll
+// also find a description of the algorithm:
+// http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf
+
+// Usage example:
+//
+// SecureHashAlgorithm sha;
+// while(there is data to hash)
+// sha.Update(moredata, size of data);
+// sha.Final();
+// memcpy(somewhere, sha.Digest(), 20);
+//
+// to reuse the instance of sha, call sha.Init();
+
+// TODO(jhawkins): Replace this implementation with a per-platform
+// implementation using each platform's crypto library.
+
+class SecureHashAlgorithm {
+ public:
+ SecureHashAlgorithm() { Init(); }
+
+ static const int kDigestSizeBytes;
+
+ void Init();
+ void Update(const void* data, size_t nbytes);
+ void Final();
+
+ // 20 bytes of message digest.
+ const unsigned char* Digest() const {
+ return reinterpret_cast<const unsigned char*>(H);
+ }
+
+ private:
+ void Pad();
+ void Process();
+
+ uint32 A, B, C, D, E;
+
+ uint32 H[5];
+
+ union {
+ uint32 W[80];
+ uint8 M[64];
+ };
+
+ uint32 cursor;
+ uint32 l;
+};
+
+static inline uint32 f(uint32 t, uint32 B, uint32 C, uint32 D) {
+ if (t < 20) {
+ return (B & C) | ((~B) & D);
+ } else if (t < 40) {
+ return B ^ C ^ D;
+ } else if (t < 60) {
+ return (B & C) | (B & D) | (C & D);
+ } else {
+ return B ^ C ^ D;
+ }
+}
+
+static inline uint32 S(uint32 n, uint32 X) {
+ return (X << n) | (X >> (32-n));
+}
+
+static inline uint32 K(uint32 t) {
+ if (t < 20) {
+ return 0x5a827999;
+ } else if (t < 40) {
+ return 0x6ed9eba1;
+ } else if (t < 60) {
+ return 0x8f1bbcdc;
+ } else {
+ return 0xca62c1d6;
+ }
+}
+
+static inline void swapends(uint32& t) {
+ t = ((t & 0xff000000) >> 24) |
+ ((t & 0xff0000) >> 8) |
+ ((t & 0xff00) << 8) |
+ ((t & 0xff) << 24);
+}
+
+const int SecureHashAlgorithm::kDigestSizeBytes = 20;
+
+void SecureHashAlgorithm::Init() {
+ cursor = 0;
+ l = 0;
+ H[0] = 0x67452301;
+ H[1] = 0xefcdab89;
+ H[2] = 0x98badcfe;
+ H[3] = 0x10325476;
+ H[4] = 0xc3d2e1f0;
+}
+
+void SecureHashAlgorithm::Final() {
+ Pad();
+ Process();
+
+ for (int t = 0; t < 5; ++t)
+ swapends(H[t]);
+}
+
+void SecureHashAlgorithm::Update(const void* data, size_t nbytes) {
+ const uint8* d = reinterpret_cast<const uint8*>(data);
+ while (nbytes--) {
+ M[cursor++] = *d++;
+ if (cursor >= 64)
+ Process();
+ l += 8;
+ }
+}
+
+void SecureHashAlgorithm::Pad() {
+ M[cursor++] = 0x80;
+
+ if (cursor > 64-8) {
+ // pad out to next block
+ while (cursor < 64)
+ M[cursor++] = 0;
+
+ Process();
+ }
+
+ while (cursor < 64-4)
+ M[cursor++] = 0;
+
+ M[64-4] = (l & 0xff000000) >> 24;
+ M[64-3] = (l & 0xff0000) >> 16;
+ M[64-2] = (l & 0xff00) >> 8;
+ M[64-1] = (l & 0xff);
+}
+
+void SecureHashAlgorithm::Process() {
+ uint32 t;
+
+ // Each a...e corresponds to a section in the FIPS 180-3 algorithm.
+
+ // a.
+ //
+ // W and M are in a union, so no need to memcpy.
+ // memcpy(W, M, sizeof(M));
+ for (t = 0; t < 16; ++t)
+ swapends(W[t]);
+
+ // b.
+ for (t = 16; t < 80; ++t)
+ W[t] = S(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]);
+
+ // c.
+ A = H[0];
+ B = H[1];
+ C = H[2];
+ D = H[3];
+ E = H[4];
+
+ // d.
+ for (t = 0; t < 80; ++t) {
+ uint32 TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t);
+ E = D;
+ D = C;
+ C = S(30, B);
+ B = A;
+ A = TEMP;
+ }
+
+ // e.
+ H[0] += A;
+ H[1] += B;
+ H[2] += C;
+ H[3] += D;
+ H[4] += E;
+
+ cursor = 0;
+}
+
+std::string SHA1HashString(const std::string& str) {
+ SecureHashAlgorithm sha;
+ sha.Update(str.c_str(), str.length());
+ sha.Final();
+ std::string out(reinterpret_cast<const char*>(sha.Digest()),
+ SecureHashAlgorithm::kDigestSizeBytes);
+ return out;
+}
+
+} // namespace base
diff --git a/base/sha1.h b/base/sha1.h
new file mode 100644
index 0000000..bcc1ced
--- /dev/null
+++ b/base/sha1.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SHA1_H_
+#define BASE_SHA1_H_
+
+#include <string>
+
+namespace base {
+
+// This function performs SHA-1 operations.
+
+enum {
+ SHA1_LENGTH = 20 // Length in bytes of a SHA-1 hash.
+};
+
+// Computes the SHA-1 hash of the input string |str| and returns the full
+// hash.
+std::string SHA1HashString(const std::string& str);
+
+} // namespace base
+
+#endif // BASE_SHA1_H_
diff --git a/base/sha1_unittest.cc b/base/sha1_unittest.cc
new file mode 100644
index 0000000..e445e8f
--- /dev/null
+++ b/base/sha1_unittest.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sha1.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SHA1Test, Test1) {
+ // Example A.1 from FIPS 180-2: one-block message.
+ std::string input = "abc";
+
+ int expected[] = { 0xa9, 0x99, 0x3e, 0x36,
+ 0x47, 0x06, 0x81, 0x6a,
+ 0xba, 0x3e, 0x25, 0x71,
+ 0x78, 0x50, 0xc2, 0x6c,
+ 0x9c, 0xd0, 0xd8, 0x9d };
+
+ std::string output = base::SHA1HashString(input);
+ for (size_t i = 0; i < base::SHA1_LENGTH; i++)
+ EXPECT_EQ(expected[i], output[i] & 0xFF);
+}
+
+TEST(SHA1Test, Test2) {
+ // Example A.2 from FIPS 180-2: multi-block message.
+ std::string input =
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+
+ int expected[] = { 0x84, 0x98, 0x3e, 0x44,
+ 0x1c, 0x3b, 0xd2, 0x6e,
+ 0xba, 0xae, 0x4a, 0xa1,
+ 0xf9, 0x51, 0x29, 0xe5,
+ 0xe5, 0x46, 0x70, 0xf1 };
+
+ std::string output = base::SHA1HashString(input);
+ for (size_t i = 0; i < base::SHA1_LENGTH; i++)
+ EXPECT_EQ(expected[i], output[i] & 0xFF);
+}
+
+TEST(SHA1Test, Test3) {
+ // Example A.3 from FIPS 180-2: long message.
+ std::string input(1000000, 'a');
+
+ int expected[] = { 0x34, 0xaa, 0x97, 0x3c,
+ 0xd4, 0xc4, 0xda, 0xa4,
+ 0xf6, 0x1e, 0xeb, 0x2b,
+ 0xdb, 0xad, 0x27, 0x31,
+ 0x65, 0x34, 0x01, 0x6f };
+
+ std::string output = base::SHA1HashString(input);
+ for (size_t i = 0; i < base::SHA1_LENGTH; i++)
+ EXPECT_EQ(expected[i], output[i] & 0xFF);
+}
diff --git a/chrome/DEPS b/chrome/DEPS
index c1fb4b8..ca6752e 100644
--- a/chrome/DEPS
+++ b/chrome/DEPS
@@ -30,6 +30,9 @@ include_rules = [
# Allow usage of Google Toolbox for Mac.
"+third_party/GTM",
+ # Allow usage of the libjingle library.
+ "+third_party/libjingle",
+
# Our Skia extensions.
"+skia/ext",
diff --git a/chrome/browser/autofill/autofill_field.cc b/chrome/browser/autofill/autofill_field.cc
new file mode 100644
index 0000000..fba28a0
--- /dev/null
+++ b/chrome/browser/autofill/autofill_field.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/autofill/autofill_field.h"
+
+#include "base/logging.h"
+#include "base/sha1.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+
+namespace {
+
+static std::string Hash32Bit(const std::string& str) {
+ std::string hash_bin = base::SHA1HashString(str);
+ DCHECK(hash_bin.length() == 20);
+
+ uint32 hash32 = ((hash_bin[0] & 0xFF) << 24) |
+ ((hash_bin[1] & 0xFF) << 16) |
+ ((hash_bin[2] & 0xFF) << 8) |
+ (hash_bin[3] & 0xFF);
+
+ return UintToString(hash32);
+}
+
+} // namespace
+
+AutoFillField::AutoFillField(const webkit_glue::FormField& field)
+ : webkit_glue::FormField(field) {
+}
+
+std::string AutoFillField::FieldSignature() const {
+ std::string field_name = UTF16ToUTF8(name());
+ std::string type = UTF16ToUTF8(html_input_type());
+ std::string field_string = field_name + "&" + type;
+ return Hash32Bit(field_string);
+}
diff --git a/chrome/browser/autofill/autofill_field.h b/chrome/browser/autofill/autofill_field.h
new file mode 100644
index 0000000..670fd14
--- /dev/null
+++ b/chrome/browser/autofill/autofill_field.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_FIELD_H_
+#define CHROME_BROWSER_AUTOFILL_AUTOFILL_FIELD_H_
+
+#include "chrome/browser/autofill/field_types.h"
+#include "webkit/glue/form_field.h"
+
+class AutoFillField : public webkit_glue::FormField {
+ public:
+ AutoFillField(const webkit_glue::FormField& field);
+
+ const FieldTypeSet& possible_types() const { return possible_types_; }
+
+ // The unique signature of this field, composed of the field name and the html
+ // input type in a 32-bit hash.
+ std::string FieldSignature() const;
+
+ private:
+ FieldTypeSet possible_types_;
+};
+
+#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_FIELD_H_
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc
index 6b78a3d..2a9d3f3 100644
--- a/chrome/browser/autofill/autofill_manager.cc
+++ b/chrome/browser/autofill/autofill_manager.cc
@@ -4,8 +4,11 @@
#include "chrome/browser/autofill/autofill_manager.h"
+#include <string>
+
#include "base/command_line.h"
#include "chrome/browser/autofill/autofill_infobar_delegate.h"
+#include "chrome/browser/autofill/form_structure.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "webkit/glue/form_field_values.h"
@@ -26,16 +29,29 @@ void AutoFillManager::FormFieldValuesSubmitted(
return;
// Grab a copy of the form data.
- form_data_.reset(new webkit_glue::FormFieldValues(form));
+ form_structure_.reset(new FormStructure(form));
+
+ if (!form_structure_->IsAutoFillable())
+ return;
// Ask the user for permission to save form information.
infobar_.reset(new AutoFillInfoBarDelegate(tab_contents_, this));
}
void AutoFillManager::SaveFormData() {
+ UploadFormData();
+
// TODO(jhawkins): Save the form data to the web database.
}
+void AutoFillManager::UploadFormData() {
+ std::string xml;
+ bool ok = form_structure_->EncodeUploadRequest(false, &xml);
+ DCHECK(ok);
+
+ // TODO(jhawkins): Initiate the upload request thread.
+}
+
void AutoFillManager::Reset() {
- form_data_.reset();
+ form_structure_.reset();
}
diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h
index 6e09e6f..521d48b 100644
--- a/chrome/browser/autofill/autofill_manager.h
+++ b/chrome/browser/autofill/autofill_manager.h
@@ -13,6 +13,7 @@ class FormFieldValues;
}
class AutoFillInfoBarDelegate;
+class FormStructure;
class TabContents;
// Manages saving and restoring the user's personal information entered into web
@@ -29,6 +30,9 @@ class AutoFillManager : public RenderViewHostDelegate::AutoFill {
// Saves the form data to the web database.
void SaveFormData();
+ // Uploads the form data to the autofill server.
+ void UploadFormData();
+
// Resets the stored form data.
void Reset();
@@ -37,7 +41,7 @@ class AutoFillManager : public RenderViewHostDelegate::AutoFill {
TabContents* tab_contents_;
// Our copy of the form data.
- scoped_ptr<webkit_glue::FormFieldValues> form_data_;
+ scoped_ptr<FormStructure> form_structure_;
// The infobar asking for permission to store form information.
scoped_ptr<AutoFillInfoBarDelegate> infobar_;
diff --git a/chrome/browser/autofill/field_types.h b/chrome/browser/autofill/field_types.h
new file mode 100644
index 0000000..903af7e
--- /dev/null
+++ b/chrome/browser/autofill/field_types.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_AUTOFILL_FIELD_TYPES_H_
+#define CHROME_BROWSER_AUTOFILL_FIELD_TYPES_H_
+
+#include <set>
+
+// NOTE: This list MUST not be modified. The server aggregates and stores these
+// types over several versions, so we must remain fully compatible with the
+// autofill server, which is itself backward-compatible. The list must be kept
+// up to date with the autofill server list.
+//
+// This is the list of all valid field types.
+typedef enum _FieldType {
+ // Server indication that it has no data for the requested field.
+ NO_SERVER_DATA = 0,
+ // Client indication that the text entered did not match anything in the
+ // personal data.
+ UNKNOWN_TYPE = 1,
+ // The "empty" type indicates that the user hasn't entered anything
+ // in this field.
+ EMPTY_TYPE = 2,
+ // Personal Information categorization types.
+ NAME_FIRST = 3,
+ NAME_MIDDLE = 4,
+ NAME_LAST = 5,
+ NAME_MIDDLE_INITIAL = 6,
+ NAME_FULL = 7,
+ NAME_SUFFIX = 8,
+ EMAIL_ADDRESS = 9,
+ PHONE_HOME_NUMBER = 10,
+ PHONE_HOME_CITY_CODE = 11,
+ PHONE_HOME_COUNTRY_CODE = 12,
+ PHONE_HOME_CITY_AND_NUMBER = 13,
+ PHONE_HOME_WHOLE_NUMBER = 14,
+
+ // Work phone numbers (values [15,19]) are deprecated.
+
+ PHONE_FAX_NUMBER = 20,
+ PHONE_FAX_CITY_CODE = 21,
+ PHONE_FAX_COUNTRY_CODE = 22,
+ PHONE_FAX_CITY_AND_NUMBER = 23,
+ PHONE_FAX_WHOLE_NUMBER = 24,
+
+ // Cell phone numbers (values [25, 29]) are deprecated.
+
+ ADDRESS_HOME_LINE1 = 30,
+ ADDRESS_HOME_LINE2 = 31,
+ ADDRESS_HOME_APPT_NUM = 32,
+ ADDRESS_HOME_CITY = 33,
+ ADDRESS_HOME_STATE = 34,
+ ADDRESS_HOME_ZIP = 35,
+ ADDRESS_HOME_COUNTRY = 36,
+ ADDRESS_BILLING_LINE1 = 37,
+ ADDRESS_BILLING_LINE2 = 38,
+ ADDRESS_BILLING_APPT_NUM = 39,
+ ADDRESS_BILLING_CITY = 40,
+ ADDRESS_BILLING_STATE = 41,
+ ADDRESS_BILLING_ZIP = 42,
+ ADDRESS_BILLING_COUNTRY = 43,
+
+ // ADDRESS_SHIPPING values [44,50] are deprecated.
+
+ CREDIT_CARD_NAME = 51,
+ CREDIT_CARD_NUMBER = 52,
+ CREDIT_CARD_EXP_MONTH = 53,
+ CREDIT_CARD_EXP_2_DIGIT_YEAR = 54,
+ CREDIT_CARD_EXP_4_DIGIT_YEAR = 55,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR = 56,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR = 57,
+ CREDIT_CARD_TYPE = 58,
+ CREDIT_CARD_VERIFICATION_CODE = 59,
+
+ COMPANY_NAME = 60,
+
+ // No new types can be added.
+
+ MAX_VALID_FIELD_TYPE = 61,
+} AutoFillFieldType;
+
+typedef std::set<AutoFillFieldType> FieldTypeSet;
+
+#endif // CHROME_BROWSER_AUTOFILL_FIELD_TYPES_H_
diff --git a/chrome/browser/autofill/form_structure.cc b/chrome/browser/autofill/form_structure.cc
new file mode 100644
index 0000000..354a36c
--- /dev/null
+++ b/chrome/browser/autofill/form_structure.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/autofill/form_structure.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/sha1.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autofill/field_types.h"
+#include "third_party/libjingle/files/talk/xmllite/xmlelement.h"
+#include "webkit/glue/form_field.h"
+#include "webkit/glue/form_field_values.h"
+
+const char* kFormMethodGet = "get";
+const char* kFormMethodPost = "post";
+
+// XML attribute names
+const char* const kAttributeClientVersion = "clientversion";
+const char* const kAttributeAutoFillUsed = "autofillused";
+const char* const kAttributeSignature = "signature";
+const char* const kAttributeFormSignature = "formsignature";
+const char* const kAttributeDataPresent = "datapresent";
+
+const char* const kXMLElementForm = "form";
+const char* const kXMLElementField = "field";
+const char* const kAttributeAutoFillType = "autofilltype";
+
+namespace {
+
+static std::string Hash64Bit(const std::string& str) {
+ std::string hash_bin = base::SHA1HashString(str);
+ DCHECK(hash_bin.length() == 20);
+
+ uint64 hash64 = (((static_cast<uint64>(hash_bin[0])) & 0xFF) << 56) |
+ (((static_cast<uint64>(hash_bin[1])) & 0xFF) << 48) |
+ (((static_cast<uint64>(hash_bin[2])) & 0xFF) << 40) |
+ (((static_cast<uint64>(hash_bin[3])) & 0xFF) << 32) |
+ (((static_cast<uint64>(hash_bin[4])) & 0xFF) << 24) |
+ (((static_cast<uint64>(hash_bin[5])) & 0xFF) << 16) |
+ (((static_cast<uint64>(hash_bin[6])) & 0xFF) << 8) |
+ ((static_cast<uint64>(hash_bin[7])) & 0xFF);
+
+ return Uint64ToString(hash64);
+}
+
+} // namespace
+
+FormStructure::FormStructure(const webkit_glue::FormFieldValues& values)
+ : form_name_(UTF16ToUTF8(values.form_name)),
+ source_url_(values.source_url),
+ target_url_(values.target_url) {
+ // Copy the form fields.
+ std::vector<webkit_glue::FormField>::const_iterator field;
+ for (field = values.elements.begin();
+ field != values.elements.end(); field++) {
+ fields_.push_back(AutoFillField(*field));
+ }
+
+ std::string method = UTF16ToUTF8(values.method);
+ if (method == kFormMethodPost) {
+ method_ = POST;
+ } else {
+ // Either the method is 'get', or we don't know. In this case we default
+ // to GET.
+ method_ = GET;
+ }
+}
+
+bool FormStructure::EncodeUploadRequest(bool auto_fill_used,
+ std::string* encoded_xml) const {
+ bool auto_fillable = IsAutoFillable();
+ DCHECK(auto_fillable); // Caller should've checked for search pages.
+ if (!auto_fillable)
+ return false;
+
+ buzz::XmlElement autofill_upload(buzz::QName("autofillupload"));
+
+ // Attributes for the <autofillupload> element.
+ //
+ // TODO(jhawkins): Work with toolbar devs to make a spec for autofill clients.
+ // For now these values are hacked from the toolbar code.
+ autofill_upload.SetAttr(buzz::QName(kAttributeClientVersion),
+ "6.1.1715.1442/en (GGLL)");
+
+ autofill_upload.SetAttr(buzz::QName(kAttributeFormSignature),
+ FormSignature());
+
+ autofill_upload.SetAttr(buzz::QName(kAttributeAutoFillUsed),
+ auto_fill_used ? "true" : "false");
+
+ // TODO(jhawkins): Hook this up to the personal data manager.
+ // personaldata_manager_->GetDataPresent();
+ autofill_upload.SetAttr(buzz::QName(kAttributeDataPresent), "");
+
+ // Add the child nodes for the form fields.
+ std::vector<AutoFillField>::const_iterator field;
+ for (field = fields_.begin(); field != fields_.end(); field++) {
+ FieldTypeSet types = field->possible_types();
+ for (FieldTypeSet::const_iterator type = types.begin();
+ type != types.end(); type++) {
+ buzz::XmlElement *field_element = new buzz::XmlElement(
+ buzz::QName(kXMLElementField));
+
+ field_element->SetAttr(buzz::QName(kAttributeSignature),
+ field->FieldSignature());
+
+ field_element->SetAttr(buzz::QName(kAttributeAutoFillType),
+ IntToString(*type));
+
+ autofill_upload.AddElement(field_element);
+ }
+ }
+
+ // Obtain the XML structure as a string.
+ *encoded_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+ *encoded_xml += autofill_upload.Str().c_str();
+
+ return true;
+}
+
+std::string FormStructure::FormSignature() const {
+ std::string form_string = target_url_.host() +
+ "&" +
+ form_name_ +
+ form_signature_field_names_;
+
+ return Hash64Bit(form_string);
+}
+
+bool FormStructure::IsAutoFillable() const {
+ if (fields_.size() == 0)
+ return false;
+
+ // Rule out http(s)://*/search?...
+ // e.g. http://www.google.com/search?q=...
+ // http://search.yahoo.com/search?p=...
+ if (target_url_.path() == "/search")
+ return false;
+
+ // Disqualify all forms that are likely to be search boxes (like google.com).
+ if (fields_.size() == 1) {
+ std::string name = UTF16ToUTF8(fields_[0].name());
+ if (name == "q")
+ return false;
+ }
+
+ if (method_ == GET)
+ return false;
+
+ return true;
+}
diff --git a/chrome/browser/autofill/form_structure.h b/chrome/browser/autofill/form_structure.h
new file mode 100644
index 0000000..c0d178d9
--- /dev/null
+++ b/chrome/browser/autofill/form_structure.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_AUTOFILL_FORM_STRUCTURE_H_
+#define CHROME_BROWSER_AUTOFILL_FORM_STRUCTURE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/autofill/autofill_field.h"
+#include "googleurl/src/gurl.h"
+
+namespace webkit_glue {
+class FormFieldValues;
+}
+
+enum RequestMethod {
+ GET,
+ POST
+};
+
+// FormStructure stores a single HTML form together with the values entered
+// in the fields along with additional information needed by AutoFill.
+class FormStructure {
+ public:
+ explicit FormStructure(const webkit_glue::FormFieldValues& values);
+
+ // Encodes the XML upload request from this FormStructure.
+ bool EncodeUploadRequest(bool auto_fill_used, std::string* encoded_xml) const;
+
+ // The unique signature for this form, composed of the target url domain,
+ // the form name, and the form field names in a 64-bit hash.
+ std::string FormSignature() const;
+
+ // Runs a quick heuristic to rule out pages but obviously not auto-fillable,
+ // like google/yahoo/msn search, etc.
+ bool IsAutoFillable() const;
+
+ private:
+ // The name of the form.
+ std::string form_name_;
+
+ // The source URL.
+ GURL source_url_;
+
+ // The target URL.
+ GURL target_url_;
+
+ // A vector of all the input fields in the form.
+ std::vector<AutoFillField> fields_;
+
+ // The names of the form input elements, that are part of the form signature.
+ // The string starts with "&" and the names are also separated by the "&"
+ // character. E.g.: "&form_input1_name&form_input2_name&...&form_inputN_name"
+ std::string form_signature_field_names_;
+
+ // GET or POST.
+ RequestMethod method_;
+};
+
+#endif // CHROME_BROWSER_AUTOFILL_FORM_STRUCTURE_H_
diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc
index 0a6d6c5..14f52e1 100644
--- a/chrome/browser/webdata/web_database_unittest.cc
+++ b/chrome/browser/webdata/web_database_unittest.cc
@@ -392,19 +392,25 @@ TEST_F(WebDatabaseTest, Autofill) {
// Simulate the submission of a handful of entries in a field called "Name",
// some more often than others.
EXPECT_TRUE(db.AddFormFieldValue(
- FormField(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"))));
+ FormField(ASCIIToUTF16("Name"), string16(), ASCIIToUTF16("Superman"))));
std::vector<string16> v;
for (int i = 0; i < 5; i++) {
EXPECT_TRUE(db.AddFormFieldValue(
- FormField(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Kent"))));
+ FormField(ASCIIToUTF16("Name"),
+ string16(),
+ ASCIIToUTF16("Clark Kent"))));
}
for (int i = 0; i < 3; i++) {
EXPECT_TRUE(db.AddFormFieldValue(
- FormField(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Sutter"))));
+ FormField(ASCIIToUTF16("Name"),
+ string16(),
+ ASCIIToUTF16("Clark Sutter"))));
}
for (int i = 0; i < 2; i++) {
EXPECT_TRUE(db.AddFormFieldValue(
- FormField(ASCIIToUTF16("Favorite Color"), ASCIIToUTF16("Green"))));
+ FormField(ASCIIToUTF16("Favorite Color"),
+ string16(),
+ ASCIIToUTF16("Green"))));
}
int count = 0;
@@ -413,7 +419,7 @@ TEST_F(WebDatabaseTest, Autofill) {
// We have added the name Clark Kent 5 times, so count should be 5 and pair_id
// should be somthing non-zero.
EXPECT_TRUE(db.GetIDAndCountOfFormElement(
- FormField(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Kent")),
+ FormField(ASCIIToUTF16("Name"), string16(), ASCIIToUTF16("Clark Kent")),
&pair_id, &count));
EXPECT_EQ(5, count);
EXPECT_NE(0, pair_id);
@@ -421,12 +427,14 @@ TEST_F(WebDatabaseTest, Autofill) {
// Storing in the data base should be case sensitive, so there should be no
// database entry for clark kent lowercase.
EXPECT_TRUE(db.GetIDAndCountOfFormElement(
- FormField(ASCIIToUTF16("Name"), ASCIIToUTF16("clark kent")),
+ FormField(ASCIIToUTF16("Name"), string16(), ASCIIToUTF16("clark kent")),
&pair_id, &count));
EXPECT_EQ(0, count);
EXPECT_TRUE(db.GetIDAndCountOfFormElement(
- FormField(ASCIIToUTF16("Favorite Color"), ASCIIToUTF16("Green")),
+ FormField(ASCIIToUTF16("Favorite Color"),
+ string16(),
+ ASCIIToUTF16("Green")),
&pair_id, &count));
EXPECT_EQ(2, count);
@@ -467,7 +475,7 @@ TEST_F(WebDatabaseTest, Autofill) {
EXPECT_TRUE(db.RemoveFormElementsAddedBetween(t1, Time()));
EXPECT_TRUE(db.GetIDAndCountOfFormElement(
- FormField(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Kent")),
+ FormField(ASCIIToUTF16("Name"), string16(), ASCIIToUTF16("Clark Kent")),
&pair_id, &count));
EXPECT_EQ(0, count);
@@ -478,12 +486,16 @@ TEST_F(WebDatabaseTest, Autofill) {
// Now add some values with empty strings.
const string16 kValue = ASCIIToUTF16(" toto ");
EXPECT_TRUE(db.AddFormFieldValue(FormField(ASCIIToUTF16("blank"),
+ string16(),
string16())));
EXPECT_TRUE(db.AddFormFieldValue(FormField(ASCIIToUTF16("blank"),
+ string16(),
ASCIIToUTF16(" "))));
EXPECT_TRUE(db.AddFormFieldValue(FormField(ASCIIToUTF16("blank"),
+ string16(),
ASCIIToUTF16(" "))));
EXPECT_TRUE(db.AddFormFieldValue(FormField(ASCIIToUTF16("blank"),
+ string16(),
kValue)));
// They should be stored normally as the DB layer does not check for empty
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 02c8668..de12db9 100755
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -786,6 +786,7 @@
'../third_party/bzip2/bzip2.gyp:bzip2',
'../third_party/icu/icu.gyp:icui18n',
'../third_party/icu/icu.gyp:icuuc',
+ '../third_party/libjingle/libjingle.gyp:libjingle',
'../third_party/libxml/libxml.gyp:libxml',
'../third_party/npapi/npapi.gyp:npapi',
'../third_party/hunspell/hunspell.gyp:hunspell',
@@ -842,10 +843,15 @@
'browser/autocomplete/keyword_provider.h',
'browser/autocomplete/search_provider.cc',
'browser/autocomplete/search_provider.h',
+ 'browser/autofill/autofill_field.cc',
+ 'browser/autofill/autofill_field.h',
'browser/autofill/autofill_infobar_delegate.cc',
'browser/autofill/autofill_infobar_delegate.h',
'browser/autofill/autofill_manager.cc',
'browser/autofill/autofill_manager.h',
+ 'browser/autofill/field_types.h',
+ 'browser/autofill/form_structure.cc',
+ 'browser/autofill/form_structure.h',
'browser/automation/automation_autocomplete_edit_tracker.h',
'browser/automation/automation_browser_tracker.h',
'browser/automation/extension_automation_constants.h',
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 2e4bd89..37f7e23 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -819,12 +819,14 @@ struct ParamTraits<webkit_glue::FormFieldValues> {
typedef webkit_glue::FormFieldValues param_type;
static void Write(Message* m, const param_type& p) {
WriteParam(m, p.form_name);
+ WriteParam(m, p.method);
WriteParam(m, p.source_url);
WriteParam(m, p.target_url);
WriteParam(m, p.elements.size());
std::vector<webkit_glue::FormField>::const_iterator itr;
for (itr = p.elements.begin(); itr != p.elements.end(); itr++) {
WriteParam(m, itr->name());
+ WriteParam(m, itr->html_input_type());
WriteParam(m, itr->value());
}
}
@@ -832,16 +834,18 @@ struct ParamTraits<webkit_glue::FormFieldValues> {
bool result = true;
result = result &&
ReadParam(m, iter, &p->form_name) &&
+ ReadParam(m, iter, &p->method) &&
ReadParam(m, iter, &p->source_url) &&
ReadParam(m, iter, &p->target_url);
size_t elements_size = 0;
result = result && ReadParam(m, iter, &elements_size);
p->elements.resize(elements_size);
for (size_t i = 0; i < elements_size; i++) {
- string16 name, value;
+ string16 name, type, value;
result = result && ReadParam(m, iter, &name);
+ result = result && ReadParam(m, iter, &type);
result = result && ReadParam(m, iter, &value);
- p->elements[i] = webkit_glue::FormField(name, value);
+ p->elements[i] = webkit_glue::FormField(name, type, value);
}
return result;
}
diff --git a/webkit/glue/form_field.cc b/webkit/glue/form_field.cc
index 665f498..6d49054 100644
--- a/webkit/glue/form_field.cc
+++ b/webkit/glue/form_field.cc
@@ -10,8 +10,10 @@ FormField::FormField() {
}
FormField::FormField(const string16& name,
+ const string16& html_input_type,
const string16& value)
: name_(name),
+ html_input_type_(html_input_type),
value_(value) {
}
diff --git a/webkit/glue/form_field.h b/webkit/glue/form_field.h
index 224934d..92e8faea 100644
--- a/webkit/glue/form_field.h
+++ b/webkit/glue/form_field.h
@@ -14,15 +14,18 @@ class FormField {
public:
FormField();
FormField(const string16& name,
+ const string16& html_input_type,
const string16& value);
string16 name() const { return name_; }
+ string16 html_input_type() const { return html_input_type_; }
string16 value() const { return value_; }
void set_value(const string16& value) { value_ = value; }
private:
string16 name_;
+ string16 html_input_type_;
string16 value_;
};
diff --git a/webkit/glue/form_field_values.cc b/webkit/glue/form_field_values.cc
index 1f9603f..5e2e32f 100644
--- a/webkit/glue/form_field_values.cc
+++ b/webkit/glue/form_field_values.cc
@@ -42,6 +42,7 @@ FormFieldValues* FormFieldValues::Create(const WebForm& webform) {
FormFieldValues* result = new FormFieldValues();
result->form_name = StringToString16(form->name());
+ result->method = StringToString16(form->method());
result->source_url = KURLToGURL(document->url());
result->target_url = KURLToGURL(document->completeURL(form->action()));
result->ExtractFormFieldValues(webform);
@@ -74,14 +75,18 @@ void FormFieldValues::ExtractFormFieldValues(const WebKit::WebForm& webform) {
// For each TEXT input field, store the name and value
string16 value = StringToString16(input_element->value());
TrimWhitespace(value, TRIM_LEADING, &value);
- if (value.length() == 0)
+ if (value.empty())
continue;
string16 name = StringToString16(WebKit::nameOfInputElement(input_element));
- if (name.length() == 0)
+ if (name.empty())
continue; // If we have no name, there is nothing to store.
- elements.push_back(FormField(name, value));
+ string16 type = StringToString16(input_element->formControlType());
+ if (type.empty())
+ continue;
+
+ elements.push_back(FormField(name, type, value));
}
}
diff --git a/webkit/glue/form_field_values.h b/webkit/glue/form_field_values.h
index c67f1e2..bd45499 100644
--- a/webkit/glue/form_field_values.h
+++ b/webkit/glue/form_field_values.h
@@ -26,6 +26,9 @@ class FormFieldValues {
// The name of the form.
string16 form_name;
+ // GET or POST.
+ string16 method;
+
// The source URL.
GURL source_url;