xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/test_tools/hpack_entry_collector.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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