blob: 80d4f9295c2a6dcb7ee705d611cffb4ad9e50140 [file] [log] [blame]
QUICHE teamfd50a402018-12-07 22:54:05 -05001// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_collector.h"
6
QUICHE teamfd50a402018-12-07 22:54:05 -05007#include "testing/gtest/include/gtest/gtest.h"
8#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_string_collector.h"
9#include "net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h"
QUICHE team61940b42019-03-07 23:32:27 -050010#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
QUICHE teamfd50a402018-12-07 22:54:05 -050011#include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h"
12#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
13
14using ::testing::AssertionResult;
15
16namespace http2 {
17namespace test {
18namespace {
19
20const HpackEntryType kInvalidHeaderType = static_cast<HpackEntryType>(99);
21const size_t kInvalidIndex = 99999999;
22
23} // namespace
24
25HpackEntryCollector::HpackEntryCollector() {
26 Clear();
27}
28
29HpackEntryCollector::HpackEntryCollector(const HpackEntryCollector& other) =
30 default;
31
32HpackEntryCollector::HpackEntryCollector(HpackEntryType type,
33 size_t index_or_size)
34 : header_type_(type), index_(index_or_size), started_(true), ended_(true) {}
35HpackEntryCollector::HpackEntryCollector(HpackEntryType type,
36 size_t index,
37 bool value_huffman,
bnc47904002019-08-16 11:49:48 -070038 const std::string& value)
QUICHE teamfd50a402018-12-07 22:54:05 -050039 : header_type_(type),
40 index_(index),
41 value_(value, value_huffman),
42 started_(true),
43 ended_(true) {}
44HpackEntryCollector::HpackEntryCollector(HpackEntryType type,
45 bool name_huffman,
bnc47904002019-08-16 11:49:48 -070046 const std::string& name,
QUICHE teamfd50a402018-12-07 22:54:05 -050047 bool value_huffman,
bnc47904002019-08-16 11:49:48 -070048 const std::string& value)
QUICHE teamfd50a402018-12-07 22:54:05 -050049 : header_type_(type),
50 index_(0),
51 name_(name, name_huffman),
52 value_(value, value_huffman),
53 started_(true),
54 ended_(true) {}
55
56HpackEntryCollector::~HpackEntryCollector() = default;
57
58void HpackEntryCollector::OnIndexedHeader(size_t index) {
59 ASSERT_FALSE(started_);
60 ASSERT_TRUE(IsClear()) << ToString();
61 Init(HpackEntryType::kIndexedHeader, index);
62 ended_ = true;
63}
64void HpackEntryCollector::OnStartLiteralHeader(HpackEntryType header_type,
65 size_t maybe_name_index) {
66 ASSERT_FALSE(started_);
67 ASSERT_TRUE(IsClear()) << ToString();
68 Init(header_type, maybe_name_index);
69}
70void HpackEntryCollector::OnNameStart(bool huffman_encoded, size_t len) {
71 ASSERT_TRUE(started_);
72 ASSERT_FALSE(ended_);
73 ASSERT_FALSE(IsClear());
74 ASSERT_TRUE(LiteralNameExpected()) << ToString();
75 name_.OnStringStart(huffman_encoded, len);
76}
77void HpackEntryCollector::OnNameData(const char* data, size_t len) {
78 ASSERT_TRUE(started_);
79 ASSERT_FALSE(ended_);
80 ASSERT_TRUE(LiteralNameExpected()) << ToString();
81 ASSERT_TRUE(name_.IsInProgress());
82 name_.OnStringData(data, len);
83}
84void HpackEntryCollector::OnNameEnd() {
85 ASSERT_TRUE(started_);
86 ASSERT_FALSE(ended_);
87 ASSERT_TRUE(LiteralNameExpected()) << ToString();
88 ASSERT_TRUE(name_.IsInProgress());
89 name_.OnStringEnd();
90}
91void HpackEntryCollector::OnValueStart(bool huffman_encoded, size_t len) {
92 ASSERT_TRUE(started_);
93 ASSERT_FALSE(ended_);
94 if (LiteralNameExpected()) {
95 ASSERT_TRUE(name_.HasEnded());
96 }
97 ASSERT_TRUE(LiteralValueExpected()) << ToString();
98 ASSERT_TRUE(value_.IsClear()) << value_.ToString();
99 value_.OnStringStart(huffman_encoded, len);
100}
101void HpackEntryCollector::OnValueData(const char* data, size_t len) {
102 ASSERT_TRUE(started_);
103 ASSERT_FALSE(ended_);
104 ASSERT_TRUE(LiteralValueExpected()) << ToString();
105 ASSERT_TRUE(value_.IsInProgress());
106 value_.OnStringData(data, len);
107}
108void HpackEntryCollector::OnValueEnd() {
109 ASSERT_TRUE(started_);
110 ASSERT_FALSE(ended_);
111 ASSERT_TRUE(LiteralValueExpected()) << ToString();
112 ASSERT_TRUE(value_.IsInProgress());
113 value_.OnStringEnd();
114 ended_ = true;
115}
116void HpackEntryCollector::OnDynamicTableSizeUpdate(size_t size) {
117 ASSERT_FALSE(started_);
118 ASSERT_TRUE(IsClear()) << ToString();
119 Init(HpackEntryType::kDynamicTableSizeUpdate, size);
120 ended_ = true;
121}
122
123void HpackEntryCollector::Clear() {
124 header_type_ = kInvalidHeaderType;
125 index_ = kInvalidIndex;
126 name_.Clear();
127 value_.Clear();
128 started_ = ended_ = false;
129}
130bool HpackEntryCollector::IsClear() const {
131 return header_type_ == kInvalidHeaderType && index_ == kInvalidIndex &&
132 name_.IsClear() && value_.IsClear() && !started_ && !ended_;
133}
134bool HpackEntryCollector::IsComplete() const {
135 return started_ && ended_;
136}
137bool HpackEntryCollector::LiteralNameExpected() const {
138 switch (header_type_) {
139 case HpackEntryType::kIndexedLiteralHeader:
140 case HpackEntryType::kUnindexedLiteralHeader:
141 case HpackEntryType::kNeverIndexedLiteralHeader:
142 return index_ == 0;
143 default:
144 return false;
145 }
146}
147bool HpackEntryCollector::LiteralValueExpected() const {
148 switch (header_type_) {
149 case HpackEntryType::kIndexedLiteralHeader:
150 case HpackEntryType::kUnindexedLiteralHeader:
151 case HpackEntryType::kNeverIndexedLiteralHeader:
152 return true;
153 default:
154 return false;
155 }
156}
157AssertionResult HpackEntryCollector::ValidateIndexedHeader(
158 size_t expected_index) const {
159 VERIFY_TRUE(started_);
160 VERIFY_TRUE(ended_);
161 VERIFY_EQ(HpackEntryType::kIndexedHeader, header_type_);
162 VERIFY_EQ(expected_index, index_);
163 return ::testing::AssertionSuccess();
164}
165AssertionResult HpackEntryCollector::ValidateLiteralValueHeader(
166 HpackEntryType expected_type,
167 size_t expected_index,
168 bool expected_value_huffman,
bnc74646d12019-12-13 09:21:19 -0800169 quiche::QuicheStringPiece expected_value) const {
QUICHE teamfd50a402018-12-07 22:54:05 -0500170 VERIFY_TRUE(started_);
171 VERIFY_TRUE(ended_);
172 VERIFY_EQ(expected_type, header_type_);
173 VERIFY_NE(0u, expected_index);
174 VERIFY_EQ(expected_index, index_);
175 VERIFY_TRUE(name_.IsClear());
176 VERIFY_SUCCESS(value_.Collected(expected_value, expected_value_huffman));
177 return ::testing::AssertionSuccess();
178}
179AssertionResult HpackEntryCollector::ValidateLiteralNameValueHeader(
180 HpackEntryType expected_type,
181 bool expected_name_huffman,
bnc74646d12019-12-13 09:21:19 -0800182 quiche::QuicheStringPiece expected_name,
QUICHE teamfd50a402018-12-07 22:54:05 -0500183 bool expected_value_huffman,
bnc74646d12019-12-13 09:21:19 -0800184 quiche::QuicheStringPiece expected_value) const {
QUICHE teamfd50a402018-12-07 22:54:05 -0500185 VERIFY_TRUE(started_);
186 VERIFY_TRUE(ended_);
187 VERIFY_EQ(expected_type, header_type_);
188 VERIFY_EQ(0u, index_);
189 VERIFY_SUCCESS(name_.Collected(expected_name, expected_name_huffman));
190 VERIFY_SUCCESS(value_.Collected(expected_value, expected_value_huffman));
191 return ::testing::AssertionSuccess();
192}
193AssertionResult HpackEntryCollector::ValidateDynamicTableSizeUpdate(
194 size_t size) const {
195 VERIFY_TRUE(started_);
196 VERIFY_TRUE(ended_);
197 VERIFY_EQ(HpackEntryType::kDynamicTableSizeUpdate, header_type_);
198 VERIFY_EQ(index_, size);
199 return ::testing::AssertionSuccess();
200}
201
202void HpackEntryCollector::AppendToHpackBlockBuilder(
203 HpackBlockBuilder* hbb) const {
204 ASSERT_TRUE(started_ && ended_) << *this;
205 switch (header_type_) {
206 case HpackEntryType::kIndexedHeader:
207 hbb->AppendIndexedHeader(index_);
208 return;
209
210 case HpackEntryType::kDynamicTableSizeUpdate:
211 hbb->AppendDynamicTableSizeUpdate(index_);
212 return;
213
214 case HpackEntryType::kIndexedLiteralHeader:
215 case HpackEntryType::kUnindexedLiteralHeader:
216 case HpackEntryType::kNeverIndexedLiteralHeader:
217 ASSERT_TRUE(value_.HasEnded()) << *this;
218 if (index_ != 0) {
219 CHECK(name_.IsClear());
220 hbb->AppendNameIndexAndLiteralValue(header_type_, index_,
221 value_.huffman_encoded, value_.s);
222 } else {
223 CHECK(name_.HasEnded()) << *this;
224 hbb->AppendLiteralNameAndValue(header_type_, name_.huffman_encoded,
225 name_.s, value_.huffman_encoded,
226 value_.s);
227 }
228 return;
229
230 default:
231 ADD_FAILURE() << *this;
232 }
233}
234
bnc47904002019-08-16 11:49:48 -0700235std::string HpackEntryCollector::ToString() const {
236 std::string result("Type=");
QUICHE teamfd50a402018-12-07 22:54:05 -0500237 switch (header_type_) {
238 case HpackEntryType::kIndexedHeader:
239 result += "IndexedHeader";
240 break;
241 case HpackEntryType::kDynamicTableSizeUpdate:
242 result += "DynamicTableSizeUpdate";
243 break;
244 case HpackEntryType::kIndexedLiteralHeader:
245 result += "IndexedLiteralHeader";
246 break;
247 case HpackEntryType::kUnindexedLiteralHeader:
248 result += "UnindexedLiteralHeader";
249 break;
250 case HpackEntryType::kNeverIndexedLiteralHeader:
251 result += "NeverIndexedLiteralHeader";
252 break;
253 default:
254 if (header_type_ == kInvalidHeaderType) {
255 result += "<unset>";
256 } else {
257 Http2StrAppend(&result, header_type_);
258 }
259 }
260 if (index_ != 0) {
261 Http2StrAppend(&result, " Index=", index_);
262 }
263 if (!name_.IsClear()) {
264 Http2StrAppend(&result, " Name", name_.ToString());
265 }
266 if (!value_.IsClear()) {
267 Http2StrAppend(&result, " Value", value_.ToString());
268 }
269 if (!started_) {
270 EXPECT_FALSE(ended_);
271 Http2StrAppend(&result, " !started");
272 } else if (!ended_) {
273 Http2StrAppend(&result, " !ended");
274 } else {
275 Http2StrAppend(&result, " Complete");
276 }
277 return result;
278}
279
280void HpackEntryCollector::Init(HpackEntryType type, size_t maybe_index) {
281 ASSERT_TRUE(IsClear()) << ToString();
282 header_type_ = type;
283 index_ = maybe_index;
284 started_ = true;
285}
286
287bool operator==(const HpackEntryCollector& a, const HpackEntryCollector& b) {
288 return a.name() == b.name() && a.value() == b.value() &&
289 a.index() == b.index() && a.header_type() == b.header_type() &&
290 a.started() == b.started() && a.ended() == b.ended();
291}
292bool operator!=(const HpackEntryCollector& a, const HpackEntryCollector& b) {
293 return !(a == b);
294}
295
296std::ostream& operator<<(std::ostream& out, const HpackEntryCollector& v) {
297 return out << v.ToString();
298}
299
300} // namespace test
301} // namespace http2