blob: dcb028e68f043ffbfbf1fa07967216bee5e413fe [file] [log] [blame]
// Copyright 2013 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/autofill/core/common/form_data.h"
#include <stddef.h>
#include <tuple>
#include "base/base64.h"
#include "base/pickle.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/common/form_field_data.h"
namespace autofill {
namespace {
const int kFormDataPickleVersion = 6;
bool ReadGURL(base::PickleIterator* iter, GURL* url) {
std::string spec;
if (!iter->ReadString(&spec))
return false;
*url = GURL(spec);
return true;
}
bool ReadOrigin(base::PickleIterator* iter, url::Origin* origin) {
std::string spec;
if (!iter->ReadString(&spec))
return false;
*origin = url::Origin::Create(GURL(spec));
return true;
}
void SerializeFormFieldDataVector(const std::vector<FormFieldData>& fields,
base::Pickle* pickle) {
pickle->WriteInt(static_cast<int>(fields.size()));
for (size_t i = 0; i < fields.size(); ++i) {
SerializeFormFieldData(fields[i], pickle);
}
}
bool DeserializeFormFieldDataVector(base::PickleIterator* iter,
std::vector<FormFieldData>* fields) {
int size;
if (!iter->ReadInt(&size))
return false;
FormFieldData temp;
for (int i = 0; i < size; ++i) {
if (!DeserializeFormFieldData(iter, &temp))
return false;
fields->push_back(temp);
}
return true;
}
void LogDeserializationError(int version) {
DVLOG(1) << "Could not deserialize version " << version
<< " FormData from pickle.";
}
} // namespace
FormData::FormData() : is_form_tag(true), is_formless_checkout(false) {}
FormData::FormData(const FormData& data)
: name(data.name),
button_title(data.button_title),
origin(data.origin),
action(data.action),
main_frame_origin(data.main_frame_origin),
is_form_tag(data.is_form_tag),
is_formless_checkout(data.is_formless_checkout),
unique_renderer_id(data.unique_renderer_id),
fields(data.fields),
username_predictions(data.username_predictions) {}
FormData::~FormData() {
}
bool FormData::SameFormAs(const FormData& form) const {
if (name != form.name || origin != form.origin || action != form.action ||
is_form_tag != form.is_form_tag ||
is_formless_checkout != form.is_formless_checkout ||
fields.size() != form.fields.size())
return false;
for (size_t i = 0; i < fields.size(); ++i) {
if (!fields[i].SameFieldAs(form.fields[i]))
return false;
}
return true;
}
bool FormData::SimilarFormAs(const FormData& form) const {
if (name != form.name || origin != form.origin || action != form.action ||
is_form_tag != form.is_form_tag ||
is_formless_checkout != form.is_formless_checkout ||
fields.size() != form.fields.size())
return false;
for (size_t i = 0; i < fields.size(); ++i) {
if (!fields[i].SimilarFieldAs(form.fields[i]))
return false;
}
return true;
}
bool FormData::DynamicallySameFormAs(const FormData& form) const {
if (name != form.name || fields.size() != form.fields.size())
return false;
for (size_t i = 0; i < fields.size(); ++i) {
if (!fields[i].DynamicallySameFieldAs(form.fields[i]))
return false;
}
return true;
}
bool FormData::operator==(const FormData& form) const {
return name == form.name && origin == form.origin && action == form.action &&
unique_renderer_id == form.unique_renderer_id &&
is_form_tag == form.is_form_tag &&
is_formless_checkout == form.is_formless_checkout &&
fields == form.fields &&
username_predictions == form.username_predictions;
}
bool FormData::operator!=(const FormData& form) const {
return !(*this == form);
}
bool FormData::operator<(const FormData& form) const {
return std::tie(name, origin, action, is_form_tag, is_formless_checkout,
fields) < std::tie(form.name, form.origin, form.action,
form.is_form_tag,
form.is_formless_checkout, form.fields);
}
std::ostream& operator<<(std::ostream& os, const FormData& form) {
os << base::UTF16ToUTF8(form.name) << " " << form.origin << " " << form.action
<< " " << form.main_frame_origin << " " << form.is_form_tag << " "
<< form.is_formless_checkout << " "
<< "Fields:";
for (size_t i = 0; i < form.fields.size(); ++i) {
os << form.fields[i] << ",";
}
return os;
}
void SerializeFormData(const FormData& form_data, base::Pickle* pickle) {
pickle->WriteInt(kFormDataPickleVersion);
pickle->WriteString16(form_data.name);
pickle->WriteString(form_data.origin.spec());
pickle->WriteString(form_data.action.spec());
SerializeFormFieldDataVector(form_data.fields, pickle);
pickle->WriteBool(form_data.is_form_tag);
pickle->WriteBool(form_data.is_formless_checkout);
pickle->WriteString(form_data.main_frame_origin.Serialize());
}
void SerializeFormDataToBase64String(const FormData& form_data,
std::string* output) {
base::Pickle pickle;
SerializeFormData(form_data, &pickle);
Base64Encode(
base::StringPiece(static_cast<const char*>(pickle.data()), pickle.size()),
output);
}
bool DeserializeFormData(base::PickleIterator* iter, FormData* form_data) {
int version;
FormData temp_form_data;
if (!iter->ReadInt(&version)) {
DVLOG(1) << "Bad pickle of FormData, no version present";
return false;
}
if (version < 1 || version > kFormDataPickleVersion) {
DVLOG(1) << "Unknown FormData pickle version " << version;
return false;
}
if (!iter->ReadString16(&temp_form_data.name)) {
LogDeserializationError(version);
return false;
}
if (version == 1) {
base::string16 method;
if (!iter->ReadString16(&method)) {
LogDeserializationError(version);
return false;
}
}
bool unused_user_submitted;
if (!ReadGURL(iter, &temp_form_data.origin) ||
!ReadGURL(iter, &temp_form_data.action) ||
// user_submitted was removed/no longer serialized in version 4.
(version < 4 && !iter->ReadBool(&unused_user_submitted)) ||
!DeserializeFormFieldDataVector(iter, &temp_form_data.fields)) {
LogDeserializationError(version);
return false;
}
if (version >= 3) {
if (!iter->ReadBool(&temp_form_data.is_form_tag)) {
LogDeserializationError(version);
return false;
}
} else {
form_data->is_form_tag = true;
}
if (version >= 5) {
if (!iter->ReadBool(&temp_form_data.is_formless_checkout)) {
LogDeserializationError(version);
return false;
}
}
if (version >= 6) {
if (!ReadOrigin(iter, &temp_form_data.main_frame_origin)) {
LogDeserializationError(version);
return false;
}
}
*form_data = temp_form_data;
return true;
}
bool DeserializeFormDataFromBase64String(const base::StringPiece& input,
FormData* form_data) {
if (input.empty())
return false;
std::string pickle_data;
Base64Decode(input, &pickle_data);
base::Pickle pickle(pickle_data.data(), static_cast<int>(pickle_data.size()));
base::PickleIterator iter(pickle);
return DeserializeFormData(&iter, form_data);
}
} // namespace autofill