1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/autofill/core/common/form_data.h"
6 
7 #include <stddef.h>
8 #include <tuple>
9 
10 #include "base/base64.h"
11 #include "base/pickle.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "components/autofill/core/common/form_field_data.h"
15 #include "components/autofill/core/common/logging/log_buffer.h"
16 
17 namespace autofill {
18 
19 namespace {
20 
21 const int kFormDataPickleVersion = 6;
22 
ReadGURL(base::PickleIterator * iter,GURL * url)23 bool ReadGURL(base::PickleIterator* iter, GURL* url) {
24   std::string spec;
25   if (!iter->ReadString(&spec))
26     return false;
27 
28   *url = GURL(spec);
29   return true;
30 }
31 
ReadOrigin(base::PickleIterator * iter,url::Origin * origin)32 bool ReadOrigin(base::PickleIterator* iter, url::Origin* origin) {
33   std::string spec;
34   if (!iter->ReadString(&spec))
35     return false;
36 
37   *origin = url::Origin::Create(GURL(spec));
38   return true;
39 }
40 
SerializeFormFieldDataVector(const std::vector<FormFieldData> & fields,base::Pickle * pickle)41 void SerializeFormFieldDataVector(const std::vector<FormFieldData>& fields,
42                                   base::Pickle* pickle) {
43   pickle->WriteInt(static_cast<int>(fields.size()));
44   for (size_t i = 0; i < fields.size(); ++i) {
45     SerializeFormFieldData(fields[i], pickle);
46   }
47 }
48 
DeserializeFormFieldDataVector(base::PickleIterator * iter,std::vector<FormFieldData> * fields)49 bool DeserializeFormFieldDataVector(base::PickleIterator* iter,
50                                     std::vector<FormFieldData>* fields) {
51   int size;
52   if (!iter->ReadInt(&size))
53     return false;
54 
55   FormFieldData temp;
56   for (int i = 0; i < size; ++i) {
57     if (!DeserializeFormFieldData(iter, &temp))
58       return false;
59 
60     fields->push_back(temp);
61   }
62   return true;
63 }
64 
LogDeserializationError(int version)65 void LogDeserializationError(int version) {
66   DVLOG(1) << "Could not deserialize version " << version
67            << " FormData from pickle.";
68 }
69 
70 }  // namespace
71 
72 FormData::FormData() = default;
73 
74 FormData::FormData(const FormData&) = default;
75 
76 FormData& FormData::operator=(const FormData&) = default;
77 
78 FormData::FormData(FormData&&) = default;
79 
80 FormData& FormData::operator=(FormData&&) = default;
81 
82 FormData::~FormData() = default;
83 
SameFormAs(const FormData & form) const84 bool FormData::SameFormAs(const FormData& form) const {
85   if (name != form.name || id_attribute != form.id_attribute ||
86       name_attribute != form.name_attribute || url != form.url ||
87       action != form.action || is_form_tag != form.is_form_tag ||
88       is_formless_checkout != form.is_formless_checkout ||
89       fields.size() != form.fields.size())
90     return false;
91   for (size_t i = 0; i < fields.size(); ++i) {
92     if (!fields[i].SameFieldAs(form.fields[i]))
93       return false;
94   }
95   return true;
96 }
97 
SimilarFormAs(const FormData & form) const98 bool FormData::SimilarFormAs(const FormData& form) const {
99   if (name != form.name || id_attribute != form.id_attribute ||
100       name_attribute != form.name_attribute || url != form.url ||
101       action != form.action || is_action_empty != form.is_action_empty ||
102       is_form_tag != form.is_form_tag ||
103       is_formless_checkout != form.is_formless_checkout ||
104       fields.size() != form.fields.size()) {
105     return false;
106   }
107   for (size_t i = 0; i < fields.size(); ++i) {
108     if (!fields[i].SimilarFieldAs(form.fields[i]))
109       return false;
110   }
111   return true;
112 }
113 
DynamicallySameFormAs(const FormData & form) const114 bool FormData::DynamicallySameFormAs(const FormData& form) const {
115   if (name != form.name || id_attribute != form.id_attribute ||
116       name_attribute != form.name_attribute ||
117       fields.size() != form.fields.size())
118     return false;
119   for (size_t i = 0; i < fields.size(); ++i) {
120     if (!fields[i].DynamicallySameFieldAs(form.fields[i]))
121       return false;
122   }
123   return true;
124 }
125 
operator ()(const FormData & a,const FormData & b) const126 bool FormData::IdentityComparator::operator()(const FormData& a,
127                                               const FormData& b) const {
128   // |unique_renderer_id| uniquely identifies the form, if and only if it is
129   // set; the other members compared below together uniquely identify the form
130   // as well.
131   auto tie = [](const FormData& f) {
132     return std::tie(f.unique_renderer_id, f.name, f.id_attribute,
133                     f.name_attribute, f.url, f.action, f.is_form_tag,
134                     f.is_formless_checkout);
135   };
136   if (tie(a) < tie(b))
137     return true;
138   if (tie(b) < tie(a))
139     return false;
140   return std::lexicographical_compare(a.fields.begin(), a.fields.end(),
141                                       b.fields.begin(), b.fields.end(),
142                                       FormFieldData::IdentityComparator());
143 }
144 
FormHasNonEmptyPasswordField(const FormData & form)145 bool FormHasNonEmptyPasswordField(const FormData& form) {
146   for (const auto& field : form.fields) {
147     if (field.IsPasswordInputElement()) {
148       if (!field.value.empty() || !field.typed_value.empty())
149         return true;
150     }
151   }
152   return false;
153 }
154 
operator <<(std::ostream & os,const FormData & form)155 std::ostream& operator<<(std::ostream& os, const FormData& form) {
156   os << base::UTF16ToUTF8(form.name) << " " << form.url << " " << form.action
157      << " " << form.main_frame_origin << " " << form.is_form_tag << " "
158      << form.is_formless_checkout << " "
159      << "Fields:";
160   for (size_t i = 0; i < form.fields.size(); ++i) {
161     os << form.fields[i] << ",";
162   }
163   return os;
164 }
165 
SerializeFormData(const FormData & form_data,base::Pickle * pickle)166 void SerializeFormData(const FormData& form_data, base::Pickle* pickle) {
167   pickle->WriteInt(kFormDataPickleVersion);
168   pickle->WriteString16(form_data.name);
169   pickle->WriteString(form_data.url.spec());
170   pickle->WriteString(form_data.action.spec());
171   SerializeFormFieldDataVector(form_data.fields, pickle);
172   pickle->WriteBool(form_data.is_form_tag);
173   pickle->WriteBool(form_data.is_formless_checkout);
174   pickle->WriteString(form_data.main_frame_origin.Serialize());
175 }
176 
DeserializeFormData(base::PickleIterator * iter,FormData * form_data)177 bool DeserializeFormData(base::PickleIterator* iter, FormData* form_data) {
178   int version;
179   FormData temp_form_data;
180   if (!iter->ReadInt(&version)) {
181     DVLOG(1) << "Bad pickle of FormData, no version present";
182     return false;
183   }
184 
185   if (version < 1 || version > kFormDataPickleVersion) {
186     DVLOG(1) << "Unknown FormData pickle version " << version;
187     return false;
188   }
189 
190   if (!iter->ReadString16(&temp_form_data.name)) {
191     LogDeserializationError(version);
192     return false;
193   }
194 
195   if (version == 1) {
196     base::string16 method;
197     if (!iter->ReadString16(&method)) {
198       LogDeserializationError(version);
199       return false;
200     }
201   }
202 
203   bool unused_user_submitted;
204   if (!ReadGURL(iter, &temp_form_data.url) ||
205       !ReadGURL(iter, &temp_form_data.action) ||
206       // user_submitted was removed/no longer serialized in version 4.
207       (version < 4 && !iter->ReadBool(&unused_user_submitted)) ||
208       !DeserializeFormFieldDataVector(iter, &temp_form_data.fields)) {
209     LogDeserializationError(version);
210     return false;
211   }
212 
213   if (version >= 3) {
214     if (!iter->ReadBool(&temp_form_data.is_form_tag)) {
215       LogDeserializationError(version);
216       return false;
217     }
218   } else {
219     form_data->is_form_tag = true;
220   }
221 
222   if (version >= 5) {
223     if (!iter->ReadBool(&temp_form_data.is_formless_checkout)) {
224       LogDeserializationError(version);
225       return false;
226     }
227   }
228 
229   if (version >= 6) {
230     if (!ReadOrigin(iter, &temp_form_data.main_frame_origin)) {
231       LogDeserializationError(version);
232       return false;
233     }
234   }
235 
236   *form_data = temp_form_data;
237   return true;
238 }
239 
operator <<(LogBuffer & buffer,const FormData & form)240 LogBuffer& operator<<(LogBuffer& buffer, const FormData& form) {
241   buffer << Tag{"div"} << Attrib{"class", "form"};
242   buffer << Tag{"table"};
243   buffer << Tr{} << "Form name:" << form.name;
244   buffer << Tr{} << "Unique renderer Id:" << form.unique_renderer_id.value();
245   buffer << Tr{} << "URL:" << form.url;
246   buffer << Tr{} << "Action:" << form.action;
247   buffer << Tr{} << "Is action empty:" << form.is_action_empty;
248   buffer << Tr{} << "Is <form> tag:" << form.is_form_tag;
249   for (size_t i = 0; i < form.fields.size(); ++i) {
250     buffer << Tag{"tr"};
251     buffer << Tag{"td"} << "Field " << i << ": " << CTag{};
252     buffer << Tag{"td"};
253     buffer << Tag{"table"} << form.fields.at(i) << CTag{"table"};
254     buffer << CTag{"td"};
255     buffer << CTag{"tr"};
256   }
257   buffer << CTag{"table"};
258   buffer << CTag{"div"};
259   return buffer;
260 }
261 
FormDataEqualForTesting(const FormData & lhs,const FormData & rhs)262 bool FormDataEqualForTesting(const FormData& lhs, const FormData& rhs) {
263   FormData::IdentityComparator less;
264   return !less(lhs, rhs) && !less(rhs, lhs);
265 }
266 
267 }  // namespace autofill
268