blob: e00006c72d4c25bbb7100670b35aedfd1028aa33 [file] [log] [blame]
// Copyright 2018 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 "components/password_manager/core/browser/form_parsing/fuzzer/form_data_producer.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/password_manager/core/browser/form_parsing/fuzzer/data_accessor.h"
#include "url/gurl.h"
#include "url/origin.h"
using autofill::FormData;
using autofill::FormFieldData;
namespace password_manager {
namespace {
struct FormFieldDataParams {
size_t form_control_type_length;
size_t autocomplete_attribute_length;
size_t label_length;
size_t name_length;
size_t id_length;
size_t value_length;
// In an array of FormFieldData, all instances with |same_value_field| true
// get the same value as the first such instance.
bool same_value_field;
};
} // namespace
FormData GenerateWithDataAccessor(DataAccessor* accessor) {
FormData result;
// First determine the main non-string attributes not specific to particular
// fields.
result.is_form_tag = accessor->ConsumeBit();
result.is_formless_checkout = accessor->ConsumeBit();
// To minimize wasting bits, string-based data itself gets extracted after all
// numbers and flags are. Their length can be determined now, however. A
// reasonable range is 0-127 characters, i.e., 7 bits.
const size_t name_length = accessor->ConsumeNumber(7);
const size_t action_length = accessor->ConsumeNumber(7);
const size_t origin_length = accessor->ConsumeNumber(7);
const size_t main_frame_origin_length = accessor->ConsumeNumber(7);
// Determine how many fields this form will have. 0-15, i.e., 4 bits.
const size_t number_of_fields = accessor->ConsumeNumber(4);
result.fields.resize(number_of_fields);
FormFieldDataParams field_params[15];
int first_field_with_same_value = -1;
for (size_t i = 0; i < number_of_fields; ++i) {
// Determine the non-string value for each field.
result.fields[i].is_focusable = accessor->ConsumeBit();
// And the lengths of the string values.
field_params[i].form_control_type_length = accessor->ConsumeNumber(7);
field_params[i].autocomplete_attribute_length = accessor->ConsumeNumber(7);
field_params[i].label_length = accessor->ConsumeNumber(7);
field_params[i].name_length = accessor->ConsumeNumber(7);
field_params[i].id_length = accessor->ConsumeNumber(7);
field_params[i].same_value_field = accessor->ConsumeBit();
bool has_value_copy_from_earlier = field_params[i].same_value_field;
if (field_params[i].same_value_field && first_field_with_same_value == -1) {
first_field_with_same_value = static_cast<int>(i);
has_value_copy_from_earlier = false;
}
// Emtpy values are interesting from the parsing perspective. Ensure that a
// big chunk of the cases ends up with an empty value by letting an input
// bit decide.
field_params[i].value_length = 0;
if (!has_value_copy_from_earlier && accessor->ConsumeBit()) {
field_params[i].value_length = accessor->ConsumeNumber(7) + 1;
}
}
// Now go back and determine the string-based values of the form itself.
result.name = accessor->ConsumeString16(name_length);
result.action = GURL(accessor->ConsumeString(action_length));
result.origin = GURL(accessor->ConsumeString(origin_length));
result.main_frame_origin = url::Origin::Create(
GURL(accessor->ConsumeString(main_frame_origin_length)));
// And finally do the same for all the fields.
for (size_t i = 0; i < number_of_fields; ++i) {
result.fields[i].form_control_type =
accessor->ConsumeString(field_params[i].form_control_type_length);
result.fields[i].autocomplete_attribute =
accessor->ConsumeString(field_params[i].autocomplete_attribute_length);
result.fields[i].label =
accessor->ConsumeString16(field_params[i].label_length);
result.fields[i].name =
accessor->ConsumeString16(field_params[i].name_length);
result.fields[i].name_attribute = result.fields[i].name;
result.fields[i].id_attribute =
accessor->ConsumeString16(field_params[i].id_length);
#if defined(OS_IOS)
result.fields[i].unique_id = result.fields[i].id_attribute +
base::UTF8ToUTF16("-") +
base::NumberToString16(i);
#endif
if (field_params[i].same_value_field &&
first_field_with_same_value != static_cast<int>(i)) {
result.fields[i].value = result.fields[first_field_with_same_value].value;
} else {
result.fields[i].value =
accessor->ConsumeString16(field_params[i].value_length);
}
}
return result;
}
} // namespace password_manager