proxygen
QPACKCodecTests.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
10 #include <folly/Range.h>
11 #include <folly/io/Cursor.h>
12 #include <folly/io/IOBuf.h>
13 #include <glog/logging.h>
20 #include <vector>
21 
22 using namespace folly::io;
23 using namespace folly;
24 using namespace proxygen::compress;
25 using namespace proxygen::hpack;
26 using namespace proxygen;
27 using namespace std;
28 using namespace testing;
29 
30 namespace {
31 void headersEq(vector<Header>& headerVec, compress::HeaderPieceList& headers) {
32  size_t i = 0;
33  EXPECT_EQ(headerVec.size() * 2, headers.size());
34  for (auto& h: headerVec) {
35  string name = *h.name;
36  char *mutableName = (char *)name.data();
37  folly::toLowerAscii(mutableName, name.size());
38  EXPECT_EQ(name, headers[i++].str);
39  EXPECT_EQ(*h.value, headers[i++].str);
40  }
41 }
42 }
43 
44 class QPACKTests : public testing::Test {
45  public:
46 
47  protected:
48  void controlAck() {
49  auto ack = server.encodeTableStateSync();
50  EXPECT_EQ(client.decodeDecoderStream(std::move(ack)),
51  HPACK::DecodeError::NONE);
52  }
53 
54  void headerAck(uint64_t streamId) {
55  auto ack = server.encodeHeaderAck(streamId);
56  EXPECT_EQ(client.decodeDecoderStream(std::move(ack)),
57  HPACK::DecodeError::NONE);
58  }
59 
62 };
63 
64 TEST_F(QPACKTests, TestSimple) {
65  vector<Header> req = basicHeaders();
66  auto encodeResult = client.encode(req, 1);
67  ASSERT_NE(encodeResult.control.get(), nullptr);
68  EXPECT_EQ(server.decodeEncoderStream(std::move(encodeResult.control)),
69  HPACK::DecodeError::NONE);
71  auto length = encodeResult.stream->computeChainDataLength();
72  server.decodeStreaming(1, std::move(encodeResult.stream), length, &cb);
73  headerAck(1);
74  auto result = cb.getResult();
75  EXPECT_TRUE(!result.hasError());
76  headersEq(req, result->headers);
77 }
78 
79 TEST_F(QPACKTests, TestAbsoluteIndex) {
80  int flights = 10;
81  for (int i = 0; i < flights; i++) {
82  vector<vector<string>> headers;
83  for (int j = 0; j < 32; j++) {
84  int value = (i >> 1) * 32 + j; // duplicate the last flight
85  headers.emplace_back(
86  vector<string>({string("foomonkey"), folly::to<string>(value)}));
87  }
88  auto req = headersFromArray(headers);
89  auto encodeResult = client.encode(req, i + 1);
90  if (i % 2 == 1) {
91  EXPECT_EQ(encodeResult.control.get(), nullptr);
92  } else {
93  ASSERT_NE(encodeResult.control.get(), nullptr);
94  CHECK_EQ(server.decodeEncoderStream(std::move(encodeResult.control)),
95  HPACK::DecodeError::NONE);
96  }
98  auto length = encodeResult.stream->computeChainDataLength();
99  server.decodeStreaming(i + 1, std::move(encodeResult.stream), length, &cb);
100  headerAck(i + 1);
101  auto result = cb.getResult();
102  EXPECT_TRUE(!result.hasError());
103  headersEq(req, result->headers);
104  }
105 }
106 
107 TEST_F(QPACKTests, TestWithQueue) {
108  // Sends 10 flights of 4 requests each
109  // Each request contains two 'connection' headers, one with the current
110  // index, and current index - 8.
111  // Each flight is processed in the order 0, 3, 2, 1, unless an eviction
112  // happens on 2 or 3, in which case we force an blocking event.
113  vector<Header> req = basicHeaders();
114  vector<string> values;
115  int flights = 10;
116  for (auto i = 0; i < flights * 4; i++) {
117  values.push_back(folly::to<string>(i));
118  }
119  client.setEncoderHeaderTableSize(1024);
120  for (auto f = 0; f < flights; f++) {
121  vector<std::pair<unique_ptr<IOBuf>, TestStreamingCallback>> data;
122  list<unique_ptr<IOBuf>> controlFrames;
123  for (int i = 0; i < 4; i++) {
124  auto reqI = req;
125  for (int j = 0; j < 2; j++) {
126  reqI.emplace_back(HTTP_HEADER_CONNECTION, values[
127  std::max(f * 4 + i - j * 8, 0)]);
128  }
129  VLOG(4) << "Encoding req=" << f * 4 + i;
130  auto res = client.encode(reqI, f * 4 + i);
131  if (res.control && res.control->computeChainDataLength() > 0) {
132  controlFrames.emplace_back(std::move(res.control));
133  }
134  data.emplace_back(std::move(res.stream), TestStreamingCallback());
135  }
136 
137  std::vector<int> insertOrder{0, 3, 2, 1};
138  if (!controlFrames.empty()) {
139  auto control = std::move(controlFrames.front());
140  controlFrames.pop_front();
141  server.decodeEncoderStream(std::move(control));
142  }
143  for (auto i: insertOrder) {
144  auto& encodedReq = data[i].first;
145  auto len = encodedReq->computeChainDataLength();
146  server.decodeStreaming(i, std::move(encodedReq), len, &data[i].second);
147  }
148  while (!controlFrames.empty()) {
149  auto control = std::move(controlFrames.front());
150  controlFrames.pop_front();
151  server.decodeEncoderStream(std::move(control));
152  }
153  int i = 0;
154  for (auto& d: data) {
155  auto result = d.second.getResult();
156  EXPECT_TRUE(!result.hasError());
157  auto reqI = req;
158  for (int j = 0; j < 2; j++) {
159  reqI.emplace_back(HTTP_HEADER_CONNECTION,
160  values[std::max(f * 4 + i - j * 8, 0)]);
161  }
162  headersEq(reqI, result->headers);
163  headerAck(f * 4 + i);
164  i++;
165  }
166  VLOG(4) << "getHolBlockCount=" << server.getHolBlockCount();
167  }
168  // Skipping redundant table adds reduces the HOL block count
169  EXPECT_EQ(server.getHolBlockCount(), 30);
170 
171 }
172 
173 TEST_F(QPACKTests, HeaderCodecStats) {
174  vector<vector<string>> headers = {
175  {"Content-Length", "80"},
176  {"Content-Encoding", "gzip"},
177  {"X-FB-Debug", "eirtijvdgtccffkutnbttcgbfieghgev"}
178  };
179  vector<Header> resp = headersFromArray(headers);
180 
181  TestHeaderCodecStats stats(HeaderCodec::Type::QPACK);
182  // encode
183  server.setStats(&stats);
184  auto encResult = server.encode(resp, 1);
185  EXPECT_EQ(stats.encodes, 1);
186  EXPECT_EQ(stats.decodes, 0);
187  EXPECT_EQ(stats.errors, 0);
188  EXPECT_TRUE(stats.encodedBytesCompr > 0);
189  EXPECT_TRUE(stats.encodedBytesUncompr > 0);
190  EXPECT_EQ(stats.decodedBytesCompr, 0);
191  EXPECT_EQ(stats.decodedBytesUncompr, 0);
192  server.setStats(nullptr);
193 
194  // decode
195  stats.reset();
196  client.setStats(&stats);
198  auto len = encResult.stream->computeChainDataLength();
199  client.decodeEncoderStream(std::move(encResult.control));
200  client.decodeStreaming(1, std::move(encResult.stream), len, &cb);
201  auto result = cb.getResult();
202  EXPECT_TRUE(!result.hasError());
203  auto& decoded = result->headers;
204  CHECK_EQ(decoded.size(), 3 * 2);
205  EXPECT_EQ(stats.decodes, 1);
206  EXPECT_EQ(stats.encodes, 0);
207  EXPECT_GT(stats.decodedBytesCompr, 0);
208  EXPECT_GT(stats.decodedBytesUncompr, 0);
209  EXPECT_EQ(stats.encodedBytesCompr, 0);
210  EXPECT_EQ(stats.encodedBytesUncompr, 0);
211  client.setStats(nullptr);
212 }
*than *hazptr_holder h
Definition: Hazptr.h:116
auto f
LogLevel max
Definition: LogLevel.cpp:31
void headerAck(uint64_t streamId)
vector< compress::Header > basicHeaders()
Definition: TestUtil.cpp:116
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
vector< compress::Header > headersFromArray(vector< vector< string >> &a)
Definition: TestUtil.cpp:108
STL namespace.
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
const char * name
Definition: http_parser.c:437
std::deque< HeaderPiece > HeaderPieceList
Definition: HeaderPiece.h:59
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
TEST_F(AsyncSSLSocketWriteTest, write_coalescing1)
QPACKCodec client
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
void toLowerAscii(char *str, size_t length)
Definition: String.cpp:601
const char * string
Definition: Conv.cpp:212
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
#define ASSERT_NE(val1, val2)
Definition: gtest.h:1960
QPACKCodec server
std::vector< int > values(1'000)
folly::Expected< HeaderDecodeResult, HPACK::DecodeError > getResult()
#define EXPECT_GT(val1, val2)
Definition: gtest.h:1934