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
content / services / auction_worklet / public / cpp / cbor_test_util.cc [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/services/auction_worklet/public/cpp/cbor_test_util.h"
#include <stdint.h>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "base/check.h"
#include "base/containers/span.h"
#include "base/containers/span_writer.h"
#include "base/numerics/safe_conversions.h"
#include "base/test/values_test_util.h"
#include "base/values.h"
#include "components/cbor/values.h"
#include "components/cbor/writer.h"
namespace auction_worklet::test {
namespace {
// Lengths of various components of request and response header components.
constexpr size_t kCompressionFormatSize = 1; // bytes
constexpr size_t kCborStringLengthSize = 4; // bytes
constexpr size_t kOhttpHeaderSize = 55; // bytes
// If `convert_content_to_binary_cbor_string` is true, converts "content" values
// in dictionaries to binary CBOR strings. See documentation of
// ToKVv2ResponseCborString() for more details.
cbor::Value ToCbor(const base::Value& value,
bool convert_content_to_binary_cbor_string = false) {
switch (value.type()) {
case base::Value::Type::NONE:
return cbor::Value();
case base::Value::Type::BOOLEAN:
return cbor::Value(value.GetBool());
case base::Value::Type::INTEGER:
return cbor::Value(value.GetInt());
case base::Value::Type::DOUBLE:
return cbor::Value(value.GetDouble());
case base::Value::Type::STRING:
return cbor::Value(value.GetString());
case base::Value::Type::BINARY:
return cbor::Value(value.GetBlob());
case base::Value::Type::DICT: {
cbor::Value::MapValue map;
for (auto pair : value.GetDict()) {
if (convert_content_to_binary_cbor_string && pair.first == "content") {
std::optional<std::vector<uint8_t>> cbor_blob =
cbor::Writer::Write(ToCbor(pair.second));
CHECK(cbor_blob);
map.try_emplace(cbor::Value(pair.first),
cbor::Value(std::move(cbor_blob).value()));
continue;
}
map.try_emplace(
cbor::Value(pair.first),
ToCbor(pair.second, convert_content_to_binary_cbor_string));
}
return cbor::Value(std::move(map));
}
case base::Value::Type::LIST: {
cbor::Value::ArrayValue array;
for (const auto& entry : value.GetList()) {
array.emplace_back(
ToCbor(entry, convert_content_to_binary_cbor_string));
}
return cbor::Value(std::move(array));
}
default:
// Use a default since this is test-only code, and to avoid causing issues
// if a new type is added to base::Value.
NOTREACHED();
}
}
} // namespace
std::vector<uint8_t> ToCborVector(std::string_view json) {
std::optional<std::vector<uint8_t>> out =
cbor::Writer::Write(ToCbor(base::test::ParseJson(json)));
CHECK(out);
return std::move(out).value();
}
std::string ToCborString(std::string_view json) {
std::vector<uint8_t> vector = ToCborVector(json);
return std::string(vector.begin(), vector.end());
}
std::string ToKVv2ResponseCborString(std::string_view json) {
std::optional<std::vector<uint8_t>> vector = cbor::Writer::Write(
ToCbor(base::test::ParseJson(json),
/*convert_content_to_binary_cbor_string=*/true));
CHECK(vector);
return std::string(vector->begin(), vector->end());
}
std::string CreateKVv2RequestBody(std::string_view cbor_request_body) {
std::string request_body;
size_t size_before_padding = kOhttpHeaderSize + kCompressionFormatSize +
kCborStringLengthSize + cbor_request_body.size();
size_t size_with_padding = std::bit_ceil(size_before_padding);
size_t request_body_size = size_with_padding - kOhttpHeaderSize;
request_body.resize(request_body_size, 0x00);
base::SpanWriter writer(
base::as_writable_bytes(base::make_span(request_body)));
// Add framing header. First byte includes version and compression format.
// Always set first byte to 0x00 because request body is uncompressed.
writer.WriteU8BigEndian(0x00);
writer.WriteU32BigEndian(
base::checked_cast<uint32_t>(cbor_request_body.size()));
// Add CBOR string.
writer.Write(base::as_bytes(base::make_span(cbor_request_body)));
DCHECK_EQ(writer.num_written(), size_before_padding - kOhttpHeaderSize);
return request_body;
}
std::string CreateKVv2ResponseBody(std::string_view cbor_response_body,
std::optional<size_t> advertised_cbor_length,
size_t padding_length,
uint8_t compression_scheme) {
if (!advertised_cbor_length.has_value()) {
advertised_cbor_length = cbor_response_body.length();
}
std::string response_body(5 + cbor_response_body.size() + padding_length, 0);
base::SpanWriter writer(
base::as_writable_bytes(base::make_span(response_body)));
writer.WriteU8BigEndian(compression_scheme);
writer.WriteU32BigEndian(*advertised_cbor_length);
writer.Write(base::as_bytes(base::make_span(cbor_response_body)));
return response_body;
}
} // namespace auction_worklet::test