proxygen
HPACKBufferTests.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-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/io/Cursor.h>
11 #include <folly/io/IOBuf.h>
13 #include <memory>
16 
17 using namespace folly::io;
18 using namespace folly;
19 using namespace proxygen;
20 using namespace std;
21 using namespace testing;
23 
24 namespace {
25 const uint32_t kMaxLiteralSize = 1 << 17;
26 }
27 
29  public:
30  /*
31  * most of the tests need a tiny slice of data, so we're setting up
32  * a queue with one IOBuf of 512 bytes in it
33  */
34  HPACKBufferTests() : encoder_(512),
35  decoder_(cursor_, 0, kMaxLiteralSize) {
36  }
37 
38  protected:
39  // extracts the data from the encoder and setup pointers to it
40  void releaseData() {
41  releaseData(encoder_);
42  }
43 
44  void releaseData(HPACKEncodeBuffer& encoder) {
45  buf_ = encoder.release();
46  if (buf_) {
47  data_ = buf_->data();
48  }
49  }
50 
51  void resetDecoder() {
52  resetDecoder(buf_.get());
53  }
54 
55  void resetDecoder(IOBuf* buf) {
56  cursor_.reset(buf);
57  decoder_.reset(cursor_);
58  }
59 
60  Cursor cursor_{nullptr};
63  std::unique_ptr<IOBuf> buf_{nullptr};
64  const uint8_t* data_{nullptr};
65 };
66 
67 TEST_F(HPACKBufferTests, EncodeInteger) {
68  // all these fit in one byte
69  EXPECT_EQ(encoder_.encodeInteger(7, 192, 6), 1);
70  // this one fits perfectly, but needs an additional 0 byte
71  EXPECT_EQ(encoder_.encodeInteger(7, 192, 3), 2);
72  EXPECT_EQ(encoder_.encodeInteger(255, 0, 8), 2);
73  releaseData();
74  EXPECT_EQ(buf_->length(), 5);
75  EXPECT_EQ(data_[0], 199); // 11000111
76  EXPECT_EQ(data_[1], 199); // 11000111
77  EXPECT_EQ(data_[2], 0);
78  EXPECT_EQ(data_[3], 255); // 11111111
79  EXPECT_EQ(data_[4], 0);
80 
81  // multiple byte span
82  EXPECT_EQ(encoder_.encodeInteger(7, 192, 2), 2);
83  releaseData();
84  EXPECT_EQ(buf_->length(), 2);
85  EXPECT_EQ(data_[0], 195); // 11000011
86  EXPECT_EQ(data_[1], 4); // 00000100
87 
88  // the one from the spec - 1337
89  EXPECT_EQ(encoder_.encodeInteger(1337, 0, 5), 3);
90  releaseData();
91  EXPECT_EQ(buf_->length(), 3);
92  EXPECT_EQ(data_[0], 31); // 00011111
93  EXPECT_EQ(data_[1], 154); // 10011010
94  EXPECT_EQ(data_[2], 10); // 00001010
95 }
96 
97 TEST_F(HPACKBufferTests, EncodePlainLiteral) {
98  string literal("accept-encoding");
99  EXPECT_EQ(encoder_.encodeLiteral(literal), 16);
100  releaseData();
101  EXPECT_EQ(buf_->length(), 16);
102  EXPECT_EQ(data_[0], 15);
103  for (size_t i = 0; i < literal.size(); i++) {
104  EXPECT_EQ(data_[i + 1], literal[i]);
105  }
106 }
107 
108 TEST_F(HPACKBufferTests, EncodePlainLiteralN) {
109  string literal("accept-encodin"); // len=14
110  // length must fit in 4 bits, with room for 3 bit instruction
111  EXPECT_EQ(encoder_.encodeLiteral(0xE0, 4, literal), 15);
112  releaseData();
113  EXPECT_EQ(buf_->length(), 15);
114  EXPECT_EQ(data_[0], 0xE0 | 14);
115  for (size_t i = 0; i < literal.size(); i++) {
116  EXPECT_EQ(data_[i + 1], literal[i]);
117  }
118 }
119 
120 TEST_F(HPACKBufferTests, EncodeHuffmanLiteral) {
121  string accept("accept-encoding");
122  HPACKEncodeBuffer encoder(512, true);
123  uint32_t size = encoder.encodeLiteral(accept);
124  EXPECT_EQ(size, 12);
125  releaseData(encoder);
126  EXPECT_EQ(buf_->length(), 12);
127  EXPECT_EQ(data_[0], 0x80 | 11); // 128(huffman bit) | 11(length)
128  EXPECT_EQ(data_[11], 0x7f);
129 }
130 
131 TEST_F(HPACKBufferTests, EncodeHuffmanLiteralN) {
132  string accept("accept-encoding");
133  HPACKEncodeBuffer encoder(512, true);
134  uint32_t size = encoder.encodeLiteral(0xE0, 4, accept);
135  EXPECT_EQ(size, 12);
136  releaseData(encoder);
137  EXPECT_EQ(buf_->length(), 12);
138  EXPECT_EQ(data_[0], 0xE0 | 0x10 | 11); // instruction | huffman | length
139  EXPECT_EQ(data_[11], 0x7f);
140 }
141 
142 TEST_F(HPACKBufferTests, DecodeSingleByte) {
143  buf_ = IOBuf::create(512);
144  uint8_t* wdata = buf_->writableData();
145  buf_->append(1);
146  // 6-bit prefix
147  *wdata = 67;
148  resetDecoder();
149  uint64_t integer;
150  CHECK_EQ(decoder_.decodeInteger(7, integer), DecodeError::NONE);
151  CHECK_EQ(integer, 67);
152 
153  resetDecoder();
154 
155  CHECK_EQ(decoder_.decodeInteger(6, integer), DecodeError::NONE);
156  CHECK_EQ(integer, 3);
157 
158  // set a bit in the prefix - it should not affect the decoded value
159  *wdata = 195; // 195 = 128 + 67
160  resetDecoder();
161  CHECK_EQ(decoder_.decodeInteger(7, integer), DecodeError::NONE);
162  CHECK_EQ(integer, 67);
163 
164  // 8-bit prefix - the entire byte
165  resetDecoder();
166  CHECK_EQ(decoder_.decodeInteger(8, integer), DecodeError::NONE);
167  CHECK_EQ(integer, 195);
168 }
169 
170 TEST_F(HPACKBufferTests, DecodeMultiByte) {
171  buf_ = IOBuf::create(512);
172  uint8_t* wdata = buf_->writableData();
173  // edge case - max value in a 2-bit space
174  buf_->append(2);
175  wdata[0] = 67;
176  wdata[1] = 0;
177  resetDecoder();
178  uint64_t integer;
179  CHECK_EQ(decoder_.decodeInteger(2, integer), DecodeError::NONE);
180  CHECK_EQ(integer, 3);
181  CHECK_EQ(decoder_.cursor().length(), 0);
182  // edge case - encode 130 = 127 + 3 on 2-bit prefix
183  wdata[0] = 3;
184  wdata[1] = 127;
185  resetDecoder();
186  CHECK_EQ(decoder_.decodeInteger(2, integer), DecodeError::NONE);
187  CHECK_EQ(integer, 130);
188  CHECK_EQ(decoder_.cursor().length(), 0);
189  // edge case - encode 131 = 128 + 3
190  buf_->append(1);
191  wdata[0] = 3;
192  wdata[1] = 128;
193  wdata[2] = 1;
194  resetDecoder();
195  CHECK_EQ(decoder_.decodeInteger(2, integer), DecodeError::NONE);
196  CHECK_EQ(integer, 131);
197  CHECK_EQ(decoder_.cursor().length(), 0);
198  // encode the value from the RFC example - 1337
199  wdata[0] = 31;
200  wdata[1] = 154;
201  wdata[2] = 10;
202  resetDecoder();
203  CHECK_EQ(decoder_.decodeInteger(5, integer), DecodeError::NONE);
204  CHECK_EQ(integer, 1337);
205  CHECK_EQ(decoder_.cursor().length(), 0);
206 }
207 
208 TEST_F(HPACKBufferTests, DecodeIntegerError) {
209  buf_ = IOBuf::create(128);
210  resetDecoder();
211  // empty buffer
212  uint64_t integer;
213  CHECK_EQ(decoder_.decodeInteger(5, integer), DecodeError::BUFFER_UNDERFLOW);
214 
215  // incomplete buffer
216  buf_->append(2);
217  uint8_t* wdata = buf_->writableData();
218  wdata[0] = 31;
219  wdata[1] = 154;
220  // wdata[2] = 10 missing
221  CHECK_EQ(decoder_.decodeInteger(5, integer), DecodeError::BUFFER_UNDERFLOW);
222 }
223 
224 TEST_F(HPACKBufferTests, DecodeLiteralError) {
225  buf_ = IOBuf::create(128);
226 
227  uint8_t* wdata = buf_->writableData();
228  buf_->append(3);
229  resetDecoder();
230  wdata[0] = 255; // size
231  wdata[1] = 'a';
232  wdata[2] = 'b';
233  folly::fbstring literal;
234  CHECK_EQ(decoder_.decodeLiteral(literal), DecodeError::BUFFER_UNDERFLOW);
235 
236  resetDecoder();
237  // error decoding the size of the literal
238  wdata[0] = 0xFF;
239  wdata[1] = 0x80;
240  wdata[2] = 0x80;
241  EXPECT_EQ(decoder_.decodeLiteral(literal), DecodeError::BUFFER_UNDERFLOW);
242 }
243 
244 TEST_F(HPACKBufferTests, DecodeLiteralMultiBuffer) {
245  auto buf1 = IOBuf::create(128);
246  auto buf2 = IOBuf::create(128);
247  // encode the size
248  // buf2 will not be entirely filled, to keep space for encoding the size
249  // without overflowing
250  uint32_t size = buf1->capacity() + buf2->capacity() - 10;
251  releaseData();
252  uint32_t sizeLen = encoder_.encodeInteger(size, 0, 7);
253  releaseData();
254  // copy the encoding of the size at the beginning
255  memcpy(buf1->writableData(), buf_->data(), sizeLen);
256  for (size_t i = sizeLen; i < buf1->capacity(); i++) {
257  buf1->writableData()[i] = 'x';
258  }
259  buf1->append(buf1->capacity());
260  for (size_t i = 0; i < buf2->capacity() - 10 + sizeLen; i++) {
261  buf2->writableData()[i] = 'y';
262  }
263  buf2->append(buf2->capacity() - 10 + sizeLen);
264  buf1->appendChain(std::move(buf2));
265  // decode
266  resetDecoder(buf1.get());
267  folly::fbstring literal;
268  EXPECT_EQ(decoder_.decodeLiteral(literal), DecodeError::NONE);
269  EXPECT_EQ(literal.size(), size);
270  EXPECT_EQ(literal[0], 'x');
271  EXPECT_EQ(literal[literal.size() - 1], 'y');
272 }
273 
274 TEST_F(HPACKBufferTests, DecodeHuffmanLiteralMultiBuffer) {
275  // "gzip" fits perfectly in a 3 bytes block
276  std::array<uint8_t, 3> gzip{0x9b, 0xd9, 0xab};
277  auto buf1 = IOBuf::create(128);
278  auto buf2 = IOBuf::create(128);
279  // total size
280  uint32_t size = buf1->capacity() + buf2->capacity() - 10;
281  // it needs to fit a multiple of 3 blocks
282  size -= (size % 3);
283  // just in case we have some bytes left encoded
284  releaseData();
285  uint32_t sizeLen = encoder_.encodeInteger(size, 128, 7);
286  // extract the encoded size
287  releaseData();
288  memcpy(buf1->writableData(), buf_->data(), sizeLen);
289  // huffman index
290  uint32_t hi = 0;
291  for (size_t i = sizeLen; i < buf1->capacity(); i++) {
292  buf1->writableData()[i] = gzip[hi];
293  hi = (hi + 1) % 3;
294  }
295  buf1->append(buf1->capacity());
296  for (size_t i = 0; i < buf2->capacity() - 10 + sizeLen; i++) {
297  buf2->writableData()[i] = gzip[hi];
298  hi = (hi + 1) % 3;
299  }
300  buf2->append(buf2->capacity() - 10 + sizeLen);
301  buf1->appendChain(std::move(buf2));
302  // decode
303  resetDecoder(buf1.get());
304  folly::fbstring literal;
305  EXPECT_EQ(decoder_.decodeLiteral(literal), DecodeError::NONE);
306  EXPECT_EQ(literal.size(), 4 * (size / 3));
307  EXPECT_EQ(literal.find("gzip"), 0);
308  EXPECT_EQ(literal.rfind("gzip"), literal.size() - 4);
309 }
310 
311 TEST_F(HPACKBufferTests, DecodeHuffmanLiteralN) {
312  // "gzip" fits perfectly in a 3 bytes block
313  std::array<uint8_t, 3> gzip{0x9b, 0xd9, 0xab};
314  uint32_t size = 3;
315  // just in case we have some bytes left encoded
316  releaseData();
317  encoder_.encodeInteger(size, 0x80 | 0x10, 4);
318  releaseData();
319  memcpy(buf_->writableData() + 1, gzip.data(), size);
320  buf_->append(size);
321  // decode
322  resetDecoder(buf_.get());
323  folly::fbstring literal;
324  EXPECT_EQ(decoder_.decodeLiteral(4, literal), DecodeError::NONE);
325  EXPECT_EQ(literal.size(), 4 * (size / 3));
326  EXPECT_EQ(literal.find("gzip"), 0);
327  EXPECT_EQ(literal.rfind("gzip"), literal.size() - 4);
328 }
329 
330 TEST_F(HPACKBufferTests, DecodePlainLiteral) {
331  buf_ = IOBuf::create(512);
332  std::string gzip("gzip");
333  folly::fbstring literal;
334  uint8_t* wdata = buf_->writableData();
335 
336  buf_->append(1 + gzip.size());
337  wdata[0] = gzip.size();
338  memcpy(wdata + 1, gzip.c_str(), gzip.size());
339 
340  resetDecoder();
341  decoder_.decodeLiteral(literal);
342  CHECK_EQ(literal, gzip);
343 }
344 
345 
346 TEST_F(HPACKBufferTests, DecodePlainLiteralN) {
347  buf_ = IOBuf::create(512);
348  std::string gzip("gzip");
349  folly::fbstring literal;
350  uint8_t* wdata = buf_->writableData();
351 
352  buf_->append(1 + gzip.size());
353  wdata[0] = 0xE0 | gzip.size(); // add a 3 bit instruction
354  memcpy(wdata + 1, gzip.c_str(), gzip.size());
355 
356  resetDecoder();
357  decoder_.decodeLiteral(4, literal);
358  CHECK_EQ(literal, gzip);
359 }
360 
361 TEST_F(HPACKBufferTests, IntegerEncodeDecode) {
362  HPACKEncodeBuffer encoder(512);
363  // first encode
364  uint32_t value = 145333;
365  encoder.encodeInteger(value, 128, 5);
366  releaseData(encoder);
367  resetDecoder();
368  EXPECT_EQ(decoder_.cursor().length(), 4);
369  // now decode
370  uint64_t integer;
371  EXPECT_EQ(decoder_.decodeInteger(5, integer), DecodeError::NONE);
372  EXPECT_EQ(integer, value);
373  EXPECT_EQ(decoder_.cursor().length(), 0);
374 
375  // corner case
376  value = 63;
377  encoder.encodeInteger(value, 64, 6);
378  releaseData(encoder);
379  resetDecoder();
380  EXPECT_EQ(decoder_.decodeInteger(6, integer), DecodeError::NONE);
381  EXPECT_EQ(integer, value);
382 }
383 
387 TEST_F(HPACKBufferTests, IntegerOverflow) {
388  uint64_t integer;
389  buf_ = IOBuf::create(128);
390  uint8_t *wdata = buf_->writableData();
391 
392  // enough headroom for both cases
393  buf_->append(12);
394  // overflow the accumulated value
395  wdata[0] = 0xFF;
396  wdata[1] = 0xFF;
397  wdata[2] = 0xFF;
398  wdata[3] = 0xFF;
399  wdata[4] = 0xFF;
400  wdata[5] = 0xFF;
401  wdata[6] = 0xFF;
402  wdata[7] = 0xFF;
403  wdata[8] = 0xFF;
404  wdata[9] = 0xFF;
405  wdata[10] = 0x0F;
406  resetDecoder();
407  EXPECT_EQ(decoder_.decodeInteger(8, integer), DecodeError::INTEGER_OVERFLOW);
408 
409  // overflow the factorizer
410  wdata[0] = 0xFF;
411  wdata[1] = 0x80;
412  wdata[2] = 0x80;
413  wdata[3] = 0x80;
414  wdata[4] = 0x80;
415  wdata[5] = 0x80;
416  wdata[6] = 0x80;
417  wdata[7] = 0x80;
418  wdata[8] = 0x80;
419  wdata[9] = 0x80;
420  wdata[10] = 0x80;
421  wdata[11] = 0x01;
422  resetDecoder();
423  EXPECT_EQ(decoder_.decodeInteger(8, integer), DecodeError::INTEGER_OVERFLOW);
424 }
425 
429 TEST_F(HPACKBufferTests, IntegerMax) {
430  releaseData();
431  // encoding with all the bit prefixes
432  for (uint8_t bitprefix = 1; bitprefix <= 8; bitprefix++) {
433  encoder_.encodeInteger(std::numeric_limits<uint64_t>::max(), 0, bitprefix);
434  // take the encoded data and shove it in the decoder
435  releaseData();
436  resetDecoder();
437  uint64_t integer = 0;
438  EXPECT_EQ(decoder_.decodeInteger(bitprefix, integer), DecodeError::NONE);
440  }
441 }
442 
447 TEST_F(HPACKBufferTests, EmptyIobufLiteral) {
448  // construct an IOBuf chain made of 1 empty chain and a literal
449  unique_ptr<IOBuf> first = IOBuf::create(128);
450  // set a trap by setting first byte to 128, which signals Huffman encoding
451  first->writableData()[0] = 0x80;
452 
453  HPACKEncodeBuffer encoder(128); // no huffman
454  folly::fbstring literal("randomheadervalue");
455  encoder.encodeLiteral(literal);
456  first->appendChain(encoder.release());
457 
458  uint32_t size = first->next()->length();
459  Cursor cursor(first.get());
460  HPACKDecodeBuffer decoder(cursor, size, kMaxLiteralSize);
461  folly::fbstring decoded;
462  decoder.decodeLiteral(decoded);
463 
464  EXPECT_EQ(literal, decoded);
465 }
466 
470 TEST_F(HPACKBufferTests, LargeLiteralError) {
471  uint32_t largeSize = 10 + kMaxLiteralSize;
472  // encode a large string
473  string largeLiteral;
474  largeLiteral.append(largeSize, 'x');
475  EXPECT_TRUE(encoder_.encodeLiteral(largeLiteral));
476  releaseData();
477  resetDecoder();
478  folly::fbstring decoded = "";
479  EXPECT_EQ(decoder_.decodeLiteral(decoded), DecodeError::LITERAL_TOO_LARGE);
480  EXPECT_EQ(decoded.size(), 0);
481 }
size_type size() const
Definition: FBString.h:1337
void resetDecoder(IOBuf *buf)
uint32_t encodeLiteral(folly::StringPiece literal)
std::unique_ptr< folly::IOBuf > release()
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
LogLevel max
Definition: LogLevel.cpp:31
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
void appendChain(std::unique_ptr< IOBuf > &&iobuf)
Definition: IOBuf.h:827
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
STL namespace.
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
uint8_t * writableData()
Definition: IOBuf.h:509
constexpr Iter data() const
Definition: Range.h:446
std::size_t length() const
Definition: IOBuf.h:533
uint32_t encodeInteger(uint64_t value, uint8_t instruction, uint8_t nbit)
IOBuf * next()
Definition: IOBuf.h:600
TEST_F(AsyncSSLSocketWriteTest, write_coalescing1)
HPACKEncodeBuffer encoder_
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
const char * string
Definition: Conv.cpp:212
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
void releaseData(HPACKEncodeBuffer &encoder)
StringPiece data_
HPACKDecodeBuffer decoder_
constexpr detail::First first
Definition: Base-inl.h:2553
NetworkSocket accept(NetworkSocket s, sockaddr *addr, socklen_t *addrlen)
Definition: NetOps.cpp:71