proxygen
HTTP2FramerTest.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  */
11 
12 #include <folly/Random.h>
17 #include <random>
18 
20 
21 using namespace folly::io;
22 using namespace folly;
23 using namespace proxygen::http2;
24 using namespace proxygen;
25 using namespace std;
26 
29  QueueAppender appender(&queue, kFrameHeaderSize);
30  uint32_t lengthAndType = length << 8 | type;
31  appender.writeBE<uint32_t>(lengthAndType);
32  appender.writeBE<uint8_t>(flags);
33  appender.writeBE<uint32_t>(stream);
34 }
35 
37  public:
39 
40  template<typename ParseFunc, typename... Args>
41  void parse(ParseFunc&& parseFn, FrameHeader& outHeader, Args&&... outArgs) {
42  parse(queue_.front(), parseFn, outHeader, std::forward<Args>(outArgs)...);
43  }
44 
45  template<typename ParseFunc, typename... Args>
46  void parse(const IOBuf* data, ParseFunc&& parseFn,
47  FrameHeader& outHeader, Args&&... outArgs) {
48  Cursor cursor(data);
49  auto ret1 = parseFrameHeader(cursor, outHeader);
50  ASSERT_EQ(ret1, ErrorCode::NO_ERROR);
51  auto ret2 = (*parseFn)(cursor, outHeader, std::forward<Args>(outArgs)...);
52  ASSERT_EQ(ret2, ErrorCode::NO_ERROR);
53  }
54 
56  auto body = makeBuf(dataLen);
57  dataFrameTest(body.get(), dataLen, padLen);
58  }
59 
60  void dataFrameTest(IOBuf* body, uint32_t dataLen,
61  folly::Optional<uint8_t> padLen) {
62  uint32_t frameLen = uint32_t(dataLen);
63  if (padLen) {
64  frameLen += 1 + *padLen;
65  }
66  if (frameLen > kMaxFramePayloadLength) {
67  EXPECT_DEATH_NO_CORE(writeData(queue_, body->clone(), 1, padLen,
68  false, true), ".*");
69  } else {
70  writeData(queue_, body->clone(), 1, padLen, false, true);
71 
72  FrameHeader outHeader;
73  std::unique_ptr<IOBuf> outBuf;
74  uint16_t padding = 0;
75  parse(&parseData, outHeader, outBuf, padding);
76 
77  EXPECT_EQ(outBuf->moveToFbString(), body->moveToFbString());
78  EXPECT_EQ(padding, padLen ? (*padLen + 1) : 0);
79  }
80  queue_.move(); // reset everything
81  }
82 
84 };
85 
86 TEST_F(HTTP2FramerTest, WriteAndParseSmallDataNoPad) {
87  dataFrameTest(20, kNoPadding);
88 }
89 
90 TEST_F(HTTP2FramerTest, WriteAndParseSmallDataZeroPad) {
91  dataFrameTest(20, Padding(0));
92 }
93 
94 TEST_F(HTTP2FramerTest, WriteAndParseSmallDataSmallPad) {
95  dataFrameTest(20, Padding(20));
96 }
97 
98 TEST_F(HTTP2FramerTest, ManyDataFrameSizes) {
99  dataFrameTest(0, kNoPadding);
100  for (uint32_t dataLen = 1; dataLen < kMaxFramePayloadLength; dataLen <<= 1) {
101  auto body = makeBuf(dataLen);
102  dataFrameTest(body.get(), dataLen, Padding(0));
103  dataFrameTest(0, Padding(dataLen));
104  for (uint8_t padding = 1; padding != 0; padding <<= 1) {
105  dataFrameTest(body.get(), dataLen, Padding(padding));
106  }
107  }
108 }
109 
110 TEST_F(HTTP2FramerTest, BadStreamData) {
111  writeFrameHeaderManual(queue_, 0,
112  static_cast<uint8_t>(FrameType::DATA),
113  0, 0);
114  FrameHeader outHeader;
115  std::unique_ptr<IOBuf> outBuf;
116  uint16_t padding = 0;
117  Cursor cursor(queue_.front());
118  EXPECT_EQ(parseFrameHeader(cursor, outHeader), ErrorCode::NO_ERROR);
119  EXPECT_EQ(parseData(cursor, outHeader, outBuf, padding),
120  ErrorCode::PROTOCOL_ERROR);
121 }
122 
123 TEST_F(HTTP2FramerTest, BadStreamSettings) {
124  writeFrameHeaderManual(queue_, 0,
125  static_cast<uint8_t>(FrameType::SETTINGS),
126  ACK, 1);
127  FrameHeader outHeader;
128  std::deque<SettingPair> outSettings;
129  Cursor cursor(queue_.front());
130  EXPECT_EQ(parseFrameHeader(cursor, outHeader), ErrorCode::NO_ERROR);
131  EXPECT_EQ(parseSettings(cursor, outHeader, outSettings),
132  ErrorCode::PROTOCOL_ERROR);
133 }
134 
136  auto body = makeBuf(5);
137  writeData(queue_, body->clone(), 1, Padding(5), false, true);
138  queue_.trimEnd(5);
139  queue_.append(string("abcde"));
140 
141  FrameHeader outHeader;
142  std::unique_ptr<IOBuf> outBuf;
143  uint16_t padding = 0;
144  Cursor cursor(queue_.front());
145  EXPECT_EQ(parseFrameHeader(cursor, outHeader), ErrorCode::NO_ERROR);
146  EXPECT_EQ(parseData(cursor, outHeader, outBuf, padding),
147  ErrorCode::PROTOCOL_ERROR);
148 }
149 
150 TEST_F(HTTP2FramerTest, NoHeadroomOptimization) {
151  queue_.move();
152  auto buf = folly::IOBuf::create(200);
153  // This should make enough headroom so we will apply the optimization:
154  auto headRoomSize = kFrameHeaderSize + kFramePrioritySize * 2 + 10;
155  buf->advance(headRoomSize);
156  buf->append(20); // make a positive length
157  writeData(queue_, std::move(buf), 1, Padding(0), false,
158  false /* reuseIOBufHeadroom */);
159  auto queueHead = queue_.front();
160  EXPECT_TRUE(queueHead->isChained());
161  // This is our original iobuf:
162  auto queueNode = queueHead->prev();
163  EXPECT_TRUE(queueNode != nullptr);
164  // And its headroom or length is untouched:
165  EXPECT_EQ(headRoomSize, queueNode->headroom());
166  EXPECT_EQ(20, queueNode->length());
167 }
168 
169 TEST_F(HTTP2FramerTest, UseHeadroomOptimization) {
170  queue_.move();
171  auto buf = folly::IOBuf::create(200);
172  // This should make enough headroom so we will apply the optimization:
173  auto headRoomSize = kFrameHeaderSize + kFramePrioritySize * 2 + 10;
174  buf->advance(headRoomSize);
175  buf->append(20); // make a positive length
176  writeData(queue_, std::move(buf), 1, Padding(0), false,
177  true /* reuseIOBufHeadroom */);
178  // There won't be a chain, frame header is written in-place into our IOBuf:
179  auto queueNode = queue_.front();
180  EXPECT_FALSE(queueNode->isChained());
181  // And its headroom has been shrinked:
182  EXPECT_LT(queueNode->headroom(), headRoomSize);
183 }
184 
185 TEST_F(HTTP2FramerTest, BadStreamId) {
186  // We should crash on DBG builds if the stream id > 2^31 - 1
188  static_cast<uint32_t>(-1),
189  ErrorCode::PROTOCOL_ERROR), ".*");
190 }
191 
192 TEST_F(HTTP2FramerTest, RstStream) {
193  writeRstStream(queue_, 1, ErrorCode::CANCEL);
194 
195  FrameHeader header;
196  ErrorCode outCode;
197  parse(&parseRstStream, header, outCode);
198 
200  ASSERT_EQ(1, header.stream);
201  ASSERT_EQ(0, header.flags);
203  ASSERT_EQ(ErrorCode::CANCEL, outCode);
204 }
205 
207  writeGoaway(queue_, 0, ErrorCode::FLOW_CONTROL_ERROR);
208 
209  FrameHeader header;
210  uint32_t lastStreamID;
211  ErrorCode outCode;
212  std::unique_ptr<IOBuf> outDebugData;
213  parse(&parseGoaway, header, lastStreamID, outCode, outDebugData);
214 
216  ASSERT_EQ(0, header.stream);
217  ASSERT_EQ(0, header.flags);
219  ASSERT_EQ(ErrorCode::FLOW_CONTROL_ERROR, outCode);
220  ASSERT_EQ(0, lastStreamID);
221  ASSERT_FALSE(outDebugData);
222 }
223 
224 TEST_F(HTTP2FramerTest, GoawayDebugData) {
225  string data("abcde");
226  auto debugData = makeBuf(5);
227  memcpy(debugData->writableData(), data.data(), data.length());
228  writeGoaway(queue_, 0, ErrorCode::FLOW_CONTROL_ERROR, std::move(debugData));
229 
230  FrameHeader header;
231  uint32_t lastStreamID;
232  ErrorCode outCode;
233  std::unique_ptr<IOBuf> outDebugData;
234  parse(&parseGoaway, header, lastStreamID, outCode, outDebugData);
235 
237  ASSERT_EQ(0, header.stream);
238  ASSERT_EQ(0, header.flags);
239  ASSERT_EQ(kFrameGoawaySize + data.length(), header.length);
240  ASSERT_EQ(ErrorCode::FLOW_CONTROL_ERROR, outCode);
241  ASSERT_EQ(0, lastStreamID);
242  ASSERT_EQ(outDebugData->computeChainDataLength(), data.length());
243  EXPECT_EQ(outDebugData->moveToFbString(), data);
244 }
245 
246 // An invalid error code. Used to test a bug where
247 // a macro expansion caused us to read the error code twice
248 TEST_F(HTTP2FramerTest, GoawayDoubleRead) {
250  queue_,
252  static_cast<uint8_t>(FrameType::GOAWAY),
253  0,
254  0);
255 
256  QueueAppender appender(&queue_, kFrameGoawaySize);
257  appender.writeBE<uint32_t>(0);
258  // Here's the invalid value:
259  appender.writeBE<uint32_t>(static_cast<uint32_t>(0xffffffff));
260 
261  uint32_t outLastStreamID;
262  ErrorCode outCode;
263  std::unique_ptr<IOBuf> outDebugData;
264  FrameHeader outHeader;
265  Cursor cursor(queue_.front());
266 
267  auto ret1 = parseFrameHeader(cursor, outHeader);
268  ASSERT_EQ(ErrorCode::NO_ERROR, ret1);
269  ASSERT_EQ(FrameType::GOAWAY, outHeader.type);
270  auto ret2 = parseGoaway(cursor, outHeader, outLastStreamID,
271  outCode, outDebugData);
272  ASSERT_EQ(ErrorCode::PROTOCOL_ERROR, ret2);
273 }
274 
276  writePriority(queue_, 102, {0, false, 30});
277 
278  FrameHeader header;
279  PriorityUpdate priority;
280  parse(&parsePriority, header, priority);
281 
282  ASSERT_EQ(FrameType::PRIORITY, header.type);
283  ASSERT_EQ(102, header.stream);
284  ASSERT_EQ(0, header.flags);
285  ASSERT_EQ(0, priority.streamDependency);
286  ASSERT_FALSE(priority.exclusive);
287  ASSERT_EQ(30, priority.weight);
288 }
289 
290 TEST_F(HTTP2FramerTest, HeadersWithPaddingAndPriority) {
291  auto body = makeBuf(500);
292  writeHeaders(queue_, body->clone(), 1, {{0, true, 12}}, 200,
293  false, false);
294 
295  FrameHeader header;
297  std::unique_ptr<IOBuf> outBuf;
298  parse(&parseHeaders, header, priority, outBuf);
299 
300  ASSERT_EQ(FrameType::HEADERS, header.type);
301  ASSERT_EQ(1, header.stream);
302  ASSERT_TRUE(PRIORITY & header.flags);
303  ASSERT_FALSE(END_STREAM & header.flags);
304  ASSERT_FALSE(END_HEADERS & header.flags);
305  ASSERT_EQ(0, priority->streamDependency);
306  ASSERT_TRUE(priority->exclusive);
307  ASSERT_EQ(12, priority->weight);
308  EXPECT_EQ(outBuf->moveToFbString(), body->moveToFbString());
309 }
310 
313  writePing(queue_, data, false);
314 
315  FrameHeader header;
316  uint64_t outData;
317  parse(&parsePing, header, outData);
318 
319  ASSERT_EQ(FrameType::PING, header.type);
320  ASSERT_EQ(0, header.stream);
321  ASSERT_EQ(0, header.flags);
322  EXPECT_EQ(data, outData);
323 }
324 
325 TEST_F(HTTP2FramerTest, WindowUpdate) {
326  writeWindowUpdate(queue_, 33, 120);
327 
328  FrameHeader header;
329  uint32_t amount;
330  parse(&parseWindowUpdate, header, amount);
331 
333  ASSERT_EQ(33, header.stream);
334  ASSERT_EQ(0, header.flags);
335  EXPECT_EQ(120, amount);
336 }
337 
338 TEST_F(HTTP2FramerTest, CertificateRequest) {
339  string data("abcdef");
340  auto authRequest = makeBuf(6);
341  memcpy(authRequest->writableData(), data.data(), data.length());
342  uint16_t requestId = 120;
343  writeCertificateRequest(queue_, requestId, std::move(authRequest));
344 
345  FrameHeader header;
346  uint16_t outRequestId;
347  std::unique_ptr<IOBuf> outAuthRequest;
348  parse(&parseCertificateRequest, header, outRequestId, outAuthRequest);
349 
350  ASSERT_EQ(FrameType::CERTIFICATE_REQUEST, header.type);
351  ASSERT_EQ(0, header.stream);
352  ASSERT_EQ(0, header.flags);
353  ASSERT_EQ(kFrameCertificateRequestSizeBase + data.length(), header.length);
354  ASSERT_EQ(outRequestId, requestId);
355  ASSERT_EQ(outAuthRequest->computeChainDataLength(), data.length());
356  EXPECT_EQ(outAuthRequest->moveToFbString(), data);
357 }
358 
359 TEST_F(HTTP2FramerTest, EmptyCertificateRequest) {
360  uint16_t requestId = 120;
361  writeCertificateRequest(queue_, requestId, nullptr);
362 
363  FrameHeader header;
364  uint16_t outRequestId;
365  std::unique_ptr<IOBuf> outAuthRequest;
366  parse(&parseCertificateRequest, header, outRequestId, outAuthRequest);
367 
368  ASSERT_EQ(FrameType::CERTIFICATE_REQUEST, header.type);
369  ASSERT_EQ(0, header.stream);
370  ASSERT_EQ(0, header.flags);
372  ASSERT_EQ(outRequestId, requestId);
373  ASSERT_FALSE(outAuthRequest);
374 }
375 
376 TEST_F(HTTP2FramerTest, ShortCertificateRequest) {
377  // length field is too short for frame type
379  queue_, 1, static_cast<uint8_t>(FrameType::CERTIFICATE_REQUEST), 0, 0);
380  QueueAppender appender(&queue_, 1);
381  appender.writeBE<uint8_t>(1);
382 
383  Cursor cursor(queue_.front());
384  FrameHeader header;
385  uint16_t outRequestId;
386  std::unique_ptr<IOBuf> outAuthRequest;
387  parseFrameHeader(cursor, header);
388  auto ret =
389  parseCertificateRequest(cursor, header, outRequestId, outAuthRequest);
390  ASSERT_EQ(ErrorCode::FRAME_SIZE_ERROR, ret);
391 }
392 
393 TEST_F(HTTP2FramerTest, CertificateRequestOnNonzeroStream) {
394  // received CERTIFICATE_REQUEST frame on nonzero stream
396  queue_, 2, static_cast<uint8_t>(FrameType::CERTIFICATE_REQUEST), 0, 1);
397  QueueAppender appender(&queue_, 1);
398  appender.writeBE<uint16_t>(1);
399 
400  Cursor cursor(queue_.front());
401  FrameHeader header;
402  uint16_t outRequestId;
403  std::unique_ptr<IOBuf> outAuthRequest;
404  parseFrameHeader(cursor, header);
405  auto ret =
406  parseCertificateRequest(cursor, header, outRequestId, outAuthRequest);
407  ASSERT_EQ(ErrorCode::PROTOCOL_ERROR, ret);
408 }
409 
410 TEST_F(HTTP2FramerTest, EndingCertificate) {
411  string data("abcdef");
412  auto authenticator = makeBuf(6);
413  memcpy(authenticator->writableData(), data.data(), data.length());
414  uint16_t certId = 120;
415  // The last CERTIFICATE frame containing authenticator fragment.
416  writeCertificate(queue_, certId, std::move(authenticator), false);
417 
418  FrameHeader header;
419  uint16_t outCertId;
420  std::unique_ptr<IOBuf> outAuthenticator;
421  parse(&parseCertificate, header, outCertId, outAuthenticator);
422 
423  ASSERT_EQ(FrameType::CERTIFICATE, header.type);
424  ASSERT_EQ(0, header.stream);
425  ASSERT_EQ(0, header.flags);
426  ASSERT_EQ(kFrameCertificateSizeBase + data.length(), header.length);
427  ASSERT_EQ(outCertId, certId);
428  ASSERT_EQ(outAuthenticator->computeChainDataLength(), data.length());
429  EXPECT_EQ(outAuthenticator->moveToFbString(), data);
430 }
431 
432 TEST_F(HTTP2FramerTest, Certificate) {
433  string data("abcdef");
434  auto authenticator = makeBuf(6);
435  memcpy(authenticator->writableData(), data.data(), data.length());
436  uint16_t certId = 120;
437  // CERTIFICATE frame containing an authenticator fragment but not the last
438  // fragment.
439  writeCertificate(queue_, certId, std::move(authenticator), true);
440 
441  FrameHeader header;
442  uint16_t outCertId;
443  std::unique_ptr<IOBuf> outAuthenticator;
444  parse(&parseCertificate, header, outCertId, outAuthenticator);
445 
446  ASSERT_EQ(FrameType::CERTIFICATE, header.type);
447  ASSERT_EQ(0, header.stream);
449  ASSERT_EQ(kFrameCertificateSizeBase + data.length(), header.length);
450  ASSERT_EQ(outCertId, certId);
451  ASSERT_EQ(outAuthenticator->computeChainDataLength(), data.length());
452  EXPECT_EQ(outAuthenticator->moveToFbString(), data);
453 }
454 
455 TEST_F(HTTP2FramerTest, EmptyCertificate) {
456  uint16_t certId = 120;
457  writeCertificate(queue_, certId, nullptr, true);
458 
459  FrameHeader header;
460  uint16_t outCertId;
461  std::unique_ptr<IOBuf> outAuthenticator;
462  parse(&parseCertificate, header, outCertId, outAuthenticator);
463 
464  ASSERT_EQ(FrameType::CERTIFICATE, header.type);
465  ASSERT_EQ(0, header.stream);
468  ASSERT_EQ(outCertId, certId);
469  ASSERT_FALSE(outAuthenticator);
470 }
471 
472 TEST_F(HTTP2FramerTest, ShortCertificate) {
473  // length field is too short for frame type
475  queue_, 1, static_cast<uint8_t>(FrameType::CERTIFICATE), 0, 0);
476  QueueAppender appender(&queue_, 1);
477  appender.writeBE<uint8_t>(1);
478 
479  Cursor cursor(queue_.front());
480  FrameHeader header;
481  uint16_t outCertId;
482  std::unique_ptr<IOBuf> outAuthenticator;
483  parseFrameHeader(cursor, header);
484  auto ret = parseCertificate(cursor, header, outCertId, outAuthenticator);
485  ASSERT_EQ(ErrorCode::FRAME_SIZE_ERROR, ret);
486 }
487 
488 TEST_F(HTTP2FramerTest, CertificateOnNonzeroStream) {
489  // received CERTIFICATE frame on nonzero stream
491  queue_, 2, static_cast<uint8_t>(FrameType::CERTIFICATE), 0, 1);
492  QueueAppender appender(&queue_, 1);
493  appender.writeBE<uint16_t>(1);
494 
495  Cursor cursor(queue_.front());
496  FrameHeader header;
497  uint16_t outCertId;
498  std::unique_ptr<IOBuf> outAuthenticator;
499  parseFrameHeader(cursor, header);
500  auto ret = parseCertificate(cursor, header, outCertId, outAuthenticator);
501  ASSERT_EQ(ErrorCode::PROTOCOL_ERROR, ret);
502 }
503 
504 // TODO: auto generate this test for all frame types (except DATA)
505 TEST_F(HTTP2FramerTest, ShortWindowUpdate) {
506  // length field is too short for frame type
507  writeFrameHeaderManual(queue_, 0,
508  static_cast<uint8_t>(FrameType::WINDOW_UPDATE),
509  0, 0);
510 
511  Cursor cursor(queue_.front());
512  FrameHeader header;
513  uint32_t amount;
514  parseFrameHeader(cursor, header);
515  auto ret2 = parseWindowUpdate(cursor, header, amount);
516  ASSERT_EQ(ErrorCode::FRAME_SIZE_ERROR, ret2);
517 }
518 
519 TEST_F(HTTP2FramerTest, Uint32MaxWindowUpdate) {
520  const uint32_t uint31Max = 0x7fffffff;
521  writeWindowUpdate(queue_, 33, 1); // we will overwrite the update size
522  auto buf = queue_.move();
523  buf->coalesce();
524  // Set update size to unit32_t max
525  for (unsigned i = 0; i < 4; ++i) {
526  buf->writableData()[kFrameHeaderSize + i] = 0xff;
527  }
528 
529  FrameHeader header;
530  uint32_t amount;
531  parse(buf.get(), &parseWindowUpdate, header, amount);
532 
533  ASSERT_EQ(FrameType::WINDOW_UPDATE, header.type);
534  ASSERT_EQ(33, header.stream);
535  ASSERT_EQ(0, header.flags);
536  // We should ignore the top bit
537  EXPECT_EQ(uint31Max, amount);
538 }
539 
541  string protocol = "special-proto";
542  string host = "special-host";
543  string origin = "special-origin";
544  writeAltSvc(queue_, 2, 150, 8080, protocol, host, origin);
545 
546  FrameHeader header;
547  uint32_t outMaxAge;
548  uint32_t outPort;
549  string outProtocol;
550  string outHost;
551  string outOrigin;
552  parse(&parseAltSvc, header, outMaxAge, outPort, outProtocol,
553  outHost, outOrigin);
554 
555  ASSERT_EQ(FrameType::ALTSVC, header.type);
556  ASSERT_EQ(2, header.stream);
557  ASSERT_EQ(0, header.flags);
558  EXPECT_EQ(150, outMaxAge);
559  EXPECT_EQ(8080, outPort);
560  EXPECT_EQ(protocol, outProtocol);
561  EXPECT_EQ(host, outHost);
562  EXPECT_EQ(origin, outOrigin);
563 }
564 
566  const deque<SettingPair> settings = {{SettingsId::HEADER_TABLE_SIZE, 3},
567  {SettingsId::MAX_CONCURRENT_STREAMS, 4}};
568  writeSettings(queue_, settings);
569 
570  FrameHeader header;
571  std::deque<SettingPair> outSettings;
572  parse(&parseSettings, header, outSettings);
573 
574  ASSERT_EQ(settings.size() * 6, header.length);
576  ASSERT_EQ(0, header.stream);
577  ASSERT_EQ(0, header.flags);
578  ASSERT_EQ(settings, outSettings);
579 }
580 
581 TEST_F(HTTP2FramerTest, SettingsAck) {
582  writeSettingsAck(queue_);
583 
584  Cursor cursor(queue_.front());
585  FrameHeader header;
586  auto ret = parseFrameHeader(cursor, header);
587  ASSERT_EQ(ErrorCode::NO_ERROR, ret);
588 
589  ASSERT_EQ(0, header.length);
590  ASSERT_EQ(FrameType::SETTINGS, header.type);
591  ASSERT_EQ(0, header.stream);
592  ASSERT_EQ(ACK, header.flags);
593  std::deque<SettingPair> outSettings;
594  EXPECT_EQ(parseSettings(cursor, header, outSettings), ErrorCode::NO_ERROR);
595 }
596 
597 TEST_F(HTTP2FramerTest, BadSettingsAck) {
598  writeSettingsAck(queue_);
599  // Add an extra byte to the frame
600  uint32_t lengthAndType = htonl(1 << 8 | uint8_t(FrameType::SETTINGS));
601  memcpy(((IOBuf*)queue_.front())->writableData(), &lengthAndType, 4);
602  queue_.append("o");
603 
604  Cursor cursor(queue_.front());
605  FrameHeader header;
606  auto ret = parseFrameHeader(cursor, header);
607  ASSERT_EQ(ErrorCode::NO_ERROR, ret);
608 
609  ASSERT_EQ(FrameType::SETTINGS, header.type);
610  ASSERT_EQ(0, header.stream);
611  ASSERT_EQ(ACK, header.flags);
612  std::deque<SettingPair> outSettings;
613  EXPECT_EQ(parseSettings(cursor, header, outSettings),
614  ErrorCode::FRAME_SIZE_ERROR);
615 }
616 
617 TEST_F(HTTP2FramerTest, UnknownSetting) {
618  const deque<SettingPair> settings = {{(proxygen::SettingsId)31337, 3},
619  {(proxygen::SettingsId)0, 4}};
620  writeSettings(queue_, settings);
621 
622  FrameHeader header;
623  std::deque<SettingPair> outSettings;
624  parse(&parseSettings, header, outSettings);
625 
626  ASSERT_EQ(settings.size() * 6, header.length);
628  ASSERT_EQ(0, header.stream);
629  ASSERT_EQ(0, header.flags);
630  ASSERT_EQ(settings, outSettings);
631 }
632 
633 TEST_F(HTTP2FramerTest, PushPromise) {
634  auto body = makeBuf(500);
635  writePushPromise(queue_, 21, 22, body->clone(), 255, true);
636 
637  FrameHeader header;
638  uint32_t promisedStream;
639  std::unique_ptr<IOBuf> outBuf;
640  parse(&parsePushPromise, header, promisedStream, outBuf);
641 
642  ASSERT_EQ(FrameType::PUSH_PROMISE, header.type);
643  ASSERT_EQ(21, header.stream);
644  ASSERT_EQ(22, promisedStream);
645  EXPECT_EQ(outBuf->moveToFbString(), body->moveToFbString());
646 }
647 
648 TEST_F(HTTP2FramerTest, Continuation) {
649  auto body = makeBuf(800);
650  writeContinuation(queue_, 1, true, body->clone());
651 
652  FrameHeader header;
653  std::unique_ptr<IOBuf> outBuf;
654  parse(&parseContinuation, header, outBuf);
655 
656  ASSERT_EQ(FrameType::CONTINUATION, header.type);
657  ASSERT_TRUE(END_HEADERS & header.flags);
658  ASSERT_FALSE(PADDED & header.flags);
659  ASSERT_EQ(1, header.stream);
660  EXPECT_EQ(outBuf->moveToFbString(), body->moveToFbString());
661 }
662 
663 TEST_F(HTTP2FramerTest, ExHeaders) {
664  auto body = makeBuf(500);
665  uint32_t streamID = folly::Random::rand32(10, 1024) * 2 + 1;
666  uint32_t controlStream = streamID - 2;
667  writeExHeaders(queue_, body->clone(), streamID,
668  HTTPCodec::ExAttributes(controlStream, false),
669  {{0, true, 12}}, 200, false, false);
670 
671  FrameHeader header;
672  HTTPCodec::ExAttributes outExAttributes;
674  std::unique_ptr<IOBuf> outBuf;
675  parse(&parseExHeaders, header, outExAttributes, priority, outBuf);
676 
677  ASSERT_EQ(FrameType::EX_HEADERS, header.type);
678  ASSERT_EQ(streamID, header.stream);
679  ASSERT_EQ(controlStream, outExAttributes.controlStream);
680  ASSERT_TRUE(PRIORITY & header.flags);
681  ASSERT_FALSE(END_STREAM & header.flags);
682  ASSERT_FALSE(END_HEADERS & header.flags);
683  ASSERT_FALSE(UNIDIRECTIONAL & header.flags);
684  ASSERT_FALSE(outExAttributes.unidirectional);
685  ASSERT_EQ(0, priority->streamDependency);
686  ASSERT_TRUE(priority->exclusive);
687  ASSERT_EQ(12, priority->weight);
688  EXPECT_EQ(outBuf->moveToFbString(), body->moveToFbString());
689 }
690 
691 TEST_F(HTTP2FramerTest, ExHeadersWithFlagsSet) {
692  auto body = makeBuf(500);
693  uint32_t streamID = folly::Random::rand32(10, 1024) * 2 + 1;
694  uint32_t controlStream = streamID - 2;
695  writeExHeaders(queue_, body->clone(), streamID,
696  HTTPCodec::ExAttributes(controlStream, true),
697  folly::none, 0, true, true);
698 
699  FrameHeader header;
700  HTTPCodec::ExAttributes outExAttributes;
702  std::unique_ptr<IOBuf> outBuf;
703  parse(&parseExHeaders, header, outExAttributes, priority, outBuf);
704 
705  ASSERT_EQ(FrameType::EX_HEADERS, header.type);
706  ASSERT_EQ(streamID, header.stream);
707  ASSERT_EQ(controlStream, outExAttributes.controlStream);
708  ASSERT_FALSE(PRIORITY & header.flags);
709  ASSERT_TRUE(END_STREAM & header.flags);
710  ASSERT_TRUE(END_HEADERS & header.flags);
711  ASSERT_TRUE(UNIDIRECTIONAL & header.flags);
712  ASSERT_TRUE(outExAttributes.unidirectional);
713  EXPECT_EQ(outBuf->moveToFbString(), body->moveToFbString());
714 }
size_t parse(const char *buf, size_t len)
Definition: test.c:1591
ErrorCode parseAltSvc(Cursor &cursor, const FrameHeader &header, uint32_t &outMaxAge, uint32_t &outPort, std::string &outProtocol, std::string &outHost, std::string &outOrigin) noexcept
ErrorCode parseContinuation(Cursor &cursor, const FrameHeader &header, std::unique_ptr< IOBuf > &outBuf) noexcept
flags
Definition: http_parser.h:127
size_t writePing(IOBufQueue &queue, uint64_t opaqueData, bool ack) noexcept
ErrorCode parsePushPromise(Cursor &cursor, const FrameHeader &header, uint32_t &outPromisedStream, std::unique_ptr< IOBuf > &outBuf) noexcept
ErrorCode parseFrameHeader(Cursor &cursor, FrameHeader &header) noexcept
const uint32_t kFramePrioritySize
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
ErrorCode parseGoaway(Cursor &cursor, const FrameHeader &header, uint32_t &outLastStreamID, ErrorCode &outCode, std::unique_ptr< IOBuf > &outDebugData) noexcept
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
void writeFrameHeaderManual(IOBufQueue &queue, uint32_t length, uint8_t type, uint8_t flags, uint32_t stream)
const uint32_t kFrameHeaderSize
StreamCodecFactory stream
size_t writeHeaders(IOBufQueue &queue, std::unique_ptr< IOBuf > headers, uint32_t stream, folly::Optional< PriorityUpdate > priority, folly::Optional< uint8_t > padding, bool endStream, bool endHeaders) noexcept
#define EXPECT_DEATH_NO_CORE(token, regex)
Definition: TestUtils.h:19
PskType type
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
fbstring moveToFbString()
Definition: IOBuf.cpp:968
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
ErrorCode parsePriority(Cursor &cursor, const FrameHeader &header, PriorityUpdate &outPriority) noexcept
ErrorCode parseSettings(Cursor &cursor, const FrameHeader &header, std::deque< SettingPair > &settings) noexcept
STL namespace.
const uint32_t kMaxFramePayloadLength
size_t writePushPromise(IOBufQueue &queue, uint32_t associatedStream, uint32_t promisedStream, std::unique_ptr< IOBuf > headers, folly::Optional< uint8_t > padding, bool endHeaders) noexcept
static http_parser_settings settings
Definition: test.c:1529
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
std::unique_ptr< IOBuf > clone() const
Definition: IOBuf.cpp:527
ErrorCode parseWindowUpdate(Cursor &cursor, const FrameHeader &header, uint32_t &outAmount) noexcept
size_t writeContinuation(IOBufQueue &queue, uint32_t stream, bool endHeaders, std::unique_ptr< IOBuf > headers) noexcept
ErrorCode parseCertificateRequest(folly::io::Cursor &cursor, const FrameHeader &header, uint16_t &outRequestId, std::unique_ptr< folly::IOBuf > &outAuthRequest) noexcept
size_t writeSettings(IOBufQueue &queue, const std::deque< SettingPair > &settings)
const uint32_t kFrameCertificateSizeBase
std::unique_ptr< folly::IOBuf > makeBuf(uint32_t size)
Definition: ZlibTests.cpp:26
folly::Optional< uint8_t > Padding
Definition: HTTP2Framer.h:30
static Options cacheChainLength()
Definition: IOBufQueue.h:83
ErrorCode parseExHeaders(Cursor &cursor, const FrameHeader &header, HTTPCodec::ExAttributes &outExAttributes, folly::Optional< PriorityUpdate > &outPriority, std::unique_ptr< IOBuf > &outBuf) noexcept
const uint32_t kFrameCertificateRequestSizeBase
size_t writePriority(IOBufQueue &queue, uint32_t stream, PriorityUpdate priority) noexcept
void parse(ParseFunc &&parseFn, FrameHeader &outHeader, Args &&...outArgs)
const uint32_t kFrameGoawaySize
size_t writeCertificate(folly::IOBufQueue &writeBuf, uint16_t certId, std::unique_ptr< folly::IOBuf > authenticator, bool toBeContinued)
ErrorCode parseRstStream(Cursor &cursor, const FrameHeader &header, ErrorCode &outCode) noexcept
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
void parse(const IOBuf *data, ParseFunc &&parseFn, FrameHeader &outHeader, Args &&...outArgs)
ErrorCode parseCertificate(folly::io::Cursor &cursor, const FrameHeader &header, uint16_t &outCertId, std::unique_ptr< folly::IOBuf > &outAuthenticator) noexcept
size_t writeAltSvc(IOBufQueue &queue, uint32_t stream, uint32_t maxAge, uint16_t port, StringPiece protocol, StringPiece host, StringPiece origin) noexcept
size_t writeCertificateRequest(folly::IOBufQueue &writeBuf, uint16_t requestId, std::unique_ptr< folly::IOBuf > authRequest)
TEST_F(AsyncSSLSocketWriteTest, write_coalescing1)
ErrorCode parseHeaders(Cursor &cursor, const FrameHeader &header, folly::Optional< PriorityUpdate > &outPriority, std::unique_ptr< IOBuf > &outBuf) noexcept
size_t writeSettingsAck(IOBufQueue &queue)
std::size_t computeChainDataLength() const
Definition: IOBuf.cpp:501
void dataFrameTest(IOBuf *body, uint32_t dataLen, folly::Optional< uint8_t > padLen)
size_t writeRstStream(IOBufQueue &queue, uint32_t stream, ErrorCode errorCode) noexcept
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
size_t writeExHeaders(IOBufQueue &queue, std::unique_ptr< IOBuf > headers, uint32_t stream, const HTTPCodec::ExAttributes &exAttributes, const folly::Optional< PriorityUpdate > &priority, const folly::Optional< uint8_t > &padding, bool endStream, bool endHeaders) noexcept
size_t writeGoaway(IOBufQueue &queue, uint32_t lastStreamID, ErrorCode errorCode, std::unique_ptr< IOBuf > debugData) noexcept
const Padding kNoPadding
Definition: HTTP2Framer.cpp:20
#define ASSERT_FALSE(condition)
Definition: gtest.h:1868
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
void dataFrameTest(uint32_t dataLen, folly::Optional< uint8_t > padLen)
static uint32_t rand32()
Definition: Random.h:213
#define EXPECT_LT(val1, val2)
Definition: gtest.h:1930
static uint64_t rand64()
Definition: Random.h:263
ErrorCode parseData(Cursor &cursor, const FrameHeader &header, std::unique_ptr< IOBuf > &outBuf, uint16_t &outPadding) noexcept
size_t writeData(IOBufQueue &queue, std::unique_ptr< IOBuf > data, uint32_t stream, folly::Optional< uint8_t > padding, bool endStream, bool reuseIOBufHeadroom) noexcept
#define ASSERT_TRUE(condition)
Definition: gtest.h:1865
uint32_t streamID
Definition: SPDYCodec.cpp:131
size_t writeWindowUpdate(IOBufQueue &queue, uint32_t stream, uint32_t amount) noexcept
const uint32_t kFrameRstStreamSize
constexpr None none
Definition: Optional.h:87
ErrorCode parsePing(Cursor &cursor, const FrameHeader &header, uint64_t &outOpaqueData) noexcept
void writeBE(T value)
Definition: Cursor.h:744