File: form_data.h

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (397 lines) | stat: -rw-r--r-- 16,634 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_FORM_DATA_H_
#define COMPONENTS_AUTOFILL_CORE_COMMON_FORM_DATA_H_

#include <limits>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "build/build_config.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/unique_ids.h"
#include "url/gurl.h"
#include "url/origin.h"

namespace autofill {

class LogBuffer;
namespace internal {
class FormForest;
}

// Pair of a button title (e.g. "Register") and its type (e.g.
// INPUT_ELEMENT_SUBMIT_TYPE).
using ButtonTitleInfo = std::pair<std::u16string, mojom::ButtonTitleType>;

// List of button titles of a given form.
using ButtonTitleList = std::vector<ButtonTitleInfo>;

using FormVersion = ::base::IdTypeU64<class FormVersionMarker>;

// Element of FormData::child_frames.
struct FrameTokenWithPredecessor {
  FrameTokenWithPredecessor();
  FrameTokenWithPredecessor(const FrameTokenWithPredecessor&);
  FrameTokenWithPredecessor(FrameTokenWithPredecessor&&);
  FrameTokenWithPredecessor& operator=(const FrameTokenWithPredecessor&);
  FrameTokenWithPredecessor& operator=(FrameTokenWithPredecessor&&);
  ~FrameTokenWithPredecessor();

  // An identifier of the child frame.
  FrameToken token;
  // This index represents which field, if any, precedes the frame in DOM order.
  // It shall be the maximum integer |i| such that the |i|th field precedes the
  // frame |token|. If there is no such field, it shall be -1.
  int predecessor = -1;

  friend bool operator==(const FrameTokenWithPredecessor& a,
                         const FrameTokenWithPredecessor& b) = default;
};

// Autofill represents forms and fields as FormData and FormFieldData objects.
//
// On the renderer side, there are roughly one-to-one correspondences
//  - between FormData and blink::WebFormElement, and
//  - between FormFieldData and blink::WebFormControlElement,
// where the Blink classes directly correspond to DOM elements.
//
// On the browser side, there are one-to-one correspondences
//  - between FormData and FormStructure, and
//  - between FormFieldData and AutofillField,
// where AutofillField and FormStructure hold additional information, such as
// Autofill type predictions and sectioning.
//
// A FormData is essentially a collection of FormFieldDatas with additional
// metadata.
//
// FormDatas and FormFieldDatas are used in the renderer-browser communication:
//  - The renderer passes a FormData and/or FormFieldData to the browser when it
//    has found a new form in the DOM, a form was submitted, etc. (see
//    mojom::AutofillDriver).
//  - The browser passes a FormData and/or FormFieldData to the renderer for
//    preview, filling, etc. (see mojom::AutofillAgent). In the preview and
//    filling cases, the browser sets the field values to the values to be
//    previewed or filled.
//
// There are a few exceptions to the aforementioned one-to-one correspondences
// between Autofill's data types and Blink's:
// - Autofill only supports certain types of WebFormControlElements: select,
//   textarea, and input elements whose type [4] is one of the following:
//   checkbox, email, month, number, password, radio, search, tel, text, url
//   (where values not listed in [4] default to "text", and "checkbox" and
//   "radio" inputs are currently not filled). In particular, form-associated
//   custom elements [3] are not supported.
// - Autofill has the concept of an unowned form, which does not correspond to
//   an existing blink::WebFormElement.
// - Autofill may move FormFieldDatas to other FormDatas across shadow/main
//   DOMs and across frames.
//
// In Blink, a field can, but does not have to be associated with a form. A
// field is *associated* with a form iff either:
// - it is a descendant of a <form> element, or
// - it has its "form" attribute set to the ID of a <form> element.
// Note that this association does not transcend DOMs. See [1] for details.
//
// In Autofill, we lift Blink's form association across DOMs. We say a field is
// *owned* by a form iff:
// - the field is associated with that form, or
// - the field is unassociated and the form is its nearest shadow-including
//   ancestor [2].
// So the difference between the two terms is that a field in a shadow DOM may
// be unassociated but owned (by a <form> in an ancestor DOM).
//
// Example:
// <body>
//   <form>
//     <input id=A>
//   </form>
//   <input id=B>
//   <form>
//     #shadow-root
//       <input id=C>
//   </form>
// </body>
// The input A is an associated and owned field.
// The input B is an unassociated and unowned field.
// The input C is an unassociated but an owned field.
//
// The unowned fields of the frame constitute that frame's *unowned form*.
//
// Forms from different frames of the same WebContents may furthermore be
// merged. For details, see AutofillDriverRouter.
//
// clang-format off
// [1] https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#reset-the-form-owner
// [2] https://dom.spec.whatwg.org/#concept-shadow-including-descendant
// [3] https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-face-example
// [4] https://html.spec.whatwg.org/multipage/input.html#attr-input-type
// clang-format on
class FormData {
 public:
  struct FillData;
  // Returns true if many members of forms |a| and |b| are identical.
  //
  // "Many" is intended to be "all", but currently the following members are not
  // being compared:
  //
  // - FormData::button_titles,
  // - FormData::full_url,
  // - FormData::is_action_empty,
  // - FormData::main_frame_origin,
  // - FormData::host_frame,
  // - FormData::version,
  // - FormData::submission_event,
  // - FormData::username_predictions,
  // - FormData::is_gaia_with_skip_save_password_form,
  // - some fields of FormFieldData (see FormFieldData::Equal()).
  static bool DeepEqual(const FormData& a, const FormData& b);

  FormData();
  FormData(const FormData&);
  FormData& operator=(const FormData&);
  FormData(FormData&&);
  FormData& operator=(FormData&&);
  ~FormData();

  // Uniquely identifies the DOM element that this form represents.
  //
  // It does *not* uniquely identify this FormData object (there is no such kind
  // of identifier because FormData is a value type).
  //
  // Must not be leaked to renderer process. See FormGlobalId for details.
  FormGlobalId global_id() const { return {host_frame(), renderer_id()}; }

  // Returns a pointer to the field if found, otherwise returns nullptr.
  // Note that FormFieldData::global_id() is not guaranteed to be unique among
  // FormData::fields.
  const FormFieldData* FindFieldByGlobalId(
      const FieldGlobalId& global_id) const;

  // The id attribute of the form.
  const std::u16string& id_attribute() const { return id_attribute_; }
  void set_id_attribute(std::u16string id_attribute) {
    id_attribute_ = std::move(id_attribute);
  }

  // The name attribute of the form.
  const std::u16string& name_attribute() const { return name_attribute_; }
  void set_name_attribute(std::u16string name_attribute) {
    name_attribute_ = std::move(name_attribute);
  }

  // NOTE: Update `FormDataAndroid::SimilarFormAs()` if needed when adding new a
  // member.

  // The name by which autofill knows this form. This is generally either the
  // name attribute or the id_attribute value, which-ever is non-empty with
  // priority given to the name_attribute. This value is used when computing
  // form signatures.
  // TODO(crbug.com/40598703): remove this and use attributes/unique_id instead.
  const std::u16string& name() const { return name_; }
  void set_name(std::u16string name) { name_ = std::move(name); }

  // Titles of form's buttons.
  const ButtonTitleList& button_titles() const { return button_titles_; }
  void set_button_titles(ButtonTitleList button_titles) {
    button_titles_ = std::move(button_titles);
  }

  // The URL (minus query parameters and fragment) containing the form.
  // This value should not be sent via mojo.
  const GURL& url() const { return url_; }
  void set_url(GURL url) { url_ = std::move(url); }

  // The full URL, including query parameters and fragment.
  // If `kAutofillIncludeUrlInCrowdsourcing` is disabled, this value should only
  // be set for password forms. This value should not be sent via mojo.
  const GURL& full_url() const { return full_url_; }
  void set_full_url(GURL full_url) { full_url_ = std::move(full_url); }

  // The action target of the form.
  const GURL& action() const { return action_; }
  void set_action(GURL action) { action_ = std::move(action); }

  // If the form in the DOM has an empty action attribute, the |action| field in
  // the FormData is set to the frame URL of the embedding document. This field
  // indicates whether the action attribute is empty in the form in the DOM.
  bool is_action_empty() const { return is_action_empty_; }
  void set_is_action_empty(bool is_action_empty) {
    is_action_empty_ = std::move(is_action_empty);
  }

  // The URL of main frame containing this form.
  // This value should not be sent via mojo.
  // |main_frame_origin| represents the main frame (not necessarily primary
  // main frame) of the form's frame tree as described by MPArch nested frame
  // trees. For details, see RenderFrameHost::GetMainFrame().
  const url::Origin& main_frame_origin() const { return main_frame_origin_; }
  void set_main_frame_origin(url::Origin main_frame_origin) {
    main_frame_origin_ = std::move(main_frame_origin);
  }

  // A unique identifier of the containing frame. This value is not serialized
  // because LocalFrameTokens must not be leaked to other renderer processes.
  // See LocalFrameToken for details.
  const LocalFrameToken& host_frame() const { return host_frame_; }
  void set_host_frame(LocalFrameToken host_frame) {
    host_frame_ = std::move(host_frame);
  }

  // Uniquely identifies the DOM element that this form represents among the
  // form DOM elements in the same frame.
  // In the browser process, use global_id() instead.
  // See global_id() for details.
  const FormRendererId& renderer_id() const { return renderer_id_; }
  void set_renderer_id(FormRendererId renderer_id) {
    renderer_id_ = std::move(renderer_id);
  }

  // A monotonically increasing counter that indicates the generation of the
  // form: if `f.version < g.version`, then `f` has been received from the
  // renderer before `g`. On non-iOS, the converse direction holds as well.
  //
  // This is intended only for AutofillManager's form cache as a workaround for
  // the cache-downdating problem.
  // TODO(crbug.com/40144964): Remove once FormData objects aren't stored
  // globally anymore.
  const FormVersion& version() const { return version_; }
  void set_version(FormVersion version) { version_ = std::move(version); }

  // A vector of all frames in the form, where currently 'frames' only refers
  // to iframes and not fenced frames. It can only be iframes because those are
  // the only frames with cross frame form filling.
  const std::vector<FrameTokenWithPredecessor>& child_frames() const {
    return child_frames_;
  }
  void set_child_frames(std::vector<FrameTokenWithPredecessor> child_frames) {
    child_frames_ = std::move(child_frames);
  }

  // The type of the event that was taken as an indication that this form is
  // being or has already been submitted. This field is filled only in Password
  // Manager for submitted password forms.
  mojom::SubmissionIndicatorEvent submission_event() const {
    return submission_event_;
  }
  void set_submission_event(mojom::SubmissionIndicatorEvent submission_event) {
    submission_event_ = std::move(submission_event);
  }

  // A vector of all the input fields in the form.
  //
  // WARNING: `fields` may contain duplicates:
  //
  // Usually, FormFieldData::global_id() (in the browser process) and
  // FormFieldData::renderer_id (in the renderer process) uniquely identify
  // objects in `fields`. This is reliable enough for practical purposes.
  //
  // Collisions are possible in rare cases. Two known scenarios are:
  // - The renderer is compromised and sends duplicates.
  // - In the DOM, a field F moves from a form G to a form H and the browser
  //   still knows an outdated version of G at the time it learns about the
  //   updated version of H. Then the browser has FormData representations of G
  //   and H which both include a FormFieldData representation of F. If G and H
  //   come from subframes, they're flattened into the same FormData, which then
  //   contains two representations of F; that is, FormData::fields contains two
  //   fields with the same FormFieldData::global_id().
  const std::vector<FormFieldData>& fields() const { return fields_; }
  void set_fields(std::vector<FormFieldData> new_fields) {
    fields_ = std::move(new_fields);
  }
  [[nodiscard]] std::vector<FormFieldData> ExtractFields() {
    return std::exchange(fields_, std::vector<FormFieldData>());
  }
  class MutableFieldsPassKey {
    constexpr MutableFieldsPassKey() = default;
    friend class FormDataAndroid;
    friend class internal::FormForest;
  };
  // Use `ExtractFields()` and `set_fields()` instead if possible.
  std::vector<FormFieldData>& mutable_fields(MutableFieldsPassKey pass_key) {
    return fields_;
  }

  // Contains unique renderer IDs of text elements which are predicted to be
  // usernames. The order matters: elements are sorted in descending likelihood
  // of being a username (the first one is the most likely username). Can
  // contain IDs of elements which are not in |fields|. This is only used during
  // parsing into PasswordForm, and hence not serialized for storage.
  const std::vector<FieldRendererId>& username_predictions() const {
    return username_predictions_;
  }
  void set_username_predictions(
      std::vector<FieldRendererId> username_predictions) {
    username_predictions_ = std::move(username_predictions);
  }

  // True if this is a Gaia form which should be skipped on saving.
  bool is_gaia_with_skip_save_password_form() const {
    return is_gaia_with_skip_save_password_form_;
  }
  void set_is_gaia_with_skip_save_password_form(
      bool is_gaia_with_skip_save_password_form) {
    is_gaia_with_skip_save_password_form_ =
        is_gaia_with_skip_save_password_form;
  }

  // Currently likely_contains_captcha_ is initialized only on Android platform.
  // For all other platforms its value is always `false`.
  bool likely_contains_captcha() const { return likely_contains_captcha_; }
  void set_likely_contains_captcha(bool likely_contains_captcha) {
    likely_contains_captcha_ = likely_contains_captcha;
  }

 private:
  friend class FormDataTestApi;

  std::u16string id_attribute_;
  std::u16string name_attribute_;
  std::u16string name_;
  ButtonTitleList button_titles_;
  GURL url_;
  GURL full_url_;
  GURL action_;
  bool is_action_empty_ = false;
  url::Origin main_frame_origin_;
  LocalFrameToken host_frame_;
  FormRendererId renderer_id_;
  FormVersion version_;
  std::vector<FrameTokenWithPredecessor> child_frames_;
  mojom::SubmissionIndicatorEvent submission_event_ =
      mojom::SubmissionIndicatorEvent::NONE;
  std::vector<FormFieldData> fields_;
  std::vector<FieldRendererId> username_predictions_;
  bool is_gaia_with_skip_save_password_form_ = false;
  bool likely_contains_captcha_ = false;
};

// Whether any of the fields in |form| is a non-empty password field.
bool FormHasNonEmptyPasswordField(const FormData& form);

// For testing.
std::ostream& operator<<(std::ostream& os, const FormData& form);

#if defined(UNIT_TEST)
inline bool operator==(const FormData& lhs, const FormData& rhs) {
  return FormData::DeepEqual(lhs, rhs);
}
#endif  // defined(UNIT_TEST)

// Serialize FormData. Used by the PasswordManager to persist FormData
// pertaining to password forms. Serialized data is appended to |pickle|.
void SerializeFormData(const FormData& form_data, base::Pickle* pickle);
// Deserialize FormData. This assumes that |iter| is currently pointing to
// the part of a pickle created by SerializeFormData. Returns true on success.
bool DeserializeFormData(base::PickleIterator* iter, FormData* form_data);

LogBuffer& operator<<(LogBuffer& buffer, const FormData& form);

}  // namespace autofill

#endif  // COMPONENTS_AUTOFILL_CORE_COMMON_FORM_DATA_H_