OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/form_structure.h" | 5 #include "chrome/browser/autofill/form_structure.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/sha1.h" | 9 #include "base/sha1.h" |
10 #include "base/string_number_conversions.h" | 10 #include "base/string_number_conversions.h" |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
106 | 106 |
107 bool FormStructure::EncodeUploadRequest(bool auto_fill_used, | 107 bool FormStructure::EncodeUploadRequest(bool auto_fill_used, |
108 std::string* encoded_xml) const { | 108 std::string* encoded_xml) const { |
109 DCHECK(encoded_xml); | 109 DCHECK(encoded_xml); |
110 encoded_xml->clear(); | 110 encoded_xml->clear(); |
111 bool auto_fillable = IsAutoFillable(false); | 111 bool auto_fillable = IsAutoFillable(false); |
112 DCHECK(auto_fillable); // Caller should've checked for search pages. | 112 DCHECK(auto_fillable); // Caller should've checked for search pages. |
113 if (!auto_fillable) | 113 if (!auto_fillable) |
114 return false; | 114 return false; |
115 | 115 |
116 buzz::XmlElement autofil_request_xml(buzz::QName("autofillupload")); | 116 buzz::XmlElement autofill_request_xml(buzz::QName("autofillupload")); |
117 | 117 |
118 // Attributes for the <autofillupload> element. | 118 // Attributes for the <autofillupload> element. |
119 // | 119 // |
120 // TODO(jhawkins): Work with toolbar devs to make a spec for autofill clients. | 120 // TODO(jhawkins): Work with toolbar devs to make a spec for autofill clients. |
121 // For now these values are hacked from the toolbar code. | 121 // For now these values are hacked from the toolbar code. |
122 autofil_request_xml.SetAttr(buzz::QName(kAttributeClientVersion), | 122 autofill_request_xml.SetAttr(buzz::QName(kAttributeClientVersion), |
123 "6.1.1715.1442/en (GGLL)"); | 123 "6.1.1715.1442/en (GGLL)"); |
124 | 124 |
125 autofil_request_xml.SetAttr(buzz::QName(kAttributeFormSignature), | 125 autofill_request_xml.SetAttr(buzz::QName(kAttributeFormSignature), |
126 FormSignature()); | 126 FormSignature()); |
127 | 127 |
128 autofil_request_xml.SetAttr(buzz::QName(kAttributeAutoFillUsed), | 128 autofill_request_xml.SetAttr(buzz::QName(kAttributeAutoFillUsed), |
129 auto_fill_used ? "true" : "false"); | 129 auto_fill_used ? "true" : "false"); |
130 | 130 |
131 // TODO(jhawkins): Hook this up to the personal data manager. | 131 autofill_request_xml.SetAttr(buzz::QName(kAttributeDataPresent), |
132 // personaldata_manager_->GetDataPresent(); | 132 ConvertPresenceBitsToString().c_str()); |
133 autofil_request_xml.SetAttr(buzz::QName(kAttributeDataPresent), ""); | |
134 | 133 |
135 if (!EncodeFormRequest(FormStructure::UPLOAD, &autofil_request_xml)) | 134 if (!EncodeFormRequest(FormStructure::UPLOAD, &autofill_request_xml)) |
136 return false; // Malformed form, skip it. | 135 return false; // Malformed form, skip it. |
137 | 136 |
138 // Obtain the XML structure as a string. | 137 // Obtain the XML structure as a string. |
139 *encoded_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; | 138 *encoded_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; |
140 *encoded_xml += autofil_request_xml.Str().c_str(); | 139 *encoded_xml += autofill_request_xml.Str().c_str(); |
141 | 140 |
142 return true; | 141 return true; |
143 } | 142 } |
144 | 143 |
145 // static | 144 // static |
146 bool FormStructure::EncodeQueryRequest(const ScopedVector<FormStructure>& forms, | 145 bool FormStructure::EncodeQueryRequest(const ScopedVector<FormStructure>& forms, |
147 std::vector<std::string>* encoded_signatures, | 146 std::vector<std::string>* encoded_signatures, |
148 std::string* encoded_xml) { | 147 std::string* encoded_xml) { |
149 DCHECK(encoded_signatures); | 148 DCHECK(encoded_signatures); |
150 DCHECK(encoded_xml); | 149 DCHECK(encoded_xml); |
151 encoded_xml->clear(); | 150 encoded_xml->clear(); |
152 encoded_signatures->clear(); | 151 encoded_signatures->clear(); |
153 encoded_signatures->reserve(forms.size()); | 152 encoded_signatures->reserve(forms.size()); |
154 buzz::XmlElement autofil_request_xml(buzz::QName("autofillquery")); | 153 buzz::XmlElement autofill_request_xml(buzz::QName("autofillquery")); |
155 // Attributes for the <autofillquery> element. | 154 // Attributes for the <autofillquery> element. |
156 // | 155 // |
157 // TODO(jhawkins): Work with toolbar devs to make a spec for autofill clients. | 156 // TODO(jhawkins): Work with toolbar devs to make a spec for autofill clients. |
158 // For now these values are hacked from the toolbar code. | 157 // For now these values are hacked from the toolbar code. |
159 autofil_request_xml.SetAttr(buzz::QName(kAttributeClientVersion), | 158 autofill_request_xml.SetAttr(buzz::QName(kAttributeClientVersion), |
160 "6.1.1715.1442/en (GGLL)"); | 159 "6.1.1715.1442/en (GGLL)"); |
161 // Some badly formatted web sites repeat forms - detect that and encode only | 160 // Some badly formatted web sites repeat forms - detect that and encode only |
162 // one form as returned data would be the same for all the repeated forms. | 161 // one form as returned data would be the same for all the repeated forms. |
163 std::set<std::string> processed_forms; | 162 std::set<std::string> processed_forms; |
164 for (ScopedVector<FormStructure>::const_iterator it = forms.begin(); | 163 for (ScopedVector<FormStructure>::const_iterator it = forms.begin(); |
165 it != forms.end(); | 164 it != forms.end(); |
166 ++it) { | 165 ++it) { |
167 std::string signature((*it)->FormSignature()); | 166 std::string signature((*it)->FormSignature()); |
168 if (processed_forms.find(signature) != processed_forms.end()) | 167 if (processed_forms.find(signature) != processed_forms.end()) |
169 continue; | 168 continue; |
170 processed_forms.insert(signature); | 169 processed_forms.insert(signature); |
171 scoped_ptr<buzz::XmlElement> encompassing_xml_element( | 170 scoped_ptr<buzz::XmlElement> encompassing_xml_element( |
172 new buzz::XmlElement(buzz::QName("form"))); | 171 new buzz::XmlElement(buzz::QName("form"))); |
173 encompassing_xml_element->SetAttr(buzz::QName(kAttributeSignature), | 172 encompassing_xml_element->SetAttr(buzz::QName(kAttributeSignature), |
174 signature); | 173 signature); |
175 | 174 |
176 if (!(*it)->EncodeFormRequest(FormStructure::QUERY, | 175 if (!(*it)->EncodeFormRequest(FormStructure::QUERY, |
177 encompassing_xml_element.get())) | 176 encompassing_xml_element.get())) |
178 continue; // Malformed form, skip it. | 177 continue; // Malformed form, skip it. |
179 | 178 |
180 autofil_request_xml.AddElement(encompassing_xml_element.release()); | 179 autofill_request_xml.AddElement(encompassing_xml_element.release()); |
181 encoded_signatures->push_back(signature); | 180 encoded_signatures->push_back(signature); |
182 } | 181 } |
183 | 182 |
184 if (!encoded_signatures->size()) | 183 if (!encoded_signatures->size()) |
185 return false; | 184 return false; |
186 | 185 |
187 // Obtain the XML structure as a string. | 186 // Obtain the XML structure as a string. |
188 *encoded_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; | 187 *encoded_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; |
189 *encoded_xml += autofil_request_xml.Str().c_str(); | 188 *encoded_xml += autofill_request_xml.Str().c_str(); |
190 | 189 |
191 return true; | 190 return true; |
192 } | 191 } |
193 | 192 |
194 // static | 193 // static |
195 void FormStructure::ParseQueryResponse(const std::string& response_xml, | 194 void FormStructure::ParseQueryResponse(const std::string& response_xml, |
196 const std::vector<FormStructure*>& forms, | 195 const std::vector<FormStructure*>& forms, |
197 UploadRequired* upload_required, | 196 UploadRequired* upload_required, |
198 const AutoFillMetrics& metric_logger) { | 197 const AutoFillMetrics& metric_logger) { |
199 metric_logger.Log(AutoFillMetrics::QUERY_RESPONSE_RECEIVED); | 198 metric_logger.Log(AutoFillMetrics::QUERY_RESPONSE_RECEIVED); |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
406 if (field_count() > kMaxFieldsOnTheForm) { | 405 if (field_count() > kMaxFieldsOnTheForm) { |
407 // This is not a valid form, most certainly. Do not send request for the | 406 // This is not a valid form, most certainly. Do not send request for the |
408 // wrongly formatted forms. | 407 // wrongly formatted forms. |
409 return false; | 408 return false; |
410 } | 409 } |
411 // Add the child nodes for the form fields. | 410 // Add the child nodes for the form fields. |
412 for (size_t index = 0; index < field_count(); ++index) { | 411 for (size_t index = 0; index < field_count(); ++index) { |
413 const AutoFillField* field = fields_[index]; | 412 const AutoFillField* field = fields_[index]; |
414 if (request_type == FormStructure::UPLOAD) { | 413 if (request_type == FormStructure::UPLOAD) { |
415 FieldTypeSet types = field->possible_types(); | 414 FieldTypeSet types = field->possible_types(); |
416 for (FieldTypeSet::const_iterator type = types.begin(); | 415 // If we have more than one type for the field, report UNKNOWN_TYPE to not |
417 type != types.end(); type++) { | 416 // pollute crowd sourcing with inexact data. |
417 if (!AllowedForUpload(types)) { | |
418 types.clear(); | |
419 types.insert(UNKNOWN_TYPE); | |
420 } | |
421 for (FieldTypeSet::iterator field_type = types.begin(); | |
422 field_type != types.end(); ++field_type) { | |
418 buzz::XmlElement *field_element = new buzz::XmlElement( | 423 buzz::XmlElement *field_element = new buzz::XmlElement( |
419 buzz::QName(kXMLElementField)); | 424 buzz::QName(kXMLElementField)); |
420 | 425 |
421 field_element->SetAttr(buzz::QName(kAttributeSignature), | 426 field_element->SetAttr(buzz::QName(kAttributeSignature), |
422 field->FieldSignature()); | 427 field->FieldSignature()); |
423 field_element->SetAttr(buzz::QName(kAttributeAutoFillType), | 428 field_element->SetAttr(buzz::QName(kAttributeAutoFillType), |
424 base::IntToString(*type)); | 429 base::IntToString(*field_type)); |
425 encompassing_xml_element->AddElement(field_element); | 430 encompassing_xml_element->AddElement(field_element); |
426 } | 431 } |
427 } else { | 432 } else { |
428 buzz::XmlElement *field_element = new buzz::XmlElement( | 433 buzz::XmlElement *field_element = new buzz::XmlElement( |
429 buzz::QName(kXMLElementField)); | 434 buzz::QName(kXMLElementField)); |
430 field_element->SetAttr(buzz::QName(kAttributeSignature), | 435 field_element->SetAttr(buzz::QName(kAttributeSignature), |
431 field->FieldSignature()); | 436 field->FieldSignature()); |
432 encompassing_xml_element->AddElement(field_element); | 437 encompassing_xml_element->AddElement(field_element); |
433 } | 438 } |
434 } | 439 } |
435 return true; | 440 return true; |
436 } | 441 } |
442 | |
443 std::string FormStructure::ConvertPresenceBitsToString() const { | |
444 std::vector<uint8> presence_bitfield; | |
445 // Determine all of the field types that were autofilled. Pack bits into | |
446 // |presence_bitfield|. The necessary size for |presence_bitfield| is | |
447 // ceil((MAX_VALID_FIELD_TYPE + 7) / 8) bytes (uint8). | |
448 presence_bitfield.resize((MAX_VALID_FIELD_TYPE + 0x7) / 8); | |
449 for (size_t i = 0; i < presence_bitfield.size(); ++i) | |
450 presence_bitfield[i] = 0; | |
451 | |
452 for (size_t i = 0; i < field_count(); ++i) { | |
453 const AutoFillField* field = fields_[i]; | |
454 FieldTypeSet types = field->possible_types(); | |
455 // If we have more than one type for the field, report UNKNOWN_TYPE to not | |
456 // pollute crowd sourcing with inexact data. | |
457 if (!AllowedForUpload(types)) { | |
458 types.clear(); | |
459 types.insert(UNKNOWN_TYPE); | |
460 } | |
Ilya Sherman
2011/01/22 01:12:35
nit: You already have this above; no need to do it
GeorgeY
2011/01/22 01:40:40
Done.
| |
461 for (FieldTypeSet::iterator field_type = types.begin(); | |
462 field_type != types.end(); ++field_type) { | |
463 DCHECK(presence_bitfield.size() > (static_cast<size_t>(*field_type) / 8)); | |
464 // Set bit in the bitfield: byte |field_type| / 8, bit in byte | |
465 // |field_type| % 8 from the left. | |
466 presence_bitfield[*field_type / 8] |= (0x80 >> (*field_type % 8)); | |
467 } | |
468 } | |
469 | |
470 std::string data_presence; | |
471 data_presence.reserve(presence_bitfield.size() * 2 + 1); | |
472 | |
473 // Skip trailing zeroes. If all mask is 0 - return empty string. | |
474 size_t data_end = presence_bitfield.size(); | |
475 for (; data_end > 0 && !presence_bitfield[data_end - 1]; --data_end) { | |
476 } | |
477 | |
478 // Print all meaningfull bytes into the string. | |
479 for (size_t i = 0; i < data_end; ++i) { | |
480 base::StringAppendF(&data_presence, "%02x", presence_bitfield[i]); | |
481 } | |
482 | |
483 return data_presence; | |
484 } | |
485 | |
486 bool FormStructure::AllowedForUpload(FieldTypeSet const& field_set) { | |
487 // For each pair |field_set| allowed to be both types on the same line (nth | |
488 // and n+1th), so being ADDRESS_HOME_LINE1 and ADDRESS_BILLING_LINE1 is | |
489 // allowed, but ADDRESS_HOME_LINE1, ADDRESS_BILLING_LINE2 is not. | |
490 static AutoFillFieldType allowed_multi_fields[] = { | |
491 PHONE_FAX_CITY_CODE, PHONE_HOME_CITY_CODE, | |
492 PHONE_FAX_COUNTRY_CODE, PHONE_HOME_COUNTRY_CODE, | |
493 ADDRESS_HOME_LINE1, ADDRESS_BILLING_LINE1, | |
494 ADDRESS_HOME_LINE2, ADDRESS_BILLING_LINE2, | |
495 ADDRESS_HOME_APT_NUM, ADDRESS_BILLING_APT_NUM, | |
496 ADDRESS_HOME_CITY, ADDRESS_BILLING_CITY, | |
497 ADDRESS_HOME_STATE, ADDRESS_BILLING_STATE, | |
498 ADDRESS_HOME_ZIP, ADDRESS_BILLING_ZIP, | |
499 ADDRESS_HOME_COUNTRY, ADDRESS_BILLING_COUNTRY, | |
500 }; | |
501 if (field_set.size() == 0 || field_set.size() > 2) { | |
502 return false; | |
503 } else if (field_set.size() == 1) { | |
504 return true; | |
505 } else { | |
506 DCHECK((arraysize(allowed_multi_fields) & 1) == 0); | |
Ilya Sherman
2011/01/22 01:12:35
nit: Please write this as "% 2" rather than "& 1"
GeorgeY
2011/01/22 01:40:40
Done.
| |
507 for (size_t i = 0; i < arraysize(allowed_multi_fields); i += 2) | |
508 if (field_set.find(allowed_multi_fields[i]) != field_set.end() && | |
509 field_set.find(allowed_multi_fields[i + 1]) != field_set.end()) | |
510 return true; | |
511 } | |
512 return false; | |
513 } | |
Ilya Sherman
2011/01/22 01:12:35
nit: This was the extra code complexity that I was
GeorgeY
2011/01/22 01:40:40
removed
| |
514 | |
OLD | NEW |