chromium/third_party/blink/common/page_state/page_state_serialization.cc

// 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.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "third_party/blink/public/common/page_state/page_state_serialization.h"

#include <algorithm>
#include <limits>
#include <utility>

#include "base/containers/span.h"
#include "base/pickle.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "mojo/public/cpp/base/string16_mojom_traits.h"
#include "mojo/public/cpp/base/time_mojom_traits.h"
#include "mojo/public/cpp/bindings/enum_utils.h"
#include "services/network/public/cpp/resource_request_body.h"
#include "third_party/blink/public/common/loader/http_body_element_type.h"
#include "third_party/blink/public/common/unique_name/unique_name_helper.h"
#include "third_party/blink/public/mojom/page_state/page_state.mojom.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/mojom/geometry_mojom_traits.h"
#include "url/mojom/url_gurl_mojom_traits.h"

namespace blink {

namespace {

#if BUILDFLAG(IS_ANDROID)
float g_device_scale_factor_for_testing = 0.0;
#endif

//-----------------------------------------------------------------------------

void AppendDataToRequestBody(
    const scoped_refptr<network::ResourceRequestBody>& request_body,
    const char* data,
    size_t data_length) {}

void AppendFileRangeToRequestBody(
    const scoped_refptr<network::ResourceRequestBody>& request_body,
    const std::optional<std::u16string>& file_path,
    int file_start,
    int file_length,
    base::Time file_modification_time) {}

//----------------------------------------------------------------------------

void AppendReferencedFilesFromHttpBody(
    const std::vector<network::DataElement>& elements,
    std::vector<std::optional<std::u16string>>* referenced_files) {}

bool AppendReferencedFilesFromDocumentState(
    const std::vector<std::optional<std::u16string>>& document_state,
    std::vector<std::optional<std::u16string>>* referenced_files) {}

bool RecursivelyAppendReferencedFiles(
    const ExplodedFrameState& frame_state,
    std::vector<std::optional<std::u16string>>* referenced_files) {}

//----------------------------------------------------------------------------

struct SerializeObject {};

// IMPORTANT: When making updates to the PageState serialization code, be sure
// to first read
// https://chromium.googlesource.com/chromium/src/+/main/docs/modifying_session_history_serialization.md

// Version ID of serialized format.
// 11: Min version
// 12: Adds support for contains_passwords in HTTP body
// 13: Adds support for URL (FileSystem URL)
// 14: Adds list of referenced files, version written only for first item.
// 15: Removes a bunch of values we defined but never used.
// 16: Switched from blob urls to blob uuids.
// 17: Add a target frame id number.
// 18: Add referrer policy.
// 19: Remove target frame id, which was a bad idea, and original url string,
//         which is no longer used.
// 20: Add visual viewport scroll offset, the offset of the pinched zoomed
//     viewport within the unzoomed main frame.
// 21: Add frame sequence number.
// 22: Add scroll restoration type.
// 23: Remove frame sequence number, there are easier ways.
// 24: Add did save scroll or scale state.
// 25: Limit the length of unique names: https://crbug.com/626202
// 26: Switch to mojo-based serialization.
// 27: Add serialized scroll anchor to FrameState.
// 28: Add initiator origin to FrameState.
// 29: Add navigation API key.
// 30: Add navigation API state.
// 31: Add protect url in navigation API bit.
// 32: Fix assign() for initiator origin.
// 33: Add initiator base url to FrameState.
// NOTE: If the version is -1, then the pickle contains only a URL string.
// See ReadPageState.
//
const int kMinVersion =;
// NOTE: When changing the version, please add a backwards compatibility test.
// See PageStateSerializationTest.DumpExpectedPageStateForBackwardsCompat for
// instructions on how to generate the new test case.
const int kCurrentVersion =;

// A bunch of convenience functions to write to/read from SerializeObjects.  The
// de-serializers assume the input data will be in the correct format and fall
// back to returning safe defaults when not. These are mostly used by
// legacy(pre-mojo) serialization methods. If you're making changes to the
// PageState serialization format you almost certainly want to add/remove fields
// in page_state.mojom rather than using these methods.

void WriteData(base::span<const uint8_t> data, SerializeObject* obj) {}

std::optional<base::span<const uint8_t>> ReadData(SerializeObject* obj) {}

void WriteInteger(int data, SerializeObject* obj) {}

int ReadInteger(SerializeObject* obj) {}

void WriteInteger64(int64_t data, SerializeObject* obj) {}

int64_t ReadInteger64(SerializeObject* obj) {}

void WriteReal(double data, SerializeObject* obj) {}

double ReadReal(SerializeObject* obj) {}

void WriteBoolean(bool data, SerializeObject* obj) {}

bool ReadBoolean(SerializeObject* obj) {}

GURL ReadGURL(SerializeObject* obj) {}

std::string ReadStdString(SerializeObject* obj) {}

// Pickles a std::u16string as <int length>:<char*16 data> tuple>.
void WriteString(const std::u16string& str, SerializeObject* obj) {}

// If str is a null optional, this simply pickles a length of -1. Otherwise,
// delegates to the std::u16string overload.
void WriteString(const std::optional<std::u16string>& str,
                 SerializeObject* obj) {}

// This reads a serialized std::optional<std::u16string> from obj. If a string
// can't be read, nullptr is returned.
const char16_t* ReadStringNoCopy(SerializeObject* obj, int* num_chars) {}

std::optional<std::u16string> ReadString(SerializeObject* obj) {}

template <typename T>
void WriteAndValidateVectorSize(const std::vector<T>& v, SerializeObject* obj) {}

size_t ReadAndValidateVectorSize(SerializeObject* obj, size_t element_size) {}

// Writes a Vector of strings into a SerializeObject for serialization.
void WriteStringVector(const std::vector<std::optional<std::u16string>>& data,
                       SerializeObject* obj) {}

void ReadStringVector(SerializeObject* obj,
                      std::vector<std::optional<std::u16string>>* result) {}

void WriteResourceRequestBody(const network::ResourceRequestBody& request_body,
                              SerializeObject* obj) {}

void ReadResourceRequestBody(
    SerializeObject* obj,
    const scoped_refptr<network::ResourceRequestBody>& request_body) {}

void ReadHttpBody(SerializeObject* obj, ExplodedHttpBody* http_body) {}

void WriteHttpBody(const ExplodedHttpBody& http_body, SerializeObject* obj) {}

// This is only used for versions < 26. Later versions use ReadMojoFrameState.
void ReadLegacyFrameState(
    SerializeObject* obj,
    bool is_top,
    std::vector<UniqueNameHelper::Replacement>* unique_name_replacements,
    ExplodedFrameState* state) {}

// Writes the ExplodedFrameState data into the SerializeObject object for
// serialization. This uses the custom, legacy format, and its implementation
// should remain frozen in order to preserve this format.
// TODO(pnoland, dcheng) Move the legacy write methods into a test-only helper.
void WriteLegacyFrameState(const ExplodedFrameState& state,
                           SerializeObject* obj,
                           bool is_top) {}

void WriteLegacyPageState(const ExplodedPageState& state,
                          SerializeObject* obj) {}

// Legacy read/write functions above this line. Don't change these.
//-----------------------------------------------------------------------------
// "Modern" read/write functions start here. These are probably what you want.

void WriteResourceRequestBody(const network::ResourceRequestBody& request_body,
                              mojom::RequestBody* mojo_body) {}

void ReadResourceRequestBody(
    mojom::RequestBody* mojo_body,
    const scoped_refptr<network::ResourceRequestBody>& request_body) {}

void WriteHttpBody(const ExplodedHttpBody& http_body,
                   mojom::HttpBody* mojo_body) {}

void ReadHttpBody(mojom::HttpBody* mojo_body, ExplodedHttpBody* http_body) {}

// Do not depend on feature state when writing data to frame, so that the
// contents of persisted history do not depend on whether a feature is enabled
// or not.
void WriteMojoFrameState(const ExplodedFrameState& state,
                         mojom::FrameState* frame) {}

// This is used for versions >= 26.
void ReadMojoFrameState(mojom::FrameState* frame, ExplodedFrameState* state) {}

void ReadMojoPageState(SerializeObject* obj, ExplodedPageState* state) {}

void WriteMojoPageState(const ExplodedPageState& state, SerializeObject* obj) {}

void ReadPageState(SerializeObject* obj, ExplodedPageState* state) {}

}  // namespace

ExplodedHttpBody::ExplodedHttpBody() :{}

ExplodedHttpBody::~ExplodedHttpBody() {}

ExplodedFrameState::ExplodedFrameState() = default;

ExplodedFrameState::ExplodedFrameState(const ExplodedFrameState& other) {}

ExplodedFrameState::~ExplodedFrameState() {}

void ExplodedFrameState::operator=(const ExplodedFrameState& other) {}

// All members of ExplodedFrameState should be copied.
void ExplodedFrameState::assign(const ExplodedFrameState& other) {}

ExplodedPageState::ExplodedPageState() {}

ExplodedPageState::~ExplodedPageState() {}

int DecodePageStateInternal(const std::string& encoded,
                            ExplodedPageState* exploded) {}

bool DecodePageState(const std::string& encoded, ExplodedPageState* exploded) {}

int DecodePageStateForTesting(const std::string& encoded,
                              ExplodedPageState* exploded) {}

void EncodePageState(const ExplodedPageState& exploded, std::string* encoded) {}

void LegacyEncodePageStateForTesting(const ExplodedPageState& exploded,
                                     int version,
                                     std::string* encoded) {}

#if BUILDFLAG(IS_ANDROID)
bool DecodePageStateWithDeviceScaleFactorForTesting(
    const std::string& encoded,
    float device_scale_factor,
    ExplodedPageState* exploded) {
  g_device_scale_factor_for_testing = device_scale_factor;
  bool rv = DecodePageState(encoded, exploded);
  g_device_scale_factor_for_testing = 0.0;
  return rv;
}

scoped_refptr<network::ResourceRequestBody> DecodeResourceRequestBody(
    const char* data,
    size_t size) {
  scoped_refptr<network::ResourceRequestBody> result =
      new network::ResourceRequestBody();
  SerializeObject obj(base::as_bytes(base::span(data, size)));
  ReadResourceRequestBody(&obj, result);
  // Please see the EncodeResourceRequestBody() function below for information
  // about why the contains_sensitive_info() field is being explicitly
  // deserialized.
  result->set_contains_sensitive_info(ReadBoolean(&obj));
  return obj.parse_error ? nullptr : result;
}

std::string EncodeResourceRequestBody(
    const network::ResourceRequestBody& resource_request_body) {
  SerializeObject obj;
  obj.version = 25;
  WriteResourceRequestBody(resource_request_body, &obj);
  // EncodeResourceRequestBody() is different from WriteResourceRequestBody()
  // because it covers additional data (e.g.|contains_sensitive_info|) which
  // is marshaled between native code and java. WriteResourceRequestBody()
  // serializes data which needs to be saved out to disk.
  WriteBoolean(resource_request_body.contains_sensitive_info(), &obj);
  return obj.GetAsString();
}

#endif

}  // namespace blink