proxygen
QPACKContextTests.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/Conv.h>
11 #include <glog/logging.h>
13 #include <memory>
18 
19 using namespace folly;
20 using namespace proxygen;
21 using namespace std;
22 using namespace testing;
23 
24 namespace {
25 void verifyDecode(QPACKDecoder& decoder, QPACKEncoder::EncodeResult result,
26  const std::vector<HPACKHeader>& expectedHeaders,
27  HPACK::DecodeError expectedError = HPACK::DecodeError::NONE) {
28  auto cb = std::make_shared<TestStreamingCallback>();
29  if (result.control) {
31  HPACK::DecodeError::NONE);
32  }
33  auto length = result.stream->computeChainDataLength();
34  if (expectedError == HPACK::DecodeError::NONE) {
35  cb->headersCompleteCb =
36  [&expectedHeaders, cb] () mutable {
37  std::vector<HPACKHeader> test;
38  for (size_t i = 0; i < cb->headers.size(); i += 2) {
39  test.emplace_back(cb->headers[i].str, cb->headers[i + 1].str);
40  }
41  EXPECT_EQ(cb->error, HPACK::DecodeError::NONE);
42  EXPECT_EQ(test, expectedHeaders);
43  cb.reset();
44  };
45  }
46  // streamID only matters for cancellation
47  decoder.decodeStreaming(0, std::move(result.stream), length, cb.get());
48  EXPECT_EQ(cb->error, expectedError);
49 }
50 
51 bool stringInOutput(IOBuf* stream, const std::string& expected) {
52  stream->coalesce();
53  return memmem(stream->data(), stream->length(),
54  expected.data(), expected.length());
55 }
56 
57 HPACK::DecodeError headerAck(QPACKDecoder& decoder, QPACKEncoder& encoder,
58  uint64_t streamId) {
59  return encoder.decodeDecoderStream(decoder.encodeHeaderAck(streamId));
60 }
61 
62 HPACK::DecodeError cancelStream(QPACKDecoder& decoder, QPACKEncoder& encoder,
63  uint64_t streamId) {
64  return encoder.decodeDecoderStream(decoder.encodeCancelStream(streamId));
65 }
66 }
67 
68 TEST(QPACKContextTests, StaticOnly) {
69  QPACKEncoder encoder(true, 128);
70  QPACKDecoder decoder(128);
71  vector<HPACKHeader> req;
72  req.push_back(HPACKHeader("accept-encoding", "gzip, deflate"));
73  auto result = encoder.encode(req, 10, 1);
74  EXPECT_EQ(result.stream->computeChainDataLength(), 3);
75  EXPECT_EQ(result.stream->data()[0], 0);
76  EXPECT_EQ(result.stream->data()[1], 0);
77  verifyDecode(decoder, std::move(result), req);
78  // nothing to ack
79  EXPECT_EQ(decoder.encodeTableStateSync(), nullptr);
80 }
81 
82 TEST(QPACKContextTests, Indexed) {
83  QPACKEncoder encoder(true, 128);
84  QPACKDecoder decoder(128);
85  vector<HPACKHeader> req;
86  // Encodes "Post Base"
87  req.push_back(HPACKHeader("Blarf", "Blah"));
88  auto result = encoder.encode(req, 10, 1);
89  verifyDecode(decoder, std::move(result), req);
90  // Encodes "Normal"
91  result = encoder.encode(req, 10, 2);
92  verifyDecode(decoder, std::move(result), req);
93 }
94 
95 TEST(QPACKContextTests, NameIndexed) {
96  QPACKEncoder encoder(true, 64);
97  QPACKDecoder decoder(64);
98  vector<HPACKHeader> req;
99 
100  // Encodes a "Post Base" name index since the table is full
101  req.push_back(HPACKHeader("Blarf", "Blah"));
102  req.push_back(HPACKHeader("Blarf", "Blerg"));
103  auto result = encoder.encode(req, 10, 1);
104  verifyDecode(decoder, std::move(result), req);
105  // Encodes "Normal" name index
106  result = encoder.encode(req, 10, 2);
107  verifyDecode(decoder, std::move(result), req);
108 }
109 
110 TEST(QPACKContextTests, NameIndexedInsert) {
111  QPACKEncoder encoder(false, 128);
112  QPACKDecoder decoder(128);
113  vector<HPACKHeader> req;
114 
115  req.push_back(HPACKHeader("Blarf", "Blah"));
116  auto result = encoder.encode(req, 10, 1);
117  verifyDecode(decoder, std::move(result), req);
118 
119  // Encodes an insert using a dynamic name reference
120  req.push_back(HPACKHeader("Blarf", "Blerg"));
121  result = encoder.encode(req, 10, 2);
122  EXPECT_FALSE(stringInOutput(result.control.get(), "blarf"));
123  verifyDecode(decoder, std::move(result), req);
124 }
125 
126 TEST(QPACKContextTests, PostBaseNameIndexedLiteral) {
127  QPACKEncoder encoder(false, 360);
128  QPACKDecoder decoder(360);
129  vector<HPACKHeader> req;
130 
131  encoder.setMaxVulnerable(1);
132  // Fills the table with exacty minFree (48) empty
133  for (auto i = 0; i < 8; i++) {
134  req.push_back(HPACKHeader(folly::to<std::string>("Blarf", i), "0"));
135  }
136  // Too big to put in the table without evicting, perfect
137  // for Post-Base Name-Indexed literal with idx=7
138  req.push_back(HPACKHeader("Blarf7", "blergblergblerg"));
139  auto result = encoder.encode(req, 10, 1);
140  EXPECT_EQ(result.stream->computeChainDataLength(),
141  2 /*prefix*/ + 8 /*pb indexed*/ + 2 /*name idx len*/ +
142  1 /*val len*/ + 15 /* value */);
143  verifyDecode(decoder, std::move(result), req);
144 }
145 
146 
147 TEST(QPACKContextTests, Unacknowledged) {
148  QPACKEncoder encoder(true, 128);
149  QPACKDecoder decoder(128);
150  // Disallow unack'd headers
151  encoder.setMaxVulnerable(0);
152  vector<HPACKHeader> req;
153  req.push_back(HPACKHeader("Blarf", "Blah"));
154  auto result = encoder.encode(req, 10, 1);
155 
156  // Stream will encode a literal: prefix(2) + <more than 1>
157  EXPECT_GT(result.stream->computeChainDataLength(), 3);
158  verifyDecode(decoder, std::move(result), req);
159 
160  req.push_back(HPACKHeader("Blarf", "Blerg"));
161  result = encoder.encode(req, 10, 2);
162  EXPECT_GT(result.stream->computeChainDataLength(), 4);
163  verifyDecode(decoder, std::move(result), req);
164 }
165 
166 TEST(QPACKContextTests, TestDraining) {
167  QPACKEncoder encoder(false, 128);
168  vector<HPACKHeader> req;
169  req.push_back(HPACKHeader("accept-encoding", "gzip,deflate"));
170  auto result = encoder.encode(req, 0, 1);
171 
172  // This will result in the first header being drained in the middle
173  // of encoding the new control channel, and force a literal.
174  req.clear();
175  req.push_back(HPACKHeader("accept-encoding", "sdch,gzip"));
176  req.push_back(HPACKHeader("accept-encoding", "gzip,deflate"));
177  result = encoder.encode(req, 0, 2);
178  EXPECT_GT(result.stream->computeChainDataLength(), 4);
179  EXPECT_TRUE(stringInOutput(result.stream.get(), "gzip,deflate"));
180 }
181 
182 TEST(QPACKContextTests, TestDuplicate) {
183  QPACKEncoder encoder(false, 200);
184  QPACKDecoder decoder(200);
185  vector<HPACKHeader> req;
186  // 5 inserts and one literal
187  for (auto i = 0; i < 6; i++) {
188  req.emplace_back(folly::to<string>('a' + i), folly::to<string>(i));
189  }
190  // a=0 should now be draining
191  auto result = encoder.encode(req, 0, 1);
192  verifyDecode(decoder, std::move(result), req);
193  EXPECT_EQ(encoder.onTableStateSync(5), HPACK::DecodeError::NONE);
194  EXPECT_EQ(headerAck(decoder, encoder, 1), HPACK::DecodeError::NONE);
195  req.erase(req.begin() + 1, req.end());
196  result = encoder.encode(req, 0, 2);
197  // Control contains one-byte duplicate instruction, stream prefix + 1
198  EXPECT_EQ(result.control->computeChainDataLength(), 1);
199  EXPECT_EQ(result.stream->computeChainDataLength(), 3);
200  verifyDecode(decoder, std::move(result), req);
201 }
202 
203 TEST(QPACKContextTests, TestTableSizeUpdate) {
204  QPACKEncoder encoder(false, 100);
205  QPACKDecoder decoder(100);
206  vector<HPACKHeader> req;
207  req.emplace_back("Blarf", "Blah");
208  req.emplace_back("Blarf", "Blerg");
209  auto result = encoder.encode(req, 0, 1);
210  verifyDecode(decoder, std::move(result), req);
211  EXPECT_EQ(encoder.onTableStateSync(2), HPACK::DecodeError::NONE);
212  EXPECT_EQ(headerAck(decoder, encoder, 1), HPACK::DecodeError::NONE);
213  encoder.setHeaderTableSize(64); // This will evict the oldest header
214  EXPECT_EQ(encoder.getHeadersStored(), 1);
215  result = encoder.encode(req, 0, 2);
216  verifyDecode(decoder, std::move(result), req);
217  EXPECT_EQ(decoder.getHeadersStored(), 1);
218  EXPECT_EQ(headerAck(decoder, encoder, 2), HPACK::DecodeError::NONE);
219 
220  encoder.setHeaderTableSize(100);
221  result = encoder.encode(req, 0, 3);
222  EXPECT_EQ(encoder.getHeadersStored(), 2);
223  verifyDecode(decoder, std::move(result), req);
224  EXPECT_EQ(decoder.getHeadersStored(), 2);
225 }
226 
227 
228 TEST(QPACKContextTests, TestAcks) {
229  QPACKEncoder encoder(false, 100);
230  QPACKDecoder decoder(100);
231  encoder.setMaxVulnerable(1);
232  EXPECT_EQ(encoder.onTableStateSync(1), HPACK::DecodeError::INVALID_ACK);
233  EXPECT_EQ(headerAck(decoder, encoder, 1), HPACK::DecodeError::INVALID_ACK);
234 
235  vector<HPACKHeader> req;
236  req.emplace_back("Blarf", "BlahBlahBlah");
237  auto result = encoder.encode(req, 0, 1);
238  verifyDecode(decoder, std::move(result), req);
239  req.clear();
240  req.emplace_back("accept-encoding", "gzip, deflate");
241  result = encoder.encode(req, 0, 1);
242  verifyDecode(decoder, std::move(result), req);
243  req.clear();
244  req.emplace_back("Blarf", "BlahBlahBlah");
245  result = encoder.encode(req, 0, 1);
246  verifyDecode(decoder, std::move(result), req);
247 
248  // Blarf: Blah is unacknowledged and maxVulnerable is 1 -> literal
249  result = encoder.encode(req, 0, 2);
250  EXPECT_EQ(result.control, nullptr);
251  EXPECT_TRUE(stringInOutput(result.stream.get(), "blarf"));
252  verifyDecode(decoder, std::move(result), req);
253 
254  // Table is full and Blarf: BlahBlahBlah cannot be evicted -> literal
255  req.clear();
256  req.emplace_back("Foo", "BlahBlahBlahBlah!");
257  result = encoder.encode(req, 0, 3);
258  EXPECT_EQ(result.control, nullptr);
259  EXPECT_TRUE(stringInOutput(result.stream.get(), "foo"));
260  verifyDecode(decoder, std::move(result), req);
261  EXPECT_EQ(headerAck(decoder, encoder, 3), HPACK::DecodeError::NONE);
262 
263  // Should remove all encoder state. Blarf: BlahBlahBlah can now be evicted
264  // and a new vulnerable reference can be made.
265  EXPECT_EQ(headerAck(decoder, encoder, 2), HPACK::DecodeError::NONE);
266  EXPECT_EQ(cancelStream(decoder, encoder, 1), HPACK::DecodeError::NONE);
267  EXPECT_EQ(encoder.onTableStateSync(1), HPACK::DecodeError::NONE);
268 
269  result = encoder.encode(req, 0, 2);
270  // Encodes an insert
271  EXPECT_GT(result.control->computeChainDataLength(), 1);
272  EXPECT_EQ(result.stream->computeChainDataLength(), 3);
273  EXPECT_FALSE(stringInOutput(result.stream.get(), "foo"));
274  verifyDecode(decoder, std::move(result), req);
275 }
276 
277 TEST(QPACKContextTests, TestImplicitAcks) {
278  QPACKEncoder encoder(false, 1024);
279  QPACKDecoder decoder(1024);
280  encoder.setMaxVulnerable(2);
281 
282  vector<HPACKHeader> req;
283  req.emplace_back("Blarf", "Blah");
284  auto result = encoder.encode(req, 0, 1);
285  verifyDecode(decoder, std::move(result), req);
286  req.emplace_back("Foo", "Blah");
287  result = encoder.encode(req, 0, 2);
288  verifyDecode(decoder, std::move(result), req);
289  EXPECT_EQ(encoder.onHeaderAck(2, false), HPACK::DecodeError::NONE);
290  // both headers are now acknowledged, 1 unacked header allowed
291  req.clear();
292  req.emplace_back("Bar", "Binky");
293  result = encoder.encode(req, 0, 3);
294 
295  // No unacked headers allowed
296  req.emplace_back("Blarf", "Blah");
297  req.emplace_back("Foo", "Blah");
298  result = encoder.encode(req, 0, 4);
299  EXPECT_FALSE(stringInOutput(result.stream.get(), "Blah"));
300  verifyDecode(decoder, std::move(result), req);
301 
302  // cancel
303  EXPECT_EQ(encoder.onHeaderAck(2, true), HPACK::DecodeError::NONE);
304  EXPECT_EQ(encoder.onHeaderAck(4, true), HPACK::DecodeError::NONE);
305 }
306 
307 TEST(QPACKContextTests, TestDecodeQueue) {
308  QPACKEncoder encoder(false, 64);
309  QPACKDecoder decoder(64);
310 
311  vector<HPACKHeader> req1;
312  req1.emplace_back("Blarf", "Blah");
313  auto result1 = encoder.encode(req1, 0, 1);
314 
315  vector<HPACKHeader> req2;
316  req2.emplace_back("Blarf", "Blerg");
317  auto result2 = encoder.encode(req2, 0, 2);
318  verifyDecode(decoder, std::move(result2), req2);
319  verifyDecode(decoder, std::move(result1), req1);
320 }
321 
322 TEST(QPACKContextTests, TestDecodeQueueDelete) {
323  // This test deletes the decoder from a callback while there are items in
324  // the queue
325  QPACKEncoder encoder(true, 100);
326  auto decoder = std::make_unique<QPACKDecoder>(100);
327 
328  vector<HPACKHeader> req1;
329  req1.emplace_back("Blarf", "Blah");
330  auto result1 = encoder.encode(req1, 0, 1);
331 
332  vector<HPACKHeader> req2;
333  req2.emplace_back("Blarf", "Blerg");
334  auto result2 = encoder.encode(req2, 0, 2);
335 
336 
337  // Decode #1, no control stream, queued
338  auto cb1 = std::make_unique<TestStreamingCallback>();
339  auto rawCb1 = cb1.get();
340  auto rawDecoder = decoder.get();
341  cb1->headersCompleteCb = [decoder=std::move(decoder)] () mutable {
342  // Delete decoder from callback
343  decoder.reset();
344  };
345  auto length = result1.stream->computeChainDataLength();
346  rawDecoder->decodeStreaming(1, std::move(result1.stream), length, rawCb1);
347 
348  // Decode #2, no control stream, queued
349  auto cb2 = std::make_unique<TestStreamingCallback>();
350  length = result2.stream->computeChainDataLength();
351  rawDecoder->decodeStreaming(2, std::move(result2.stream), length, cb2.get());
352 
353  // Decode control stream #1, will unblock 1 and delete decoder
354  EXPECT_EQ(rawDecoder->decodeEncoderStream(std::move(result1.control)),
355  HPACK::DecodeError::NONE);
356 
357  // cb2 doesn't execute because the decoder was destroyed from cb1
358  EXPECT_EQ(cb2->error, HPACK::DecodeError::NONE);
359  EXPECT_EQ(cb2->headers.size(), 0);
360 }
361 
362 TEST(QPACKContextTests, TestDecodeMaxUncompressed) {
363  QPACKEncoder encoder(false, 64);
364  QPACKDecoder decoder(64);
365  decoder.setMaxUncompressed(5);
366 
367  vector<HPACKHeader> req;
368  req.emplace_back("Blarf", "Blah");
369  auto result = encoder.encode(req, 0, 1);
370  verifyDecode(decoder, std::move(result), req,
371  HPACK::DecodeError::HEADERS_TOO_LARGE);
372 }
373 
374 TEST(QPACKContextTests, TestDecoderStreamChunked) {
375  QPACKEncoder encoder(false, 5000);
376  QPACKDecoder decoder(5000);
377 
378  vector<HPACKHeader> req;
379  for (auto i = 0; i < 128; i++) {
380  req.emplace_back("a", folly::to<string>(i));
381  }
382  auto result = encoder.encode(req, 0, 1);
384  HPACK::DecodeError::NONE);
385  auto ack = decoder.encodeTableStateSync();
386  EXPECT_EQ(ack->computeChainDataLength(), 2);
387  auto ackPart = ack->clone();
388  ackPart->trimEnd(1);
389  ack->trimStart(1);
390  EXPECT_EQ(encoder.decodeDecoderStream(std::move(ackPart)),
391  HPACK::DecodeError::NONE);
393  HPACK::DecodeError::NONE);
394  EXPECT_FALSE(encoder.getTable().isVulnerable(128));
395  EXPECT_TRUE(encoder.getTable().isVulnerable(129));
396 }
397 
398 TEST(QPACKContextTests, TestDecodePartialControl) {
399  QPACKEncoder encoder(false, 1000);
400  QPACKDecoder decoder(1000);
401 
402  vector<HPACKHeader> req;
403  req.emplace_back("abcdeabcdeabcdeabcdeabcdeabcdeabcde",
404  "vwxyzvwxyzvwxyzvwxyzvwxyzvwxyzvwxyz");
405  auto result = encoder.encode(req, 0, 1);
406  folly::io::Cursor c(result.control.get());
407  while (!c.isAtEnd()) {
408  std::unique_ptr<folly::IOBuf> buf;
409  c.clone(buf, 1);
411  HPACK::DecodeError::NONE);
412  }
413  EXPECT_EQ(decoder.getHeadersStored(), 1);
414  EXPECT_EQ(decoder.getHeader(false, 1, 1, false), req[0]);
415 }
416 
417 void checkQError(QPACKDecoder& decoder, std::unique_ptr<IOBuf> buf,
418  const HPACK::DecodeError err) {
419  auto cb = std::make_unique<TestStreamingCallback>();
420  auto len = buf->computeChainDataLength();
421  // streamID only matters for cancellation
422  decoder.decodeStreaming(0, std::move(buf), len, cb.get());
423  EXPECT_EQ(cb->error, err);
424 }
425 
426 TEST(QPACKContextTests, DecodeErrors) {
427  QPACKDecoder decoder(128);
428  unique_ptr<IOBuf> buf = IOBuf::create(128);
429 
430  // Largest ref invalid
431  buf->writableData()[0] = 0xFF;
432  buf->append(1);
433  checkQError(decoder, buf->clone(), HPACK::DecodeError::BUFFER_UNDERFLOW);
434 
435  // Base delta missing
436  buf->writableData()[0] = 0x01;
437  checkQError(decoder, buf->clone(), HPACK::DecodeError::BUFFER_UNDERFLOW);
438 
439  // Base delta invalid
440  buf->writableData()[1] = 0xFF;
441  buf->append(1);
442  checkQError(decoder, buf->clone(), HPACK::DecodeError::BUFFER_UNDERFLOW);
443 
444  // Base delta too negative
445  buf->writableData()[0] = 0x01;
446  buf->writableData()[1] = 0x82;
447  checkQError(decoder, buf->clone(), HPACK::DecodeError::INVALID_INDEX);
448 
449  // Exceeds blocking max
450  decoder.setMaxBlocking(0);
451  buf->writableData()[0] = 0x01;
452  buf->writableData()[1] = 0x00;
453  checkQError(decoder, buf->clone(), HPACK::DecodeError::TOO_MANY_BLOCKING);
454 
455  // valid prefix
456  buf->writableData()[0] = 0x00;
457  buf->writableData()[1] = 0x00;
458 
459  // Literal bad name index
460  buf->writableData()[2] = 0x4F;
461  buf->append(1);
462  checkQError(decoder, buf->clone(), HPACK::DecodeError::BUFFER_UNDERFLOW);
463 
464  // Literal invalid name index
465  buf->writableData()[2] = 0x41;
466  checkQError(decoder, buf->clone(), HPACK::DecodeError::INVALID_INDEX);
467 
468  // Literal bad name length
469  buf->writableData()[2] = 0x27;
470  checkQError(decoder, buf->clone(), HPACK::DecodeError::BUFFER_UNDERFLOW);
471 
472  // Literal invalid value length
473  buf->writableData()[2] = 0x51;
474  buf->writableData()[3] = 0xFF;
475  buf->append(1);
476  checkQError(decoder, buf->clone(), HPACK::DecodeError::BUFFER_UNDERFLOW);
477 
478  buf->trimEnd(1);
479  // Bad Index
480  buf->writableData()[2] = 0xBF;
481  checkQError(decoder, buf->clone(), HPACK::DecodeError::BUFFER_UNDERFLOW);
482 
483  // Zero static index
484  buf->writableData()[2] = 0xC0;
485  checkQError(decoder, buf->clone(), HPACK::DecodeError::INVALID_INDEX);
486 
487  // Invalid static index
488  buf->writableData()[2] = 0xFE;
489  checkQError(decoder, buf->clone(), HPACK::DecodeError::INVALID_INDEX);
490 
491  // No error after previous error
492  buf->writableData()[0] = 0xC1;
493  buf->writableData()[1] = 0x01;
494  buf->writableData()[2] = 0x41;
495  EXPECT_EQ(decoder.decodeEncoderStream(buf->clone()),
496  HPACK::DecodeError::NONE);
497 
498  // Control decode error
499  QPACKDecoder decoder2(64);
500  buf->writableData()[0] = 0x01; // duplicate dynamic index 1
501  buf->trimEnd(2);
502  EXPECT_EQ(decoder2.decodeEncoderStream(buf->clone()),
503  HPACK::DecodeError::INVALID_INDEX);
504 
505  QPACKEncoder encoder(true, 128);
506  buf->writableData()[0] = 0xFF;
507  buf->writableData()[1] = 0x80;
508  buf->writableData()[2] = 0xFF;
509  buf->writableData()[3] = 0xFF;
510  buf->writableData()[4] = 0xFF;
511  buf->writableData()[5] = 0xFF;
512  buf->writableData()[6] = 0xFF;
513  buf->writableData()[7] = 0xFF;
514  buf->writableData()[8] = 0xFF;
515  buf->writableData()[9] = 0xFF;
516  buf->writableData()[10] = 0xFF;
517  buf->writableData()[11] = 0x01;
518  buf->append(11);
519  // Bad header ack
520  EXPECT_EQ(encoder.decodeDecoderStream(buf->clone()),
521  HPACK::DecodeError::INTEGER_OVERFLOW);
522 
523  // Bad cancel
524  buf->writableData()[0] = 0x7F;
525  EXPECT_EQ(encoder.decodeDecoderStream(buf->clone()),
526  HPACK::DecodeError::INTEGER_OVERFLOW);
527 
528  // Bad table state sync
529  buf->writableData()[0] = 0x3F;
530  EXPECT_EQ(encoder.decodeDecoderStream(buf->clone()),
531  HPACK::DecodeError::INTEGER_OVERFLOW);
532 }
533 
534 TEST(QPACKContextTests, TestEvictedNameReference) {
535  QPACKEncoder encoder(false, 109);
536  QPACKDecoder decoder(109);
537  encoder.setMaxVulnerable(0);
538  vector<HPACKHeader> req;
539  req.push_back(HPACKHeader("x-accept-encoding", "foobarfoobar"));
540  auto result = encoder.encode(req, 0, 1);
541  decoder.decodeEncoderStream(std::move(result.control));
542  decoder.decodeStreaming(1, result.stream->clone(),
543  result.stream->computeChainDataLength(), nullptr);
544  encoder.onTableStateSync(1);
545  req.clear();
546  req.push_back(HPACKHeader("x-accept-encoding", "barfoobarfoo"));
547  result = encoder.encode(req, 0, 2);
548  EXPECT_TRUE(stringInOutput(result.stream.get(), "x-accept-encoding"));
550  decoder.decodeEncoderStream(std::move(result.control));
551  decoder.decodeStreaming(2, result.stream->clone(),
552  result.stream->computeChainDataLength(), &cb);
553  EXPECT_FALSE(cb.hasError());
554 }
void setMaxUncompressed(uint64_t maxUncompressed)
std::unique_ptr< folly::IOBuf > encodeTableStateSync()
HPACK::DecodeError decodeEncoderStream(std::unique_ptr< folly::IOBuf > buf)
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
void setMaxVulnerable(uint32_t maxVulnerable)
Definition: QPACKEncoder.h:61
const QPACKHeaderTable & getTable() const
Definition: QPACKContext.h:29
ByteRange coalesce()
Definition: IOBuf.h:1095
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
static uint64_t test(std::string name, bool fc_, bool dedicated_, bool tc_, bool syncops_, uint64_t base)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
STL namespace.
const uint8_t * data() const
Definition: IOBuf.h:499
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
HPACK::DecodeError onHeaderAck(uint64_t streamId, bool all)
std::unique_ptr< IOBuf > clone() const
Definition: IOBuf.cpp:527
bool isVulnerable(uint32_t absIndex) const
HPACK::DecodeError decodeDecoderStream(std::unique_ptr< folly::IOBuf > buf)
void setHeaderTableSize(uint32_t size)
Definition: QPACKEncoder.h:57
EncodeResult encode(const std::vector< HPACKHeader > &headers, uint32_t headroom, uint64_t streamId)
const HPACKHeader & getHeader(bool isStatic, uint32_t index, uint32_t base, bool aboveBase)
void decodeStreaming(uint64_t streamId, std::unique_ptr< folly::IOBuf > block, uint32_t totalBytes, HPACK::StreamingCallback *streamingCb)
uint8_t * writableData()
Definition: IOBuf.h:509
std::size_t length() const
Definition: IOBuf.h:533
uint32_t getHeadersStored() const
Definition: QPACKContext.h:41
std::size_t computeChainDataLength() const
Definition: IOBuf.cpp:501
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
void setMaxBlocking(uint32_t maxBlocking)
Definition: QPACKDecoder.h:54
const char * string
Definition: Conv.cpp:212
HPACK::DecodeError onTableStateSync(uint32_t inserts)
std::unique_ptr< folly::IOBuf > encodeHeaderAck(uint64_t streamId) const
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
void trimEnd(std::size_t amount)
Definition: IOBuf.h:718
char c
TEST(SequencedExecutor, CPUThreadPoolExecutor)
std::unique_ptr< folly::IOBuf > encodeCancelStream(uint64_t streamId)
void checkQError(QPACKDecoder &decoder, std::unique_ptr< IOBuf > buf, const HPACK::DecodeError err)
void append(std::size_t amount)
Definition: IOBuf.h:689
#define EXPECT_GT(val1, val2)
Definition: gtest.h:1934