1 // 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 "quiche/http2/test_tools/hpack_entry_collector.h"
6
7 #include "absl/strings/str_cat.h"
8 #include "quiche/http2/hpack/http2_hpack_constants.h"
9 #include "quiche/http2/test_tools/hpack_string_collector.h"
10 #include "quiche/http2/test_tools/verify_macros.h"
11 #include "quiche/common/platform/api/quiche_logging.h"
12 #include "quiche/common/platform/api/quiche_test.h"
13
14 using ::testing::AssertionResult;
15
16 namespace http2 {
17 namespace test {
18 namespace {
19
20 const HpackEntryType kInvalidHeaderType = static_cast<HpackEntryType>(99);
21 const size_t kInvalidIndex = 99999999;
22
23 } // namespace
24
HpackEntryCollector()25 HpackEntryCollector::HpackEntryCollector() { Clear(); }
26
27 HpackEntryCollector::HpackEntryCollector(const HpackEntryCollector& other) =
28 default;
29
HpackEntryCollector(HpackEntryType type,size_t index_or_size)30 HpackEntryCollector::HpackEntryCollector(HpackEntryType type,
31 size_t index_or_size)
32 : header_type_(type), index_(index_or_size), started_(true), ended_(true) {}
HpackEntryCollector(HpackEntryType type,size_t index,bool value_huffman,const std::string & value)33 HpackEntryCollector::HpackEntryCollector(HpackEntryType type, size_t index,
34 bool value_huffman,
35 const std::string& value)
36 : header_type_(type),
37 index_(index),
38 value_(value, value_huffman),
39 started_(true),
40 ended_(true) {}
HpackEntryCollector(HpackEntryType type,bool name_huffman,const std::string & name,bool value_huffman,const std::string & value)41 HpackEntryCollector::HpackEntryCollector(HpackEntryType type, bool name_huffman,
42 const std::string& name,
43 bool value_huffman,
44 const std::string& value)
45 : header_type_(type),
46 index_(0),
47 name_(name, name_huffman),
48 value_(value, value_huffman),
49 started_(true),
50 ended_(true) {}
51
52 HpackEntryCollector::~HpackEntryCollector() = default;
53
OnIndexedHeader(size_t index)54 void HpackEntryCollector::OnIndexedHeader(size_t index) {
55 ASSERT_FALSE(started_);
56 ASSERT_TRUE(IsClear()) << ToString();
57 Init(HpackEntryType::kIndexedHeader, index);
58 ended_ = true;
59 }
OnStartLiteralHeader(HpackEntryType header_type,size_t maybe_name_index)60 void HpackEntryCollector::OnStartLiteralHeader(HpackEntryType header_type,
61 size_t maybe_name_index) {
62 ASSERT_FALSE(started_);
63 ASSERT_TRUE(IsClear()) << ToString();
64 Init(header_type, maybe_name_index);
65 }
OnNameStart(bool huffman_encoded,size_t len)66 void HpackEntryCollector::OnNameStart(bool huffman_encoded, size_t len) {
67 ASSERT_TRUE(started_);
68 ASSERT_FALSE(ended_);
69 ASSERT_FALSE(IsClear());
70 ASSERT_TRUE(LiteralNameExpected()) << ToString();
71 name_.OnStringStart(huffman_encoded, len);
72 }
OnNameData(const char * data,size_t len)73 void HpackEntryCollector::OnNameData(const char* data, size_t len) {
74 ASSERT_TRUE(started_);
75 ASSERT_FALSE(ended_);
76 ASSERT_TRUE(LiteralNameExpected()) << ToString();
77 ASSERT_TRUE(name_.IsInProgress());
78 name_.OnStringData(data, len);
79 }
OnNameEnd()80 void HpackEntryCollector::OnNameEnd() {
81 ASSERT_TRUE(started_);
82 ASSERT_FALSE(ended_);
83 ASSERT_TRUE(LiteralNameExpected()) << ToString();
84 ASSERT_TRUE(name_.IsInProgress());
85 name_.OnStringEnd();
86 }
OnValueStart(bool huffman_encoded,size_t len)87 void HpackEntryCollector::OnValueStart(bool huffman_encoded, size_t len) {
88 ASSERT_TRUE(started_);
89 ASSERT_FALSE(ended_);
90 if (LiteralNameExpected()) {
91 ASSERT_TRUE(name_.HasEnded());
92 }
93 ASSERT_TRUE(LiteralValueExpected()) << ToString();
94 ASSERT_TRUE(value_.IsClear()) << value_.ToString();
95 value_.OnStringStart(huffman_encoded, len);
96 }
OnValueData(const char * data,size_t len)97 void HpackEntryCollector::OnValueData(const char* data, size_t len) {
98 ASSERT_TRUE(started_);
99 ASSERT_FALSE(ended_);
100 ASSERT_TRUE(LiteralValueExpected()) << ToString();
101 ASSERT_TRUE(value_.IsInProgress());
102 value_.OnStringData(data, len);
103 }
OnValueEnd()104 void HpackEntryCollector::OnValueEnd() {
105 ASSERT_TRUE(started_);
106 ASSERT_FALSE(ended_);
107 ASSERT_TRUE(LiteralValueExpected()) << ToString();
108 ASSERT_TRUE(value_.IsInProgress());
109 value_.OnStringEnd();
110 ended_ = true;
111 }
OnDynamicTableSizeUpdate(size_t size)112 void HpackEntryCollector::OnDynamicTableSizeUpdate(size_t size) {
113 ASSERT_FALSE(started_);
114 ASSERT_TRUE(IsClear()) << ToString();
115 Init(HpackEntryType::kDynamicTableSizeUpdate, size);
116 ended_ = true;
117 }
118
Clear()119 void HpackEntryCollector::Clear() {
120 header_type_ = kInvalidHeaderType;
121 index_ = kInvalidIndex;
122 name_.Clear();
123 value_.Clear();
124 started_ = ended_ = false;
125 }
IsClear() const126 bool HpackEntryCollector::IsClear() const {
127 return header_type_ == kInvalidHeaderType && index_ == kInvalidIndex &&
128 name_.IsClear() && value_.IsClear() && !started_ && !ended_;
129 }
IsComplete() const130 bool HpackEntryCollector::IsComplete() const { return started_ && ended_; }
LiteralNameExpected() const131 bool HpackEntryCollector::LiteralNameExpected() const {
132 switch (header_type_) {
133 case HpackEntryType::kIndexedLiteralHeader:
134 case HpackEntryType::kUnindexedLiteralHeader:
135 case HpackEntryType::kNeverIndexedLiteralHeader:
136 return index_ == 0;
137 default:
138 return false;
139 }
140 }
LiteralValueExpected() const141 bool HpackEntryCollector::LiteralValueExpected() const {
142 switch (header_type_) {
143 case HpackEntryType::kIndexedLiteralHeader:
144 case HpackEntryType::kUnindexedLiteralHeader:
145 case HpackEntryType::kNeverIndexedLiteralHeader:
146 return true;
147 default:
148 return false;
149 }
150 }
ValidateIndexedHeader(size_t expected_index) const151 AssertionResult HpackEntryCollector::ValidateIndexedHeader(
152 size_t expected_index) const {
153 HTTP2_VERIFY_TRUE(started_);
154 HTTP2_VERIFY_TRUE(ended_);
155 HTTP2_VERIFY_EQ(HpackEntryType::kIndexedHeader, header_type_);
156 HTTP2_VERIFY_EQ(expected_index, index_);
157 return ::testing::AssertionSuccess();
158 }
ValidateLiteralValueHeader(HpackEntryType expected_type,size_t expected_index,bool expected_value_huffman,absl::string_view expected_value) const159 AssertionResult HpackEntryCollector::ValidateLiteralValueHeader(
160 HpackEntryType expected_type, size_t expected_index,
161 bool expected_value_huffman, absl::string_view expected_value) const {
162 HTTP2_VERIFY_TRUE(started_);
163 HTTP2_VERIFY_TRUE(ended_);
164 HTTP2_VERIFY_EQ(expected_type, header_type_);
165 HTTP2_VERIFY_NE(0u, expected_index);
166 HTTP2_VERIFY_EQ(expected_index, index_);
167 HTTP2_VERIFY_TRUE(name_.IsClear());
168 HTTP2_VERIFY_SUCCESS(
169 value_.Collected(expected_value, expected_value_huffman));
170 return ::testing::AssertionSuccess();
171 }
ValidateLiteralNameValueHeader(HpackEntryType expected_type,bool expected_name_huffman,absl::string_view expected_name,bool expected_value_huffman,absl::string_view expected_value) const172 AssertionResult HpackEntryCollector::ValidateLiteralNameValueHeader(
173 HpackEntryType expected_type, bool expected_name_huffman,
174 absl::string_view expected_name, bool expected_value_huffman,
175 absl::string_view expected_value) const {
176 HTTP2_VERIFY_TRUE(started_);
177 HTTP2_VERIFY_TRUE(ended_);
178 HTTP2_VERIFY_EQ(expected_type, header_type_);
179 HTTP2_VERIFY_EQ(0u, index_);
180 HTTP2_VERIFY_SUCCESS(name_.Collected(expected_name, expected_name_huffman));
181 HTTP2_VERIFY_SUCCESS(
182 value_.Collected(expected_value, expected_value_huffman));
183 return ::testing::AssertionSuccess();
184 }
ValidateDynamicTableSizeUpdate(size_t size) const185 AssertionResult HpackEntryCollector::ValidateDynamicTableSizeUpdate(
186 size_t size) const {
187 HTTP2_VERIFY_TRUE(started_);
188 HTTP2_VERIFY_TRUE(ended_);
189 HTTP2_VERIFY_EQ(HpackEntryType::kDynamicTableSizeUpdate, header_type_);
190 HTTP2_VERIFY_EQ(index_, size);
191 return ::testing::AssertionSuccess();
192 }
193
AppendToHpackBlockBuilder(HpackBlockBuilder * hbb) const194 void HpackEntryCollector::AppendToHpackBlockBuilder(
195 HpackBlockBuilder* hbb) const {
196 ASSERT_TRUE(started_ && ended_) << *this;
197 switch (header_type_) {
198 case HpackEntryType::kIndexedHeader:
199 hbb->AppendIndexedHeader(index_);
200 return;
201
202 case HpackEntryType::kDynamicTableSizeUpdate:
203 hbb->AppendDynamicTableSizeUpdate(index_);
204 return;
205
206 case HpackEntryType::kIndexedLiteralHeader:
207 case HpackEntryType::kUnindexedLiteralHeader:
208 case HpackEntryType::kNeverIndexedLiteralHeader:
209 ASSERT_TRUE(value_.HasEnded()) << *this;
210 if (index_ != 0) {
211 QUICHE_CHECK(name_.IsClear());
212 hbb->AppendNameIndexAndLiteralValue(header_type_, index_,
213 value_.huffman_encoded, value_.s);
214 } else {
215 QUICHE_CHECK(name_.HasEnded()) << *this;
216 hbb->AppendLiteralNameAndValue(header_type_, name_.huffman_encoded,
217 name_.s, value_.huffman_encoded,
218 value_.s);
219 }
220 return;
221
222 default:
223 ADD_FAILURE() << *this;
224 }
225 }
226
ToString() const227 std::string HpackEntryCollector::ToString() const {
228 std::string result("Type=");
229 switch (header_type_) {
230 case HpackEntryType::kIndexedHeader:
231 result += "IndexedHeader";
232 break;
233 case HpackEntryType::kDynamicTableSizeUpdate:
234 result += "DynamicTableSizeUpdate";
235 break;
236 case HpackEntryType::kIndexedLiteralHeader:
237 result += "IndexedLiteralHeader";
238 break;
239 case HpackEntryType::kUnindexedLiteralHeader:
240 result += "UnindexedLiteralHeader";
241 break;
242 case HpackEntryType::kNeverIndexedLiteralHeader:
243 result += "NeverIndexedLiteralHeader";
244 break;
245 default:
246 if (header_type_ == kInvalidHeaderType) {
247 result += "<unset>";
248 } else {
249 absl::StrAppend(&result, header_type_);
250 }
251 }
252 if (index_ != 0) {
253 absl::StrAppend(&result, " Index=", index_);
254 }
255 if (!name_.IsClear()) {
256 absl::StrAppend(&result, " Name", name_.ToString());
257 }
258 if (!value_.IsClear()) {
259 absl::StrAppend(&result, " Value", value_.ToString());
260 }
261 if (!started_) {
262 EXPECT_FALSE(ended_);
263 absl::StrAppend(&result, " !started");
264 } else if (!ended_) {
265 absl::StrAppend(&result, " !ended");
266 } else {
267 absl::StrAppend(&result, " Complete");
268 }
269 return result;
270 }
271
Init(HpackEntryType type,size_t maybe_index)272 void HpackEntryCollector::Init(HpackEntryType type, size_t maybe_index) {
273 ASSERT_TRUE(IsClear()) << ToString();
274 header_type_ = type;
275 index_ = maybe_index;
276 started_ = true;
277 }
278
operator ==(const HpackEntryCollector & a,const HpackEntryCollector & b)279 bool operator==(const HpackEntryCollector& a, const HpackEntryCollector& b) {
280 return a.name() == b.name() && a.value() == b.value() &&
281 a.index() == b.index() && a.header_type() == b.header_type() &&
282 a.started() == b.started() && a.ended() == b.ended();
283 }
operator !=(const HpackEntryCollector & a,const HpackEntryCollector & b)284 bool operator!=(const HpackEntryCollector& a, const HpackEntryCollector& b) {
285 return !(a == b);
286 }
287
operator <<(std::ostream & out,const HpackEntryCollector & v)288 std::ostream& operator<<(std::ostream& out, const HpackEntryCollector& v) {
289 return out << v.ToString();
290 }
291
292 } // namespace test
293 } // namespace http2
294