proxygen
HTTP2CodecTest.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  */
12 #include <folly/io/Cursor.h>
17 
20 #include <random>
21 
22 using namespace proxygen;
23 using namespace proxygen::compress;
24 using namespace folly;
25 using namespace folly::io;
26 using namespace std;
27 using namespace testing;
28 
29 TEST(HTTP2CodecConstantsTest, HTTPContantsAreCommonHeaders) {
30  // The purpose of this test is to verify some basic assumptions that should
31  // never change but to make clear that the following http2 header constants
32  // map to the respective common headers. Should this test ever fail, the
33  // H2Codec would need to be updated in the corresponding places when creating
34  // compress/Header objects.
41  EXPECT_EQ(
46 }
47 
49  public:
50 
52  :HTTPParallelCodecTest(upstreamCodec_, downstreamCodec_) {}
53 
54  void SetUp() override {
56  }
57  void testHeaderListSize(bool oversized);
58  void testFrameSizeLimit(bool oversized);
59 
60  protected:
63 };
64 
65 TEST_F(HTTP2CodecTest, IgnoreUnknownSettings) {
66  auto numSettings = downstreamCodec_.getIngressSettings()->getNumSettings();
67  std::deque<SettingPair> settings;
68  for (uint32_t i = 200; i < (200 + 1024); i++) {
69  settings.push_back(SettingPair(SettingsId(i), i));
70  }
71  http2::writeSettings(output_, settings);
72  parse();
73 
74  EXPECT_EQ(callbacks_.settings, 1);
75  EXPECT_EQ(callbacks_.sessionErrors, 0);
76  EXPECT_EQ(numSettings,
77  downstreamCodec_.getIngressSettings()->getNumSettings());
78 }
79 
80 TEST_F(HTTP2CodecTest, NoExHeaders) {
81  // do not emit ENABLE_EX_HEADERS setting, if disabled
82  SetUpUpstreamTest();
83 
84  EXPECT_EQ(callbacks_.settings, 0);
85  EXPECT_EQ(callbacks_.numSettings, 0);
86  EXPECT_EQ(false, downstreamCodec_.supportsExTransactions());
87 
88  parseUpstream();
89 
90  EXPECT_EQ(callbacks_.settings, 1);
91  // only 3 standard settings: HEADER_TABLE_SIZE, ENABLE_PUSH, MAX_FRAME_SIZE.
92  EXPECT_EQ(callbacks_.numSettings, 3);
93  EXPECT_EQ(false, downstreamCodec_.supportsExTransactions());
94 }
95 
96 TEST_F(HTTP2CodecTest, IgnoreExHeadersSetting) {
97  // disable EX_HEADERS on egress
98  downstreamCodec_.getEgressSettings()->setSetting(
100  auto ptr = downstreamCodec_.getEgressSettings()->getSetting(
102  EXPECT_EQ(0, ptr->value);
103 
104  ptr = downstreamCodec_.getIngressSettings()->getSetting(
106  EXPECT_EQ(nullptr, ptr);
107  EXPECT_EQ(false, downstreamCodec_.supportsExTransactions());
108 
109  // attempt to enable EX_HEADERS on ingress
110  http2::writeSettings(output_,
112  parse();
113 
114  EXPECT_EQ(callbacks_.settings, 1);
115  EXPECT_EQ(callbacks_.sessionErrors, 0);
116  ptr = downstreamCodec_.getIngressSettings()->getSetting(
118  EXPECT_EQ(nullptr, ptr);
119  EXPECT_EQ(false, downstreamCodec_.supportsExTransactions());
120 
121  // attempt to disable EX_HEADERS on ingress
122  callbacks_.reset();
123  http2::writeSettings(output_,
125  parse();
126 
127  EXPECT_EQ(callbacks_.settings, 1);
128  EXPECT_EQ(callbacks_.sessionErrors, 0);
129  ptr = downstreamCodec_.getIngressSettings()->getSetting(
131  EXPECT_EQ(nullptr, ptr);
132  EXPECT_EQ(false, downstreamCodec_.supportsExTransactions());
133 }
134 
135 TEST_F(HTTP2CodecTest, EnableExHeadersSetting) {
136  // enable EX_HEADERS on egress
137  downstreamCodec_.getEgressSettings()->setSetting(
139 
140  auto ptr = downstreamCodec_.getEgressSettings()->getSetting(
142  EXPECT_EQ(1, ptr->value);
143 
144  ptr = downstreamCodec_.getIngressSettings()->getSetting(
146  EXPECT_EQ(nullptr, ptr);
147  EXPECT_EQ(false, downstreamCodec_.supportsExTransactions());
148 
149  // attempt to enable EX_HEADERS on ingress
150  http2::writeSettings(output_,
152  parse();
153 
154  EXPECT_EQ(callbacks_.settings, 1);
155  EXPECT_EQ(callbacks_.sessionErrors, 0);
156  ptr = downstreamCodec_.getIngressSettings()->getSetting(
158  EXPECT_EQ(1, ptr->value);
159  EXPECT_EQ(true, downstreamCodec_.supportsExTransactions());
160 
161  // attempt to disable EX_HEADERS on ingress
162  callbacks_.reset();
163  http2::writeSettings(output_,
165  parse();
166 
167  EXPECT_EQ(callbacks_.settings, 1);
168  EXPECT_EQ(callbacks_.sessionErrors, 0);
169  ptr = downstreamCodec_.getIngressSettings()->getSetting(
171  EXPECT_EQ(0, ptr->value);
172  EXPECT_EQ(false, downstreamCodec_.supportsExTransactions());
173 }
174 
175 TEST_F(HTTP2CodecTest, InvalidExHeadersSetting) {
176  // enable EX_HEADERS on egress
177  downstreamCodec_.getEgressSettings()->setSetting(
179 
180  // attempt to set a invalid ENABLE_EX_HEADERS value
181  http2::writeSettings(output_,
183  parse();
184 
185  EXPECT_EQ(callbacks_.sessionErrors, 1);
186 }
187 
188 TEST_F(HTTP2CodecTest, BasicHeader) {
189  HTTPMessage req = getGetRequest("/guacamole");
190  req.getHeaders().add(HTTP_HEADER_USER_AGENT, "coolio");
191  req.getHeaders().add("tab-hdr", "coolio\tv2");
192  // Connection header will get dropped
193  req.getHeaders().add(HTTP_HEADER_CONNECTION, "Love");
194  req.setSecure(true);
195  upstreamCodec_.generateHeader(output_, 1, req, true /* eom */);
196 
197  parse();
198  callbacks_.expectMessage(true, 3, "/guacamole");
199  EXPECT_TRUE(callbacks_.msg->isSecure());
200  const auto& headers = callbacks_.msg->getHeaders();
201  EXPECT_EQ("coolio", headers.getSingleOrEmpty(HTTP_HEADER_USER_AGENT));
202  EXPECT_EQ("coolio\tv2", headers.getSingleOrEmpty("tab-hdr"));
203  EXPECT_EQ("www.foo.com", headers.getSingleOrEmpty(HTTP_HEADER_HOST));
204 }
205 
206 TEST_F(HTTP2CodecTest, RequestFromServer) {
207  // this is to test EX_HEADERS frame, which carrys the HTTP request initiated
208  // by server side
209  upstreamCodec_.getEgressSettings()->setSetting(
211  SetUpUpstreamTest();
214 
215  HTTPMessage req = getGetRequest("/guacamole");
216  req.getHeaders().add(HTTP_HEADER_USER_AGENT, "coolio");
217  req.getHeaders().add("tab-hdr", "coolio\tv2");
218  // Connection header will get dropped
219  req.getHeaders().add(HTTP_HEADER_CONNECTION, "Love");
220  req.setSecure(true);
221 
223  HTTPCodec::StreamID controlStream = folly::Random::rand32(10, 1024) * 2 + 1;
224  upstreamCodec_.generateExHeader(output_, stream, req,
225  HTTPCodec::ExAttributes(controlStream, true),
226  true);
227 
228  parseUpstream();
229  EXPECT_EQ(controlStream, callbacks_.controlStreamId);
230  EXPECT_TRUE(callbacks_.isUnidirectional);
231  callbacks_.expectMessage(true, 3, "/guacamole");
232  EXPECT_TRUE(callbacks_.msg->isSecure());
233  const auto& headers = callbacks_.msg->getHeaders();
234  EXPECT_EQ("coolio", headers.getSingleOrEmpty(HTTP_HEADER_USER_AGENT));
235  EXPECT_EQ("coolio\tv2", headers.getSingleOrEmpty("tab-hdr"));
236  EXPECT_EQ("www.foo.com", headers.getSingleOrEmpty(HTTP_HEADER_HOST));
237 }
238 
239 TEST_F(HTTP2CodecTest, ResponseFromClient) {
240  // this is to test EX_HEADERS frame, which carrys the HTTP response replied by
241  // client side
242  downstreamCodec_.getEgressSettings()->setSetting(
246 
247  HTTPMessage resp;
248  resp.setStatusCode(200);
249  resp.setStatusMessage("nifty-nice");
250  resp.getHeaders().add(HTTP_HEADER_CONTENT_TYPE, "x-coolio");
251 
253  HTTPCodec::StreamID controlStream = folly::Random::rand32(10, 1024) * 2 + 1;
254  downstreamCodec_.generateExHeader(output_, stream, resp,
255  HTTPCodec::ExAttributes(controlStream, true), true);
256 
257  parse();
258  EXPECT_EQ(controlStream, callbacks_.controlStreamId);
259  EXPECT_TRUE(callbacks_.isUnidirectional);
260  EXPECT_EQ("OK", callbacks_.msg->getStatusMessage());
261  callbacks_.expectMessage(true, 2, 200);
262  const auto& headers = callbacks_.msg->getHeaders();
263  EXPECT_EQ("OK", callbacks_.msg->getStatusMessage());
264  EXPECT_TRUE(callbacks_.msg->getHeaders().exists(HTTP_HEADER_DATE));
265  EXPECT_EQ("x-coolio", headers.getSingleOrEmpty(HTTP_HEADER_CONTENT_TYPE));
266 }
267 
268 TEST_F(HTTP2CodecTest, ExHeadersWithPriority) {
269  downstreamCodec_.getEgressSettings()->setSetting(
273 
274  auto req = getGetRequest();
275  auto pri = HTTPMessage::HTTPPriority(0, false, 7);
276  req.setHTTP2Priority(pri);
277  upstreamCodec_.generateExHeader(output_, 3, req,
278  HTTPCodec::ExAttributes(1, true));
279 
280  parse();
281  EXPECT_EQ(callbacks_.msg->getHTTP2Priority(), pri);
282  EXPECT_EQ(callbacks_.streamErrors, 0);
283  EXPECT_EQ(callbacks_.sessionErrors, 0);
284 }
285 
286 TEST_F(HTTP2CodecTest, IgnoreExHeadersIfNotEnabled) {
287  downstreamCodec_.getEgressSettings()->setSetting(
289 
290  HTTPMessage req = getGetRequest("/guacamole");
291  downstreamCodec_.generateExHeader(output_, 3, req,
292  HTTPCodec::ExAttributes(1, true));
293 
294  parse();
295  EXPECT_EQ(callbacks_.streamErrors, 0);
296  EXPECT_EQ(callbacks_.sessionErrors, 0);
297 }
298 
299 TEST_F(HTTP2CodecTest, BadHeaders) {
300  static const std::string v1("GET");
301  static const std::string v2("/");
302  static const std::string v3("http");
303  static const std::string v4("foo.com");
304  static const vector<proxygen::compress::Header> reqHeaders = {
309  };
310 
313  // missing fields (missing authority is OK)
314  for (size_t i = 0; i < reqHeaders.size(); i++, stream += 2) {
315  std::vector<proxygen::compress::Header> allHeaders = reqHeaders;
316  allHeaders.erase(allHeaders.begin() + i);
317  auto encodedHeaders = headerCodec.encode(allHeaders);
318  http2::writeHeaders(output_,
319  std::move(encodedHeaders),
320  stream,
321  folly::none,
323  true,
324  true);
325  }
326  // dup fields
327  std::string v("foomonkey");
328  for (size_t i = 0; i < reqHeaders.size(); i++, stream += 2) {
329  std::vector<proxygen::compress::Header> allHeaders = reqHeaders;
330  auto h = allHeaders[i];
331  h.value = &v;
332  allHeaders.push_back(h);
333  auto encodedHeaders = headerCodec.encode(allHeaders);
334  http2::writeHeaders(output_,
335  std::move(encodedHeaders),
336  stream,
337  folly::none,
339  true,
340  true);
341  }
342 
343  parse();
344  EXPECT_EQ(callbacks_.messageBegin, 1);
345  EXPECT_EQ(callbacks_.headersComplete, 1);
346  EXPECT_EQ(callbacks_.messageComplete, 1);
347  EXPECT_EQ(callbacks_.streamErrors, 7);
348  EXPECT_EQ(callbacks_.sessionErrors, 0);
349 }
350 
351 TEST_F(HTTP2CodecTest, BadPseudoHeaders) {
352  static const std::string v1("POST");
353  static const std::string v2("http");
354  static const std::string n3("foo");
355  static const std::string v3("bar");
356  static const std::string v4("/");
357  static const vector<proxygen::compress::Header> reqHeaders = {
362  };
363 
366  std::vector<proxygen::compress::Header> allHeaders = reqHeaders;
367  auto encodedHeaders = headerCodec.encode(allHeaders);
368  http2::writeHeaders(output_,
369  std::move(encodedHeaders),
370  stream,
371  folly::none,
373  true,
374  true);
375 
376  parse();
377  EXPECT_EQ(callbacks_.messageBegin, 0);
378  EXPECT_EQ(callbacks_.headersComplete, 0);
379  EXPECT_EQ(callbacks_.messageComplete, 0);
380  EXPECT_EQ(callbacks_.streamErrors, 1);
381  EXPECT_EQ(callbacks_.sessionErrors, 0);
382 }
383 
384 TEST_F(HTTP2CodecTest, BadHeaderValues) {
385  static const std::string v1("--1");
386  static const std::string v2("\13\10protocol-attack");
387  static const std::string v3("\13");
388  static const std::string v4("abc.com\\13\\10");
389  static const vector<proxygen::compress::Header> reqHeaders = {
394  };
395 
398  for (size_t i = 0; i < reqHeaders.size(); i++, stream += 2) {
399  std::vector<proxygen::compress::Header> allHeaders;
400  allHeaders.push_back(reqHeaders[i]);
401  auto encodedHeaders = headerCodec.encode(allHeaders);
402  http2::writeHeaders(output_,
403  std::move(encodedHeaders),
404  stream,
405  folly::none,
407  true,
408  true);
409  }
410 
411  parse();
412  EXPECT_EQ(callbacks_.messageBegin, 0);
413  EXPECT_EQ(callbacks_.headersComplete, 0);
414  EXPECT_EQ(callbacks_.messageComplete, 0);
415  EXPECT_EQ(callbacks_.streamErrors, 4);
416  EXPECT_EQ(callbacks_.sessionErrors, 0);
417 }
418 
423  0x00, 0x00, 0x1d, 0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x82,
424  0x87, 0x44, 0x87, 0x62, 0x6b, 0x46, 0x41, 0xd2, 0x7a, 0x0b,
425  0x41, 0x89, 0xf1, 0xe3, 0xc2, 0xf2, 0x9c, 0xeb, 0x90, 0xf4,
426  0xff, 0x40, 0x80, 0x84, 0x2d, 0x35, 0xa7, 0xd7
427 };
428 
429 TEST_F(HTTP2CodecTest, EmptyHeaderName) {
430  output_.append(IOBuf::copyBuffer(kBufEmptyHeader, sizeof(kBufEmptyHeader)));
431  parse();
432  EXPECT_EQ(callbacks_.messageBegin, 0);
433  EXPECT_EQ(callbacks_.headersComplete, 0);
434  EXPECT_EQ(callbacks_.messageComplete, 0);
435  EXPECT_EQ(callbacks_.streamErrors, 1);
436  EXPECT_EQ(callbacks_.sessionErrors, 0);
437 }
438 
439 TEST_F(HTTP2CodecTest, BasicConnect) {
440  std::string authority = "myhost:1234";
441  HTTPMessage request;
443  request.getHeaders().add(proxygen::HTTP_HEADER_HOST, authority);
444  upstreamCodec_.generateHeader(output_, 1, request, false /* eom */);
445 
446  parse();
447  callbacks_.expectMessage(false, 1, "");
448  EXPECT_EQ(HTTPMethod::CONNECT, callbacks_.msg->getMethod());
449  const auto& headers = callbacks_.msg->getHeaders();
450  EXPECT_EQ(authority, headers.getSingleOrEmpty(proxygen::HTTP_HEADER_HOST));
451 }
452 
453 TEST_F(HTTP2CodecTest, BadConnect) {
454  std::string v1 = "CONNECT";
455  std::string v2 = "somehost:576";
456  std::vector<proxygen::compress::Header> goodHeaders = {
459  };
460 
461  // See https://tools.ietf.org/html/rfc7540#section-8.3
462  std::string v3 = "/foobar";
463  std::vector<proxygen::compress::Header> badHeaders = {
466  };
467 
470 
471  for (size_t i = 0; i < badHeaders.size(); i++, stream += 2) {
472  auto allHeaders = goodHeaders;
473  allHeaders.push_back(badHeaders[i]);
474  auto encodedHeaders = headerCodec.encode(allHeaders);
475  http2::writeHeaders(output_,
476  std::move(encodedHeaders),
477  stream,
478  folly::none,
480  true,
481  true);
482  }
483 
484  parse();
485  EXPECT_EQ(callbacks_.messageBegin, 0);
486  EXPECT_EQ(callbacks_.headersComplete, 0);
487  EXPECT_EQ(callbacks_.messageComplete, 0);
488  EXPECT_EQ(callbacks_.streamErrors, badHeaders.size());
489  EXPECT_EQ(callbacks_.sessionErrors, 0);
490 }
491 
493  if (oversized) {
494  auto settings = downstreamCodec_.getEgressSettings();
496  }
497 
498  HTTPMessage req = getGetRequest("/guacamole");
499  req.getHeaders().add(HTTP_HEADER_USER_AGENT, "coolio");
500  req.getHeaders().add("x-long-long-header",
501  "supercalafragalisticexpialadoshus");
502  upstreamCodec_.generateHeader(output_, 1, req, true /* eom */);
503 
504  parse();
505  // session error
506  EXPECT_EQ(callbacks_.messageBegin, oversized ? 0 : 1);
507  EXPECT_EQ(callbacks_.headersComplete, oversized ? 0 : 1);
508  EXPECT_EQ(callbacks_.messageComplete, oversized ? 0 : 1);
509  EXPECT_EQ(callbacks_.streamErrors, 0);
510  EXPECT_EQ(callbacks_.sessionErrors, oversized ? 1 : 0);
511 }
512 
514  HTTPMessage req = getBigGetRequest("/guacamole");
515  auto settings = downstreamCodec_.getEgressSettings();
516 
517  parse(); // consume preface
518  if (oversized) {
519  // trick upstream for sending a 2x bigger HEADERS frame
522  downstreamCodec_.generateSettings(output_);
523  parseUpstream();
524  }
525 
528  upstreamCodec_.generateHeader(output_, 1, req, true /* eom */);
529 
530  parse();
531  // session error
532  EXPECT_EQ(callbacks_.messageBegin, oversized ? 0 : 1);
533  EXPECT_EQ(callbacks_.headersComplete, oversized ? 0 : 1);
534  EXPECT_EQ(callbacks_.messageComplete, oversized ? 0 : 1);
535  EXPECT_EQ(callbacks_.streamErrors, 0);
536  EXPECT_EQ(callbacks_.sessionErrors, oversized ? 1 : 0);
537 }
538 
539 TEST_F(HTTP2CodecTest, NormalSizeHeader) {
540  testHeaderListSize(false);
541 }
542 
543 TEST_F(HTTP2CodecTest, OversizedHeader) {
544  testHeaderListSize(true);
545 }
546 
547 TEST_F(HTTP2CodecTest, NormalSizeFrame) {
548  testFrameSizeLimit(false);
549 }
550 
551 TEST_F(HTTP2CodecTest, OversizedFrame) {
552  testFrameSizeLimit(true);
553 }
554 
555 TEST_F(HTTP2CodecTest, BigHeaderCompressed) {
556  SetUpUpstreamTest();
557  auto settings = downstreamCodec_.getEgressSettings();
559  downstreamCodec_.generateSettings(output_);
560  parseUpstream();
561 
562  SetUp();
563  HTTPMessage req = getGetRequest("/guacamole");
564  req.getHeaders().add(HTTP_HEADER_USER_AGENT, "coolio");
565  upstreamCodec_.generateHeader(output_, 1, req, true /* eom */);
566 
567  parse();
568  // session error
569  EXPECT_EQ(callbacks_.messageBegin, 0);
570  EXPECT_EQ(callbacks_.headersComplete, 0);
571  EXPECT_EQ(callbacks_.messageComplete, 0);
572  EXPECT_EQ(callbacks_.streamErrors, 0);
573  EXPECT_EQ(callbacks_.sessionErrors, 1);
574 }
575 
576 
577 TEST_F(HTTP2CodecTest, BasicHeaderReply) {
578  SetUpUpstreamTest();
579  HTTPMessage resp;
580  resp.setStatusCode(200);
581  resp.setStatusMessage("nifty-nice");
582  resp.getHeaders().add(HTTP_HEADER_CONTENT_TYPE, "x-coolio");
583  downstreamCodec_.generateHeader(output_, 1, resp);
584  downstreamCodec_.generateEOM(output_, 1);
585 
586  parseUpstream();
587  callbacks_.expectMessage(true, 2, 200);
588  const auto& headers = callbacks_.msg->getHeaders();
589  // HTTP/2 doesnt support serialization - instead you get the default
590  EXPECT_EQ("OK", callbacks_.msg->getStatusMessage());
591  EXPECT_TRUE(callbacks_.msg->getHeaders().exists(HTTP_HEADER_DATE));
592  EXPECT_EQ("x-coolio", headers.getSingleOrEmpty(HTTP_HEADER_CONTENT_TYPE));
593 }
594 
595 TEST_F(HTTP2CodecTest, BadHeadersReply) {
596  static const std::string v1("200");
597  static const vector<proxygen::compress::Header> respHeaders = {
599  };
600 
603  // missing fields (missing authority is OK)
604  for (size_t i = 0; i < respHeaders.size(); i++, stream += 2) {
605  std::vector<proxygen::compress::Header> allHeaders = respHeaders;
606  allHeaders.erase(allHeaders.begin() + i);
607  auto encodedHeaders = headerCodec.encode(allHeaders);
608  http2::writeHeaders(output_,
609  std::move(encodedHeaders),
610  stream,
611  folly::none,
613  true,
614  true);
615  }
616  // dup fields
617  std::string v("foomonkey");
618  for (size_t i = 0; i < respHeaders.size(); i++, stream += 2) {
619  std::vector<proxygen::compress::Header> allHeaders = respHeaders;
620  auto h = allHeaders[i];
621  h.value = &v;
622  allHeaders.push_back(h);
623  auto encodedHeaders = headerCodec.encode(allHeaders);
624  http2::writeHeaders(output_,
625  std::move(encodedHeaders),
626  stream,
627  folly::none,
629  true,
630  true);
631  }
632 
633  parse();
634  EXPECT_EQ(callbacks_.messageBegin, 0);
635  EXPECT_EQ(callbacks_.headersComplete, 0);
636  EXPECT_EQ(callbacks_.messageComplete, 0);
637  EXPECT_EQ(callbacks_.streamErrors, 2);
638  EXPECT_EQ(callbacks_.sessionErrors, 0);
639 }
640 
642  HTTPMessage req = getGetRequest("/guacamole");
643  req.getHeaders().add("Cookie", "chocolate-chip=1");
644  req.getHeaders().add("Cookie", "rainbow-chip=2");
645  req.getHeaders().add("Cookie", "butterscotch=3");
646  req.getHeaders().add("Cookie", "oatmeal-raisin=4");
647  req.setSecure(true);
648  upstreamCodec_.generateHeader(output_, 1, req);
649 
650  parse();
651  callbacks_.expectMessage(false, 2, "/guacamole");
652  EXPECT_EQ(callbacks_.msg->getCookie("chocolate-chip"), "1");
653  EXPECT_EQ(callbacks_.msg->getCookie("rainbow-chip"), "2");
654  EXPECT_EQ(callbacks_.msg->getCookie("butterscotch"), "3");
655  EXPECT_EQ(callbacks_.msg->getCookie("oatmeal-raisin"), "4");
656 }
657 
658 TEST_F(HTTP2CodecTest, BasicContinuation) {
660  upstreamCodec_.generateHeader(output_, 1, req);
661 
662  parse();
663  callbacks_.expectMessage(false, -1, "/");
664 #ifndef NDEBUG
665  EXPECT_GT(downstreamCodec_.getReceivedFrameCount(), 1);
666 #endif
667  const auto& headers = callbacks_.msg->getHeaders();
668  EXPECT_EQ("coolio", headers.getSingleOrEmpty(HTTP_HEADER_USER_AGENT));
669  EXPECT_EQ(callbacks_.messageBegin, 1);
670  EXPECT_EQ(callbacks_.headersComplete, 1);
671  EXPECT_EQ(callbacks_.messageComplete, 0);
672  EXPECT_EQ(callbacks_.streamErrors, 0);
673  EXPECT_EQ(callbacks_.sessionErrors, 0);
674 }
675 
676 TEST_F(HTTP2CodecTest, BasicContinuationEndStream) {
677  // CONTINUATION with END_STREAM flag set on the preceding HEADERS frame
679  upstreamCodec_.generateHeader(output_, 1, req, true /* eom */);
680 
681  parse();
682  callbacks_.expectMessage(true, -1, "/");
683 #ifndef NDEBUG
684  EXPECT_GT(downstreamCodec_.getReceivedFrameCount(), 1);
685 #endif
686  const auto& headers = callbacks_.msg->getHeaders();
687  EXPECT_EQ("coolio", headers.getSingleOrEmpty(HTTP_HEADER_USER_AGENT));
688  EXPECT_EQ(callbacks_.messageBegin, 1);
689  EXPECT_EQ(callbacks_.headersComplete, 1);
690  EXPECT_EQ(callbacks_.messageComplete, 1);
691  EXPECT_EQ(callbacks_.streamErrors, 0);
692  EXPECT_EQ(callbacks_.sessionErrors, 0);
693 }
694 
695 TEST_F(HTTP2CodecTest, BadContinuation) {
696  // CONTINUATION with no preceding HEADERS
697  auto fakeHeaders = makeBuf(5);
698  http2::writeContinuation(output_, 3, true, std::move(fakeHeaders));
699 
700  parse();
701  EXPECT_EQ(callbacks_.messageBegin, 0);
702  EXPECT_EQ(callbacks_.headersComplete, 0);
703  EXPECT_EQ(callbacks_.messageComplete, 0);
704  EXPECT_EQ(callbacks_.streamErrors, 0);
705  EXPECT_EQ(callbacks_.sessionErrors, 1);
706 }
707 
708 TEST_F(HTTP2CodecTest, MissingContinuation) {
709  IOBufQueue output(IOBufQueue::cacheChainLength());
711 
712  upstreamCodec_.generateHeader(output_, 1, req);
713  // empirically determined the size of continuation frame, and strip it
714  output_.trimEnd(http2::kFrameHeaderSize + 4134);
715 
716  // insert a non-continuation (but otherwise valid) frame
718 
719  parse();
720  EXPECT_EQ(callbacks_.messageBegin, 0);
721  EXPECT_EQ(callbacks_.headersComplete, 0);
722  EXPECT_EQ(callbacks_.messageComplete, 0);
723  EXPECT_EQ(callbacks_.streamErrors, 0);
724  EXPECT_EQ(callbacks_.sessionErrors, 1);
725 #ifndef NDEBUG
726  EXPECT_EQ(downstreamCodec_.getReceivedFrameCount(), 2);
727 #endif
728 }
729 
730 TEST_F(HTTP2CodecTest, MissingContinuationBadFrame) {
731  IOBufQueue output(IOBufQueue::cacheChainLength());
733  upstreamCodec_.generateHeader(output_, 1, req);
734 
735  // empirically determined the size of continuation frame, and fake it
736  output_.trimEnd(http2::kFrameHeaderSize + 4134);
737 
738  // insert an invalid frame
739  auto frame = makeBuf(http2::kFrameHeaderSize + 4134);
740  *((uint32_t *)frame->writableData()) = 0xfa000000;
741  output_.append(std::move(frame));
742 
743  parse();
744  EXPECT_EQ(callbacks_.messageBegin, 0);
745  EXPECT_EQ(callbacks_.headersComplete, 0);
746  EXPECT_EQ(callbacks_.messageComplete, 0);
747  EXPECT_EQ(callbacks_.streamErrors, 0);
748  EXPECT_EQ(callbacks_.sessionErrors, 1);
749 #ifndef NDEBUG
750  EXPECT_EQ(downstreamCodec_.getReceivedFrameCount(), 2);
751 #endif
752 }
753 
754 TEST_F(HTTP2CodecTest, BadContinuationStream) {
756  upstreamCodec_.generateHeader(output_, 1, req);
757 
758  // empirically determined the size of continuation frame, and fake it
759  output_.trimEnd(http2::kFrameHeaderSize + 4134);
760  auto fakeHeaders = makeBuf(4134);
761  http2::writeContinuation(output_, 3, true, std::move(fakeHeaders));
762 
763  parse();
764  EXPECT_EQ(callbacks_.messageBegin, 0);
765  EXPECT_EQ(callbacks_.headersComplete, 0);
766  EXPECT_EQ(callbacks_.messageComplete, 0);
767  EXPECT_EQ(callbacks_.streamErrors, 0);
768  EXPECT_EQ(callbacks_.sessionErrors, 1);
769 #ifndef NDEBUG
770  EXPECT_EQ(downstreamCodec_.getReceivedFrameCount(), 2);
771 #endif
772 }
773 
774 TEST_F(HTTP2CodecTest, FrameTooLarge) {
775  writeFrameHeaderManual(output_, 1 << 15, 0, 0, 1);
776 
777  parse();
778  EXPECT_EQ(callbacks_.messageBegin, 0);
779  EXPECT_EQ(callbacks_.headersComplete, 0);
780  EXPECT_EQ(callbacks_.messageComplete, 0);
781  EXPECT_EQ(callbacks_.streamErrors, 0);
782  EXPECT_EQ(callbacks_.sessionErrors, 1);
783  EXPECT_TRUE(callbacks_.lastParseError->hasCodecStatusCode());
784  EXPECT_EQ(callbacks_.lastParseError->getCodecStatusCode(),
786 }
787 
788 TEST_F(HTTP2CodecTest, UnknownFrameType) {
789  HTTPMessage req = getGetRequest();
790  req.getHeaders().add(HTTP_HEADER_USER_AGENT, "coolio");
791 
792  // unknown frame type 17
793  writeFrameHeaderManual(output_, 17, 37, 0, 1);
794  output_.append("wicked awesome!!!");
795  upstreamCodec_.generateHeader(output_, 1, req);
796 
797  parse();
798  callbacks_.expectMessage(false, 2, ""); // + host
799 }
800 
801 TEST_F(HTTP2CodecTest, JunkAfterConnError) {
802  HTTPMessage req = getGetRequest();
803  req.getHeaders().add(HTTP_HEADER_USER_AGENT, "coolio");
804 
805  // write headers frame for stream 0
807  // now write a valid headers frame, should never be parsed
808  upstreamCodec_.generateHeader(output_, 1, req);
809 
810  parse();
811  EXPECT_EQ(callbacks_.messageBegin, 0);
812  EXPECT_EQ(callbacks_.headersComplete, 0);
813  EXPECT_EQ(callbacks_.messageComplete, 0);
814  EXPECT_EQ(callbacks_.streamErrors, 0);
815  EXPECT_EQ(callbacks_.sessionErrors, 1);
816 }
817 
818 TEST_F(HTTP2CodecTest, BasicData) {
819  string data("abcde");
820  auto buf = folly::IOBuf::copyBuffer(data.data(), data.length());
821  upstreamCodec_.generateBody(output_, 2, std::move(buf),
822  HTTPCodec::NoPadding, true);
823 
824  parse();
825  EXPECT_EQ(callbacks_.messageBegin, 0);
826  EXPECT_EQ(callbacks_.headersComplete, 0);
827  EXPECT_EQ(callbacks_.messageComplete, 1);
828  EXPECT_EQ(callbacks_.bodyCalls, 1);
829  EXPECT_EQ(callbacks_.bodyLength, 5);
830  EXPECT_EQ(callbacks_.streamErrors, 0);
831  EXPECT_EQ(callbacks_.sessionErrors, 0);
832  EXPECT_EQ(callbacks_.data.move()->moveToFbString(), data);
833 }
834 
835 TEST_F(HTTP2CodecTest, LongData) {
836  // Hack the max frame size artificially low
837  HTTPSettings* settings = (HTTPSettings*)upstreamCodec_.getIngressSettings();
838  settings->setSetting(SettingsId::MAX_FRAME_SIZE, 16);
839  auto buf = makeBuf(100);
840  upstreamCodec_.generateBody(output_, 1, buf->clone(), HTTPCodec::NoPadding,
841  true);
842 
843  parse();
844  EXPECT_EQ(callbacks_.messageBegin, 0);
845  EXPECT_EQ(callbacks_.headersComplete, 0);
846  EXPECT_EQ(callbacks_.messageComplete, 1);
847  EXPECT_EQ(callbacks_.bodyCalls, 7);
848  EXPECT_EQ(callbacks_.bodyLength, 100);
849  EXPECT_EQ(callbacks_.streamErrors, 0);
850  EXPECT_EQ(callbacks_.sessionErrors, 0);
851  EXPECT_EQ(callbacks_.data.move()->moveToFbString(), buf->moveToFbString());
852 }
853 
854 TEST_F(HTTP2CodecTest, MalformedPaddingLength) {
855  const uint8_t badInput[] = {0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54,
856  0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a,
857  0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a,
858  0x00, 0x00, 0x7e, 0x00, 0x6f, 0x6f, 0x6f, 0x6f,
859  // The padding length byte below is 0x82 (130
860  // in decimal) which is greater than the length
861  // specified by the header's length field, 126
862  0x01, 0x82, 0x87, 0x44, 0x87, 0x92, 0x97, 0x92,
863  0x92, 0x92, 0x7a, 0x0b, 0x41, 0x89, 0xf1, 0xe3,
864  0xc0, 0xf2, 0x9c, 0xdd, 0x90, 0xf4, 0xff, 0x40,
865  0x80, 0x84, 0x2d, 0x35, 0xa7, 0xd7};
866  output_.clear();
867  output_.append(badInput, sizeof(badInput));
868  EXPECT_EQ(output_.chainLength(), sizeof(badInput));
869 
870  EXPECT_FALSE(parse());
871 }
872 
873 TEST_F(HTTP2CodecTest, MalformedPadding) {
874  const uint8_t badInput[] = {
875  0x00, 0x00, 0x0d, 0x01, 0xbe, 0x63, 0x0d, 0x0a, 0x0d, 0x0a, 0x00, 0x73,
876  0x00, 0x00, 0x06, 0x08, 0x72, 0x00, 0x24, 0x00, 0xfa, 0x4d, 0x0d
877  };
878  output_.append(badInput, sizeof(badInput));
879 
880  EXPECT_FALSE(parse());
881 }
882 
883 TEST_F(HTTP2CodecTest, NoAppByte) {
884  const uint8_t noAppByte[] = {0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54,
885  0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a,
886  0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a,
887  0x00, 0x00, 0x56, 0x00, 0x5d, 0x00, 0x00, 0x00,
888  0x01, 0x55, 0x00};
889  output_.clear();
890  output_.append(noAppByte, sizeof(noAppByte));
891  EXPECT_EQ(output_.chainLength(), sizeof(noAppByte));
892 
893  EXPECT_TRUE(parse());
894  EXPECT_EQ(callbacks_.messageBegin, 0);
895  EXPECT_EQ(callbacks_.headersComplete, 0);
896  EXPECT_EQ(callbacks_.messageComplete, 0);
897  EXPECT_EQ(callbacks_.bodyCalls, 1);
898  EXPECT_EQ(callbacks_.bodyLength, 0);
899  EXPECT_EQ(callbacks_.streamErrors, 0);
900  EXPECT_EQ(callbacks_.sessionErrors, 0);
901 }
902 
903 TEST_F(HTTP2CodecTest, DataFramePartialDataOnFrameHeaderCall) {
904  using namespace testing;
905  NiceMock<MockHTTPCodecCallback> mockCallback;
906  EXPECT_CALL(mockCallback, onFrameHeader(_, _, _, _, _));
907 
908  const size_t bufSize = 10;
909  auto buf = makeBuf(bufSize);
910  const size_t padding = 10;
911  upstreamCodec_.generateBody(output_, 1, buf->clone(), padding, true);
912  EXPECT_EQ(output_.chainLength(), 54);
913 
914  downstreamCodec_.setCallback(&mockCallback);
915 
916  auto ingress = output_.move();
917  ingress->coalesce();
918  // Copy partial byte to a new buffer
919  auto ingress1 = IOBuf::copyBuffer(ingress->data(), 34);
920  downstreamCodec_.onIngress(*ingress1);
921 }
922 
923 TEST_F(HTTP2CodecTest, DataFramePartialDataWithNoAppByte) {
924  const size_t bufSize = 10;
925  auto buf = makeBuf(bufSize);
926  const size_t padding = 10;
927  upstreamCodec_.generateBody(output_, 1, buf->clone(), padding, true);
928  EXPECT_EQ(output_.chainLength(), 54);
929 
930  auto ingress = output_.move();
931  ingress->coalesce();
932  // Copy up to the padding length byte to a new buffer
933  auto ingress1 = IOBuf::copyBuffer(ingress->data(), 34);
934  size_t parsed = downstreamCodec_.onIngress(*ingress1);
935  // The 34th byte is the padding length byte which should not be parsed
936  EXPECT_EQ(parsed, 33);
937  // Copy from the padding length byte to the end
938  auto ingress2 = IOBuf::copyBuffer(ingress->data() + 33, 21);
939  parsed = downstreamCodec_.onIngress(*ingress2);
940  // The padding length byte should be parsed this time along with 10 bytes of
941  // application data and 10 bytes of padding
942  EXPECT_EQ(parsed, 21);
943 
944  EXPECT_EQ(callbacks_.messageBegin, 0);
945  EXPECT_EQ(callbacks_.headersComplete, 0);
946  EXPECT_EQ(callbacks_.messageComplete, 1);
947  EXPECT_EQ(callbacks_.bodyCalls, 1);
948  EXPECT_EQ(callbacks_.bodyLength, bufSize);
949  // Total padding is the padding length byte and the padding bytes
950  EXPECT_EQ(callbacks_.paddingBytes, padding + 1);
951  EXPECT_EQ(callbacks_.streamErrors, 0);
952  EXPECT_EQ(callbacks_.sessionErrors, 0);
953  EXPECT_EQ(callbacks_.data.move()->moveToFbString(), buf->moveToFbString());
954 }
955 
956 TEST_F(HTTP2CodecTest, BasicRst) {
957  upstreamCodec_.generateRstStream(output_, 2, ErrorCode::ENHANCE_YOUR_CALM);
958  parse();
959  EXPECT_EQ(callbacks_.messageBegin, 0);
960  EXPECT_EQ(callbacks_.headersComplete, 0);
961  EXPECT_EQ(callbacks_.messageComplete, 0);
962  EXPECT_EQ(callbacks_.bodyCalls, 0);
963  EXPECT_EQ(callbacks_.aborts, 1);
964  EXPECT_EQ(callbacks_.streamErrors, 0);
965  EXPECT_EQ(callbacks_.sessionErrors, 0);
966 }
967 
968 TEST_F(HTTP2CodecTest, BasicRstInvalidCode) {
969  upstreamCodec_.generateRstStream(output_, 2, ErrorCode::_SPDY_INVALID_STREAM);
970  parse();
971  EXPECT_EQ(callbacks_.messageBegin, 0);
972  EXPECT_EQ(callbacks_.headersComplete, 0);
973  EXPECT_EQ(callbacks_.messageComplete, 0);
974  EXPECT_EQ(callbacks_.bodyCalls, 0);
975  EXPECT_EQ(callbacks_.aborts, 1);
976  EXPECT_EQ(callbacks_.streamErrors, 0);
977  EXPECT_EQ(callbacks_.sessionErrors, 0);
978 }
979 
980 TEST_F(HTTP2CodecTest, BasicPing) {
981  upstreamCodec_.generatePingRequest(output_);
982  upstreamCodec_.generatePingReply(output_, 17);
983 
984  uint64_t pingReq;
985  parse([&] (IOBuf* ingress) {
986  folly::io::Cursor c(ingress);
988  pingReq = c.read<uint64_t>();
989  });
990 
991  EXPECT_EQ(callbacks_.messageBegin, 0);
992  EXPECT_EQ(callbacks_.headersComplete, 0);
993  EXPECT_EQ(callbacks_.messageComplete, 0);
994  EXPECT_EQ(callbacks_.bodyCalls, 0);
995  EXPECT_EQ(callbacks_.recvPingRequest, pingReq);
996  EXPECT_EQ(callbacks_.recvPingReply, 17);
997  EXPECT_EQ(callbacks_.streamErrors, 0);
998  EXPECT_EQ(callbacks_.sessionErrors, 0);
999 }
1000 
1001 TEST_F(HTTP2CodecTest, BasicWindow) {
1002  // This test would fail if the codec had window state
1003  upstreamCodec_.generateWindowUpdate(output_, 0, 10);
1004  upstreamCodec_.generateWindowUpdate(output_, 0, http2::kMaxWindowUpdateSize);
1005  upstreamCodec_.generateWindowUpdate(output_, 1, 12);
1006  upstreamCodec_.generateWindowUpdate(output_, 1, http2::kMaxWindowUpdateSize);
1007 
1008  parse();
1009  EXPECT_EQ(callbacks_.windowUpdateCalls, 4);
1010  EXPECT_EQ(callbacks_.windowUpdates[0],
1011  std::vector<uint32_t>({10, http2::kMaxWindowUpdateSize}));
1012  EXPECT_EQ(callbacks_.windowUpdates[1],
1013  std::vector<uint32_t>({12, http2::kMaxWindowUpdateSize}));
1014  EXPECT_EQ(callbacks_.streamErrors, 0);
1015  EXPECT_EQ(callbacks_.sessionErrors, 0);
1016 }
1017 
1018 TEST_F(HTTP2CodecTest, ZeroWindow) {
1019  auto streamID = HTTPCodec::StreamID(1);
1020  // First generate a frame with delta=1 so as to pass the checks, and then
1021  // hack the frame so that delta=0 without modifying other checks
1022  upstreamCodec_.generateWindowUpdate(output_, streamID, 1);
1023  output_.trimEnd(http2::kFrameWindowUpdateSize);
1024  QueueAppender appender(&output_, http2::kFrameWindowUpdateSize);
1025  appender.writeBE<uint32_t>(0);
1026 
1027  parse();
1028  // This test doesn't ensure that RST_STREAM is generated
1029  EXPECT_EQ(callbacks_.windowUpdateCalls, 0);
1030  EXPECT_EQ(callbacks_.streamErrors, 1);
1031  EXPECT_EQ(callbacks_.lastParseError->getCodecStatusCode(),
1033 }
1034 
1035 TEST_F(HTTP2CodecTest, BasicGoaway) {
1036  std::unique_ptr<folly::IOBuf> debugData =
1037  folly::IOBuf::copyBuffer("debugData");
1038  upstreamCodec_.generateGoaway(output_, 17, ErrorCode::ENHANCE_YOUR_CALM,
1039  std::move(debugData));
1040 
1041  parse();
1042  EXPECT_EQ(callbacks_.goaways, 1);
1043  EXPECT_EQ(callbacks_.data.move()->moveToFbString(), "debugData");
1044  EXPECT_EQ(callbacks_.streamErrors, 0);
1045  EXPECT_EQ(callbacks_.sessionErrors, 0);
1046 }
1047 
1048 TEST_F(HTTP2CodecTest, BadGoaway) {
1049  std::unique_ptr<folly::IOBuf> debugData =
1050  folly::IOBuf::copyBuffer("debugData");
1051  upstreamCodec_.generateGoaway(output_, 17, ErrorCode::ENHANCE_YOUR_CALM,
1052  std::move(debugData));
1053  EXPECT_DEATH_NO_CORE(upstreamCodec_.generateGoaway(
1054  output_, 27, ErrorCode::ENHANCE_YOUR_CALM), ".*");
1055 }
1056 
1057 TEST_F(HTTP2CodecTest, DoubleGoaway) {
1058  parse();
1059  SetUpUpstreamTest();
1060  downstreamCodec_.generateGoaway(output_, std::numeric_limits<int32_t>::max(),
1062  EXPECT_TRUE(downstreamCodec_.isWaitingToDrain());
1063  EXPECT_TRUE(downstreamCodec_.isReusable());
1064  EXPECT_TRUE(downstreamCodec_.isStreamIngressEgressAllowed(0));
1065  EXPECT_TRUE(downstreamCodec_.isStreamIngressEgressAllowed(1));
1066  EXPECT_TRUE(downstreamCodec_.isStreamIngressEgressAllowed(2));
1067  downstreamCodec_.generateGoaway(output_, 0, ErrorCode::NO_ERROR);
1068  EXPECT_FALSE(downstreamCodec_.isWaitingToDrain());
1069  EXPECT_FALSE(downstreamCodec_.isReusable());
1070  EXPECT_TRUE(downstreamCodec_.isStreamIngressEgressAllowed(0));
1071  EXPECT_FALSE(downstreamCodec_.isStreamIngressEgressAllowed(1));
1072  EXPECT_TRUE(downstreamCodec_.isStreamIngressEgressAllowed(2));
1073 
1074  EXPECT_TRUE(upstreamCodec_.isStreamIngressEgressAllowed(0));
1075  EXPECT_TRUE(upstreamCodec_.isStreamIngressEgressAllowed(1));
1076  EXPECT_TRUE(upstreamCodec_.isStreamIngressEgressAllowed(2));
1077  parseUpstream();
1078  EXPECT_TRUE(upstreamCodec_.isStreamIngressEgressAllowed(0));
1079  EXPECT_FALSE(upstreamCodec_.isStreamIngressEgressAllowed(1));
1080  EXPECT_TRUE(upstreamCodec_.isStreamIngressEgressAllowed(2));
1081  EXPECT_EQ(callbacks_.goaways, 2);
1082  EXPECT_EQ(callbacks_.streamErrors, 0);
1083  EXPECT_EQ(callbacks_.sessionErrors, 0);
1084 
1085  upstreamCodec_.generateGoaway(output_, 0, ErrorCode::NO_ERROR);
1086  EXPECT_TRUE(upstreamCodec_.isStreamIngressEgressAllowed(0));
1087  EXPECT_FALSE(upstreamCodec_.isStreamIngressEgressAllowed(1));
1088  EXPECT_FALSE(upstreamCodec_.isStreamIngressEgressAllowed(2));
1089  parse();
1090  EXPECT_TRUE(downstreamCodec_.isStreamIngressEgressAllowed(0));
1091  EXPECT_FALSE(downstreamCodec_.isStreamIngressEgressAllowed(1));
1092  EXPECT_FALSE(downstreamCodec_.isStreamIngressEgressAllowed(2));
1093 }
1094 
1095 TEST_F(HTTP2CodecTest, DoubleGoawayWithError) {
1096  SetUpUpstreamTest();
1097  std::unique_ptr<folly::IOBuf> debugData =
1098  folly::IOBuf::copyBuffer("debugData");
1099  downstreamCodec_.generateGoaway(output_, std::numeric_limits<int32_t>::max(),
1101  std::move(debugData));
1102  EXPECT_FALSE(downstreamCodec_.isWaitingToDrain());
1103  EXPECT_FALSE(downstreamCodec_.isReusable());
1104  auto ret = downstreamCodec_.generateGoaway(output_, 0,
1106  EXPECT_EQ(ret, 0);
1107 
1108  parseUpstream();
1109  EXPECT_EQ(callbacks_.goaways, 1);
1110  EXPECT_EQ(callbacks_.data.move()->moveToFbString(), "debugData");
1111  EXPECT_EQ(callbacks_.streamErrors, 0);
1112  EXPECT_EQ(callbacks_.sessionErrors, 0);
1113 }
1114 
1115 TEST_F(HTTP2CodecTest, GoawayHandling) {
1116  auto settings = upstreamCodec_.getEgressSettings();
1117  settings->setSetting(SettingsId::ENABLE_PUSH, 1);
1118  upstreamCodec_.generateSettings(output_);
1119 
1120  // send request
1121  HTTPMessage req = getGetRequest();
1123  size.uncompressed = size.compressed = 0;
1124  upstreamCodec_.generateHeader(output_, 1, req, true, &size);
1125  EXPECT_GT(size.uncompressed, 0);
1126  parse();
1127  callbacks_.expectMessage(true, 1, "/");
1128  callbacks_.reset();
1129 
1130  SetUpUpstreamTest();
1131  // drain after this message
1132  downstreamCodec_.generateGoaway(output_, 1, ErrorCode::NO_ERROR);
1133  parseUpstream();
1134  // upstream cannot generate id > 1
1135  upstreamCodec_.generateHeader(output_, 3, req, false, &size);
1136  EXPECT_EQ(size.uncompressed, 0);
1137  upstreamCodec_.generateWindowUpdate(output_, 3, 100);
1138  upstreamCodec_.generateBody(output_, 3, makeBuf(10), HTTPCodec::NoPadding,
1139  false);
1140  upstreamCodec_.generatePriority(output_, 3,
1141  HTTPMessage::HTTPPriority(0, true, 1));
1142  upstreamCodec_.generateEOM(output_, 3);
1143  upstreamCodec_.generateRstStream(output_, 3, ErrorCode::CANCEL);
1144  EXPECT_EQ(output_.chainLength(), 0);
1145 
1146  // send a push promise that will be rejected by downstream
1147  req.getHeaders().add("foomonkey", "george");
1148  downstreamCodec_.generatePushPromise(output_, 2, req, 1, false, &size);
1149  EXPECT_GT(size.uncompressed, 0);
1150  HTTPMessage resp;
1151  resp.setStatusCode(200);
1152  // send a push response that will be ignored
1153  downstreamCodec_.generateHeader(output_, 2, resp, false, &size);
1154  // window update for push doesn't make any sense, but whatever
1155  downstreamCodec_.generateWindowUpdate(output_, 2, 100);
1156  downstreamCodec_.generateBody(output_, 2, makeBuf(10), HTTPCodec::NoPadding,
1157  false);
1159  output_.append(makeBuf(10));
1160 
1161  // tell the upstream no pushing, and parse the first batch
1162  IOBufQueue dummy;
1163  upstreamCodec_.generateGoaway(dummy, 0, ErrorCode::NO_ERROR);
1164  parseUpstream();
1165 
1166  output_.append(makeBuf(10));
1167  downstreamCodec_.generatePriority(output_, 2,
1168  HTTPMessage::HTTPPriority(0, true, 1));
1169  downstreamCodec_.generateEOM(output_, 2);
1170  downstreamCodec_.generateRstStream(output_, 2, ErrorCode::CANCEL);
1171 
1172  // send a response that will be accepted, headers should be ok
1173  downstreamCodec_.generateHeader(output_, 1, resp, true, &size);
1174  EXPECT_GT(size.uncompressed, 0);
1175 
1176  // parse the remainder
1177  parseUpstream();
1178  callbacks_.expectMessage(true, 1, 200);
1179 }
1180 
1181 TEST_F(HTTP2CodecTest, GoawayReply) {
1182  upstreamCodec_.generateGoaway(output_, 0, ErrorCode::NO_ERROR);
1183 
1184  parse();
1185  EXPECT_EQ(callbacks_.goaways, 1);
1186  EXPECT_EQ(callbacks_.streamErrors, 0);
1187  EXPECT_EQ(callbacks_.sessionErrors, 0);
1188 
1189  SetUpUpstreamTest();
1190  HTTPMessage resp;
1191  resp.setStatusCode(200);
1192  resp.setStatusMessage("nifty-nice");
1193  downstreamCodec_.generateHeader(output_, 1, resp);
1194  downstreamCodec_.generateEOM(output_, 1);
1195  parseUpstream();
1196  callbacks_.expectMessage(true, 1, 200);
1197  EXPECT_TRUE(callbacks_.msg->getHeaders().exists(HTTP_HEADER_DATE));
1198 }
1199 
1200 TEST_F(HTTP2CodecTest, BasicSetting) {
1201  auto settings = upstreamCodec_.getEgressSettings();
1203  settings->setSetting(SettingsId::INITIAL_WINDOW_SIZE, 12345);
1204  upstreamCodec_.generateSettings(output_);
1205 
1206  parse();
1207  EXPECT_EQ(callbacks_.settings, 1);
1208  EXPECT_EQ(callbacks_.maxStreams, 37);
1209  EXPECT_EQ(callbacks_.windowSize, 12345);
1210  EXPECT_EQ(callbacks_.streamErrors, 0);
1211  EXPECT_EQ(callbacks_.sessionErrors, 0);
1212 }
1213 
1214 TEST_F(HTTP2CodecTest, SettingsAck) {
1215  upstreamCodec_.generateSettingsAck(output_);
1216 
1217  parse();
1218  EXPECT_EQ(callbacks_.settings, 0);
1219  EXPECT_EQ(callbacks_.settingsAcks, 1);
1220  EXPECT_EQ(callbacks_.streamErrors, 0);
1221  EXPECT_EQ(callbacks_.sessionErrors, 0);
1222 }
1223 
1224 TEST_F(HTTP2CodecTest, BadSettings) {
1225  auto settings = upstreamCodec_.getEgressSettings();
1226  settings->setSetting(SettingsId::INITIAL_WINDOW_SIZE, 0xffffffff);
1227  upstreamCodec_.generateSettings(output_);
1228 
1229  parse();
1230  EXPECT_EQ(callbacks_.settings, 0);
1231  EXPECT_EQ(callbacks_.streamErrors, 0);
1232  EXPECT_EQ(callbacks_.sessionErrors, 1);
1233 }
1234 
1235 TEST_F(HTTP2CodecTest, BadPushSettings) {
1236  auto settings = downstreamCodec_.getEgressSettings();
1237  settings->clearSettings();
1238  settings->setSetting(SettingsId::ENABLE_PUSH, 0);
1239  SetUpUpstreamTest();
1240 
1241  parseUpstream([&] (IOBuf* ingress) {
1243  });
1244  EXPECT_FALSE(upstreamCodec_.supportsPushTransactions());
1245  // Only way to disable push for downstreamCodec_ is to read
1246  // ENABLE_PUSH:0 from client
1247  EXPECT_TRUE(downstreamCodec_.supportsPushTransactions());
1248  EXPECT_EQ(callbacks_.settings, 1);
1249  EXPECT_EQ(callbacks_.streamErrors, 0);
1250  EXPECT_EQ(callbacks_.sessionErrors, 0);
1251 }
1252 
1253 
1254 TEST_F(HTTP2CodecTest, SettingsTableSize) {
1255  auto settings = upstreamCodec_.getEgressSettings();
1256  settings->setSetting(SettingsId::HEADER_TABLE_SIZE, 8192);
1257  upstreamCodec_.generateSettings(output_);
1258 
1259  parse();
1260  EXPECT_EQ(callbacks_.settings, 1);
1261  EXPECT_EQ(callbacks_.streamErrors, 0);
1262  EXPECT_EQ(callbacks_.sessionErrors, 0);
1263 
1264  callbacks_.reset();
1265 
1266  HTTPMessage resp;
1267  resp.setStatusCode(200);
1268  resp.setStatusMessage("nifty-nice");
1269  resp.getHeaders().add(HTTP_HEADER_CONTENT_TYPE, "x-coolio");
1270  SetUpUpstreamTest();
1271  downstreamCodec_.generateHeader(output_, 1, resp);
1272 
1273  parseUpstream();
1274  callbacks_.expectMessage(false, 2, 200);
1275  const auto& headers = callbacks_.msg->getHeaders();
1276  EXPECT_TRUE(callbacks_.msg->getHeaders().exists(HTTP_HEADER_DATE));
1277  EXPECT_EQ("x-coolio", headers.getSingleOrEmpty(HTTP_HEADER_CONTENT_TYPE));
1278 }
1279 
1280 TEST_F(HTTP2CodecTest, BadSettingsTableSize) {
1281  auto settings = upstreamCodec_.getEgressSettings();
1282  settings->setSetting(SettingsId::HEADER_TABLE_SIZE, 8192);
1283  // This sets the max decoder table size to 8k
1284  upstreamCodec_.generateSettings(output_);
1285 
1286  parse();
1287  EXPECT_EQ(callbacks_.settings, 1);
1288  EXPECT_EQ(callbacks_.streamErrors, 0);
1289  EXPECT_EQ(callbacks_.sessionErrors, 0);
1290 
1291  callbacks_.reset();
1292 
1293  // Set max decoder table size back to 4k, but don't parse it. The
1294  // upstream encoder will up the table size to 8k per the first settings frame
1295  // and the HPACK codec will send a code to update the decoder.
1296  settings->setSetting(SettingsId::HEADER_TABLE_SIZE, 4096);
1297  upstreamCodec_.generateSettings(output_);
1298 
1299  HTTPMessage resp;
1300  resp.setStatusCode(200);
1301  resp.setStatusMessage("nifty-nice");
1302  resp.getHeaders().add(HTTP_HEADER_CONTENT_TYPE, "x-coolio");
1303  SetUpUpstreamTest();
1304  downstreamCodec_.generateHeader(output_, 1, resp);
1305 
1306  parseUpstream();
1307  EXPECT_EQ(callbacks_.streamErrors, 0);
1308  EXPECT_EQ(callbacks_.sessionErrors, 1);
1309  EXPECT_EQ(callbacks_.messageBegin, 0);
1310  EXPECT_EQ(callbacks_.headersComplete, 0);
1311 }
1312 
1313 TEST_F(HTTP2CodecTest, BasicPriority) {
1314  auto pri = HTTPMessage::HTTPPriority(0, true, 1);
1315  upstreamCodec_.generatePriority(output_, 1, pri);
1316 
1317  EXPECT_TRUE(parse());
1318  EXPECT_EQ(callbacks_.priority, pri);
1319  EXPECT_EQ(callbacks_.streamErrors, 0);
1320  EXPECT_EQ(callbacks_.sessionErrors, 0);
1321 }
1322 
1323 TEST_F(HTTP2CodecTest, BadHeaderPriority) {
1324  HTTPMessage req = getGetRequest();
1325  req.setHTTP2Priority(HTTPMessage::HTTPPriority(0, false, 7));
1326  upstreamCodec_.generateHeader(output_, 1, req, true /* eom */);
1327 
1328  // hack ingress with cirular dep
1329  EXPECT_TRUE(parse([&] (IOBuf* ingress) {
1330  folly::io::RWPrivateCursor c(ingress);
1332  c.writeBE<uint32_t>(1);
1333  }));
1334 
1335  EXPECT_EQ(callbacks_.streamErrors, 1);
1336  EXPECT_EQ(callbacks_.sessionErrors, 0);
1337 }
1338 
1339 TEST_F(HTTP2CodecTest, BadPriority) {
1340  auto pri = HTTPMessage::HTTPPriority(0, true, 1);
1341  upstreamCodec_.generatePriority(output_, 1, pri);
1342 
1343  // hack ingress with cirular dep
1344  EXPECT_TRUE(parse([&] (IOBuf* ingress) {
1345  folly::io::RWPrivateCursor c(ingress);
1347  c.writeBE<uint32_t>(1);
1348  }));
1349 
1350  EXPECT_EQ(callbacks_.streamErrors, 1);
1351  EXPECT_EQ(callbacks_.sessionErrors, 0);
1352 }
1353 
1355  public:
1357  ~DummyQueue() override {}
1359  nodes_.push_back(id);
1360  }
1361 
1362  std::vector<HTTPCodec::StreamID> nodes_;
1363 };
1364 
1365 TEST_F(HTTP2CodecTest, VirtualNodes) {
1366  DummyQueue queue;
1367  uint8_t level = 30;
1368  upstreamCodec_.addPriorityNodes(queue, output_, level);
1369 
1370  EXPECT_TRUE(parse());
1371  for (int i = 0; i < level; i++) {
1372  EXPECT_EQ(queue.nodes_[i], upstreamCodec_.mapPriorityToDependency(i));
1373  }
1374 
1375  // Out-of-range priorites are mapped to the lowest level of virtual nodes.
1376  EXPECT_EQ(queue.nodes_[level - 1],
1377  upstreamCodec_.mapPriorityToDependency(level));
1378  EXPECT_EQ(queue.nodes_[level - 1],
1379  upstreamCodec_.mapPriorityToDependency(level + 1));
1380 }
1381 
1382 TEST_F(HTTP2CodecTest, BasicPushPromise) {
1383  upstreamCodec_.generateSettings(output_);
1384  parse();
1385  EXPECT_FALSE(upstreamCodec_.supportsPushTransactions());
1386  EXPECT_FALSE(downstreamCodec_.supportsPushTransactions());
1387 
1388  auto settings = upstreamCodec_.getEgressSettings();
1389  settings->setSetting(SettingsId::ENABLE_PUSH, 1);
1390  upstreamCodec_.generateSettings(output_);
1391  parse();
1392  EXPECT_TRUE(upstreamCodec_.supportsPushTransactions());
1393  EXPECT_TRUE(downstreamCodec_.supportsPushTransactions());
1394 
1395  SetUpUpstreamTest();
1396 
1397  HTTPCodec::StreamID assocStream = 7;
1398  for (auto i = 0; i < 2; i++) {
1399  // Push promise
1400  HTTPCodec::StreamID pushStream = downstreamCodec_.createStream();
1401  HTTPMessage req = getGetRequest();
1402  req.getHeaders().add(HTTP_HEADER_USER_AGENT, "coolio");
1403  downstreamCodec_.generatePushPromise(output_, pushStream, req, assocStream);
1404 
1405  parseUpstream();
1406  callbacks_.expectMessage(false, 2, "/"); // + host
1407  EXPECT_EQ(callbacks_.assocStreamId, assocStream);
1408  EXPECT_EQ(callbacks_.headersCompleteId, pushStream);
1409  auto& headers = callbacks_.msg->getHeaders();
1410  EXPECT_EQ("coolio", headers.getSingleOrEmpty(HTTP_HEADER_USER_AGENT));
1411  callbacks_.reset();
1412 
1413  // Actual reply headers
1414  HTTPMessage resp;
1415  resp.setStatusCode(200);
1416  resp.getHeaders().add(HTTP_HEADER_CONTENT_TYPE, "text/plain");
1417  downstreamCodec_.generateHeader(output_, pushStream, resp);
1418 
1419  parseUpstream();
1420  callbacks_.expectMessage(false, 2, 200);
1421  EXPECT_EQ(callbacks_.headersCompleteId, pushStream);
1422  EXPECT_EQ(callbacks_.assocStreamId, 0);
1423  EXPECT_TRUE(callbacks_.msg->getHeaders().exists(HTTP_HEADER_DATE));
1424  EXPECT_EQ("text/plain", callbacks_.msg->getHeaders().getSingleOrEmpty(
1426  callbacks_.reset();
1427  }
1428 }
1429 
1430 TEST_F(HTTP2CodecTest, BadPushPromise) {
1431  // ENABLE_PUSH is now 0 by default
1432  SetUpUpstreamTest();
1433  HTTPMessage req = getGetRequest();
1434  req.getHeaders().add(HTTP_HEADER_USER_AGENT, "coolio");
1435  downstreamCodec_.generatePushPromise(output_, 2, req, 1);
1436 
1437  parseUpstream();
1438  EXPECT_EQ(callbacks_.messageBegin, 0);
1439  EXPECT_EQ(callbacks_.headersComplete, 0);
1440  EXPECT_EQ(callbacks_.messageComplete, 0);
1441  EXPECT_EQ(callbacks_.assocStreamId, 0);
1442  EXPECT_EQ(callbacks_.streamErrors, 0);
1443  EXPECT_EQ(callbacks_.sessionErrors, 1);
1444 }
1445 
1446 TEST_F(HTTP2CodecTest, BasicCertificateRequest) {
1447  uint16_t requestId = 17;
1448  std::unique_ptr<folly::IOBuf> authRequest =
1449  folly::IOBuf::copyBuffer("authRequestData");
1450  upstreamCodec_.generateCertificateRequest(
1451  output_, requestId, std::move(authRequest));
1452 
1453  parse();
1454  EXPECT_EQ(callbacks_.certificateRequests, 1);
1455  EXPECT_EQ(callbacks_.lastCertRequestId, requestId);
1456  EXPECT_EQ(callbacks_.data.move()->moveToFbString(), "authRequestData");
1457  EXPECT_EQ(callbacks_.streamErrors, 0);
1458  EXPECT_EQ(callbacks_.sessionErrors, 0);
1459 }
1460 
1461 TEST_F(HTTP2CodecTest, BasicCertificate) {
1462  uint16_t certId = 17;
1463  std::unique_ptr<folly::IOBuf> authenticator =
1464  folly::IOBuf::copyBuffer("authenticatorData");
1465  upstreamCodec_.generateCertificate(output_, certId, std::move(authenticator));
1466 
1467  parse();
1468  EXPECT_EQ(callbacks_.certificates, 1);
1469  EXPECT_EQ(callbacks_.lastCertId, certId);
1470  EXPECT_EQ(callbacks_.data.move()->moveToFbString(), "authenticatorData");
1471  EXPECT_EQ(callbacks_.streamErrors, 0);
1472  EXPECT_EQ(callbacks_.sessionErrors, 0);
1473 }
1474 
1475 TEST_F(HTTP2CodecTest, BadServerPreface) {
1476  output_.move();
1477  downstreamCodec_.generateWindowUpdate(output_, 0, 10);
1478  parseUpstream();
1479  EXPECT_EQ(callbacks_.messageBegin, 0);
1480  EXPECT_EQ(callbacks_.headersComplete, 0);
1481  EXPECT_EQ(callbacks_.messageComplete, 0);
1482  EXPECT_EQ(callbacks_.assocStreamId, 0);
1483  EXPECT_EQ(callbacks_.streamErrors, 0);
1484  EXPECT_EQ(callbacks_.sessionErrors, 1);
1485 }
1486 
1487 TEST_F(HTTP2CodecTest, Normal1024Continuation) {
1488  HTTPMessage req = getGetRequest();
1489  string bigval(8691, '!');
1490  bigval.append(8691, ' ');
1491  req.getHeaders().add("x-headr", bigval);
1492  req.setHTTP2Priority(HTTPMessage::HTTPPriority(0, false, 7));
1493  upstreamCodec_.generateHeader(output_, 1, req);
1494 
1495  parse();
1496  callbacks_.expectMessage(false, -1, "/");
1497  const auto& headers = callbacks_.msg->getHeaders();
1498  EXPECT_EQ(bigval, headers.getSingleOrEmpty("x-headr"));
1499  EXPECT_EQ(callbacks_.messageBegin, 1);
1500  EXPECT_EQ(callbacks_.headersComplete, 1);
1501  EXPECT_EQ(callbacks_.messageComplete, 0);
1502  EXPECT_EQ(callbacks_.streamErrors, 0);
1503  EXPECT_EQ(callbacks_.sessionErrors, 0);
1504 
1505  upstreamCodec_.generateSettingsAck(output_);
1506  parse();
1507  EXPECT_EQ(callbacks_.settingsAcks, 1);
1508 }
1509 
1510 TEST_F(HTTP2CodecTest, StreamIdOverflow) {
1512 
1513  HTTPCodec::StreamID streamId;
1515  while (codec.isReusable()) {
1516  streamId = codec.createStream();
1517  }
1519 }
1520 
1521 TEST_F(HTTP2CodecTest, TestMultipleDifferentContentLengthHeaders) {
1522  // Generate a POST request with two Content-Length headers
1523  // NOTE: getPostRequest already adds the content-length
1524  HTTPMessage req = getPostRequest();
1527 
1528  upstreamCodec_.generateHeader(output_, 1, req, true /* eom */);
1529  parse();
1530 
1531  // Check that the request fails before the codec finishes parsing the headers
1532  EXPECT_EQ(callbacks_.streamErrors, 1);
1533  EXPECT_EQ(callbacks_.headersComplete, 0);
1534  EXPECT_EQ(callbacks_.lastParseError->getHttpStatusCode(), 400);
1535 }
1536 
1537 TEST_F(HTTP2CodecTest, TestMultipleIdenticalContentLengthHeaders) {
1538  // Generate a POST request with two Content-Length headers
1539  // NOTE: getPostRequest already adds the content-length
1540  HTTPMessage req = getPostRequest();
1541  req.getHeaders().add("content-length", "200");
1542  EXPECT_EQ(req.getHeaders().getNumberOfValues("content-length"), 2);
1543 
1544  upstreamCodec_.generateHeader(output_, 1, req, true /* eom */);
1545  parse();
1546 
1547  // Check that the headers parsing completes correctly
1548  EXPECT_EQ(callbacks_.streamErrors, 0);
1549  EXPECT_EQ(callbacks_.headersComplete, 1);
1550 }
1551 
1552 TEST_F(HTTP2CodecTest, CleartextUpgrade) {
1553  HTTPMessage req = getGetRequest("/guacamole");
1554  req.getHeaders().add(HTTP_HEADER_USER_AGENT, "coolio");
1558  "Upgrade", false));
1561  http2::kProtocolSettingsHeader.c_str(), false));
1562  EXPECT_GT(
1564  0);
1565 }
1566 
1567 TEST_F(HTTP2CodecTest, HTTP2SettingsSuccess) {
1568  HTTPMessage req = getGetRequest("/guacamole");
1569 
1570  // empty settings
1572  EXPECT_TRUE(downstreamCodec_.onIngressUpgradeMessage(req));
1573 
1574  // real settings (overwrites empty)
1576  EXPECT_TRUE(downstreamCodec_.onIngressUpgradeMessage(req));
1577 }
1578 
1579 TEST_F(HTTP2CodecTest, HTTP2SettingsFailure) {
1580  HTTPMessage req = getGetRequest("/guacamole");
1581  // no settings
1582  EXPECT_FALSE(downstreamCodec_.onIngressUpgradeMessage(req));
1583 
1584  HTTPHeaders& headers = req.getHeaders();
1585 
1586  // Not base64_url settings
1587  headers.set(http2::kProtocolSettingsHeader, "????");
1588  EXPECT_FALSE(downstreamCodec_.onIngressUpgradeMessage(req));
1589  headers.set(http2::kProtocolSettingsHeader, "AAA");
1590  EXPECT_FALSE(downstreamCodec_.onIngressUpgradeMessage(req));
1591 
1592  // Too big
1593  string bigSettings((http2::kMaxFramePayloadLength + 1) * 4 / 3, 'A');
1594  headers.set(http2::kProtocolSettingsHeader, bigSettings);
1595  EXPECT_FALSE(downstreamCodec_.onIngressUpgradeMessage(req));
1596 
1597  // Malformed (not a multiple of 6)
1598  headers.set(http2::kProtocolSettingsHeader, "AAAA");
1599  EXPECT_FALSE(downstreamCodec_.onIngressUpgradeMessage(req));
1600 
1601  // Two headers
1602  headers.set(http2::kProtocolSettingsHeader, "AAAAAAAA");
1603  headers.add(http2::kProtocolSettingsHeader, "AAAAAAAA");
1604  EXPECT_FALSE(downstreamCodec_.onIngressUpgradeMessage(req));
1605 }
1606 
1607 TEST_F(HTTP2CodecTest, HTTP2EnableConnect) {
1608  SetUpUpstreamTest();
1609  // egress settings have no connect settings.
1610  auto ws_enable = upstreamCodec_.getEgressSettings()->getSetting(
1612  // enable connect settings, and check.
1613  upstreamCodec_.getEgressSettings()->setSetting(
1615  ws_enable = upstreamCodec_.getEgressSettings()->getSetting(
1617  EXPECT_EQ(ws_enable->value, 1);
1618  // generateSettings.
1619  // pass the buffer to be parsed by the codec and check for ingress settings.
1620  upstreamCodec_.generateSettings(output_);
1621  parseUpstream();
1622  EXPECT_EQ(1, upstreamCodec_.peerHasWebsockets());
1623 }
1624 
1625 TEST_F(HTTP2CodecTest, WebsocketUpgrade) {
1626  HTTPMessage req = getGetRequest("/apples");
1627  req.setSecure(true);
1629 
1630  upstreamCodec_.generateHeader(output_, 1, req, false);
1631  parse();
1632 
1633  EXPECT_TRUE(callbacks_.msg->isIngressWebsocketUpgrade());
1634  EXPECT_NE(nullptr, callbacks_.msg->getUpgradeProtocol());
1635  EXPECT_EQ(headers::kWebsocketString, *callbacks_.msg->getUpgradeProtocol());
1636 }
1637 
1638 TEST_F(HTTP2CodecTest, WebsocketBadHeader) {
1639  const std::string kConnect{"CONNECT"};
1640  const std::string kWebsocketPath{"/websocket"};
1641  const std::string kSchemeHttps{"https"};
1642  vector<proxygen::compress::Header> reqHeaders = {
1645  };
1646  vector<proxygen::compress::Header> optionalHeaders = {
1647  Header::makeHeaderForTest(headers::kPath, kWebsocketPath),
1649  };
1650 
1652  int stream = 1;
1653  for (size_t i = 0; i < optionalHeaders.size(); ++i, stream += 2) {
1654  auto headers = reqHeaders;
1655  headers.push_back(optionalHeaders[i]);
1656  auto encodedHeaders = headerCodec.encode(headers);
1657  http2::writeHeaders(output_,
1658  std::move(encodedHeaders),
1659  stream,
1660  folly::none,
1662  false,
1663  true);
1664  parse();
1665  }
1666 
1667  EXPECT_EQ(callbacks_.messageBegin, 0);
1668  EXPECT_EQ(callbacks_.headersComplete, 0);
1669  EXPECT_EQ(callbacks_.messageComplete, 0);
1670  EXPECT_EQ(callbacks_.streamErrors, optionalHeaders.size());
1671  EXPECT_EQ(callbacks_.sessionErrors, 0);
1672 }
1673 
1674 TEST_F(HTTP2CodecTest, WebsocketDupProtocol) {
1675  const std::string kConnect{"CONNECT"};
1676  const std::string kWebsocketPath{"/websocket"};
1677  const std::string kSchemeHttps{"https"};
1678  vector<proxygen::compress::Header> headers = {
1682  Header::makeHeaderForTest(headers::kPath, kWebsocketPath),
1684  };
1686  auto encodedHeaders = headerCodec.encode(headers);
1687  http2::writeHeaders(output_,
1688  std::move(encodedHeaders),
1689  1,
1690  folly::none,
1692  false,
1693  true);
1694  parse();
1695  EXPECT_EQ(callbacks_.messageBegin, 0);
1696  EXPECT_EQ(callbacks_.headersComplete, 0);
1697  EXPECT_EQ(callbacks_.messageComplete, 0);
1698  EXPECT_EQ(callbacks_.streamErrors, 1);
1699  EXPECT_EQ(callbacks_.sessionErrors, 0);
1700 }
1701 
1702 TEST_F(HTTP2CodecTest, WebsocketIncorrectResponse) {
1703  parse();
1704  SetUpUpstreamTest();
1705  parseUpstream();
1706 
1707  output_.clear();
1708  HTTPMessage req = getGetRequest("/apples");
1709  req.setSecure(true);
1711  upstreamCodec_.generateHeader(output_, 1, req, false);
1712  parse();
1713 
1714  output_.clear();
1715  HTTPMessage resp;
1716  resp.setStatusCode(201);
1717  resp.setStatusMessage("OK");
1718  downstreamCodec_.generateHeader(output_, 1, resp);
1719  parseUpstream();
1720  EXPECT_EQ(callbacks_.streamErrors, 1);
1721 }
1722 
1723 TEST_F(HTTP2CodecTest, TestAllEgressFrameTypeCallbacks) {
1724  class CallbackTypeTracker {
1725  std::set<uint8_t> types;
1726  public:
1728  types.insert(type);
1729  }
1730 
1731  bool isAllFrameTypesReceived() {
1732  http2::FrameType expectedTypes[] = {
1744  };
1745 
1746  for(http2::FrameType type: expectedTypes) {
1747  EXPECT_TRUE(types.find(static_cast<uint8_t>(type)) != types.end())
1748  << "callback missing for type " << static_cast<uint8_t>(type);
1749  }
1750  return types.size() == (sizeof(expectedTypes)/sizeof(http2::FrameType));
1751  }
1752  };
1753 
1754  CallbackTypeTracker callbackTypeTracker;
1755 
1756  NiceMock<MockHTTPCodecCallback> mockCallback;
1757  upstreamCodec_.setCallback(&mockCallback);
1758  downstreamCodec_.setCallback(&mockCallback);
1759  EXPECT_CALL(mockCallback, onGenerateFrameHeader(_, _, _, _)).
1760  WillRepeatedly(Invoke(&callbackTypeTracker, &CallbackTypeTracker::add));
1761 
1762  // DATA frame
1763  string data("abcde");
1764  auto buf = folly::IOBuf::copyBuffer(data.data(), data.length());
1765  upstreamCodec_.generateBody(output_, 2, std::move(buf),
1766  HTTPCodec::NoPadding, true);
1767 
1769  size.uncompressed = size.compressed = 0;
1770  HTTPMessage req = getGetRequest();
1771  upstreamCodec_.generateHeader(output_, 1, req, true, &size);
1772 
1773  upstreamCodec_.generatePriority(output_, 3,
1774  HTTPMessage::HTTPPriority(0, true, 1));
1775  upstreamCodec_.generateRstStream(output_, 2, ErrorCode::ENHANCE_YOUR_CALM);
1776  upstreamCodec_.generateSettings(output_);
1777  downstreamCodec_.generatePushPromise(output_, 2, req, 1);
1778  upstreamCodec_.generatePingRequest(output_);
1779 
1780  std::unique_ptr<folly::IOBuf> debugData =
1781  folly::IOBuf::copyBuffer("debugData");
1782  upstreamCodec_.generateGoaway(output_, 17, ErrorCode::ENHANCE_YOUR_CALM,
1783  std::move(debugData));
1784 
1785  upstreamCodec_.generateWindowUpdate(output_, 0, 10);
1786 
1788  HTTPCodec::StreamID controlStream = folly::Random::rand32(10, 1024) * 2 + 1;
1789  downstreamCodec_.generateExHeader(output_, stream, req,
1790  HTTPCodec::ExAttributes(controlStream, true));
1791 
1792  // Tests the continuation frame
1793  req = getBigGetRequest();
1794  upstreamCodec_.generateHeader(output_, 1, req, true /* eom */);
1795 
1796  EXPECT_TRUE(callbackTypeTracker.isAllFrameTypesReceived());
1797 }
1798 
1800  HTTPMessage req = getGetRequest("/guacamole");
1801  req.getHeaders().add(HTTP_HEADER_USER_AGENT, "coolio");
1802  upstreamCodec_.generateHeader(output_, 1, req);
1803 
1804  string data("abcde");
1805  auto buf = folly::IOBuf::copyBuffer(data.data(), data.length());
1806  upstreamCodec_.generateBody(
1807  output_, 1, std::move(buf), HTTPCodec::NoPadding, false /* eom */);
1808 
1809  HTTPHeaders trailers;
1810  trailers.add("x-trailer-1", "pico-de-gallo");
1811  upstreamCodec_.generateTrailers(output_, 1, trailers);
1812 
1813  parse();
1814 
1815  EXPECT_EQ(callbacks_.messageBegin, 1);
1816  EXPECT_EQ(callbacks_.headersComplete, 1);
1817  EXPECT_EQ(callbacks_.bodyCalls, 1);
1818  EXPECT_EQ(callbacks_.bodyLength, 5);
1819  EXPECT_EQ(callbacks_.trailers, 1);
1820  EXPECT_NE(nullptr, callbacks_.msg->getTrailers());
1821  EXPECT_EQ("pico-de-gallo",
1822  callbacks_.msg->getTrailers()->getSingleOrEmpty("x-trailer-1"));
1823  EXPECT_EQ(callbacks_.messageComplete, 1);
1824  EXPECT_EQ(callbacks_.streamErrors, 0);
1825  EXPECT_EQ(callbacks_.sessionErrors, 0);
1826 #ifndef NDEBUG
1827  EXPECT_EQ(downstreamCodec_.getReceivedFrameCount(), 3);
1828 #endif
1829 }
1830 
1831 TEST_F(HTTP2CodecTest, TrailersWithPseudoHeaders) {
1832  HTTPMessage req = getGetRequest("/guacamole");
1833  req.getHeaders().add(HTTP_HEADER_USER_AGENT, "coolio");
1834  upstreamCodec_.generateHeader(output_, 1, req);
1835 
1836  string data("abcde");
1837  auto buf = folly::IOBuf::copyBuffer(data.data(), data.length());
1838  upstreamCodec_.generateBody(
1839  output_, 1, std::move(buf), HTTPCodec::NoPadding, false /* eom */);
1840 
1842  std::string post("POST");
1843  std::vector<proxygen::compress::Header> trailers = {
1845  auto encodedTrailers = headerCodec.encode(trailers);
1846  http2::writeHeaders(output_,
1847  std::move(encodedTrailers),
1848  1,
1849  folly::none,
1851  true,
1852  true);
1853 
1854  parse();
1855 
1856  EXPECT_EQ(callbacks_.messageBegin, 1);
1857  EXPECT_EQ(callbacks_.headersComplete, 1);
1858  EXPECT_EQ(callbacks_.bodyCalls, 1);
1859  EXPECT_EQ(callbacks_.bodyLength, 5);
1860  EXPECT_EQ(callbacks_.trailers, 0);
1861  EXPECT_EQ(nullptr, callbacks_.msg->getTrailers());
1862  EXPECT_EQ(callbacks_.messageComplete, 0);
1863  EXPECT_EQ(callbacks_.streamErrors, 1);
1864 }
1865 
1866 TEST_F(HTTP2CodecTest, TrailersNoBody) {
1867  HTTPMessage req = getGetRequest("/guacamole");
1868  req.getHeaders().add(HTTP_HEADER_USER_AGENT, "coolio");
1869  upstreamCodec_.generateHeader(output_, 1, req);
1870 
1871  HTTPHeaders trailers;
1872  trailers.add("x-trailer-1", "pico-de-gallo");
1873  upstreamCodec_.generateTrailers(output_, 1, trailers);
1874 
1875  parse();
1876 
1877  EXPECT_EQ(callbacks_.messageBegin, 1);
1878  EXPECT_EQ(callbacks_.headersComplete, 1);
1879  EXPECT_EQ(callbacks_.bodyCalls, 0);
1880  EXPECT_EQ(callbacks_.bodyLength, 0);
1881  EXPECT_EQ(callbacks_.trailers, 1);
1882  EXPECT_NE(nullptr, callbacks_.msg->getTrailers());
1883  EXPECT_EQ("pico-de-gallo",
1884  callbacks_.msg->getTrailers()->getSingleOrEmpty("x-trailer-1"));
1885  EXPECT_EQ(callbacks_.messageComplete, 1);
1886  EXPECT_EQ(callbacks_.streamErrors, 0);
1887  EXPECT_EQ(callbacks_.sessionErrors, 0);
1888 #ifndef NDEBUG
1889  EXPECT_EQ(downstreamCodec_.getReceivedFrameCount(), 2);
1890 #endif
1891 }
1892 
1893 TEST_F(HTTP2CodecTest, TrailersContinuation) {
1894  HTTPMessage req = getGetRequest("/guacamole");
1895  upstreamCodec_.generateHeader(output_, 1, req);
1896 
1897  HTTPHeaders trailers;
1898  trailers.add("x-trailer-1", "pico-de-gallo");
1899  trailers.add("x-huge-trailer",
1901  upstreamCodec_.generateTrailers(output_, 1, trailers);
1902 
1903  parse();
1904 
1905  EXPECT_EQ(callbacks_.messageBegin, 1);
1906  EXPECT_EQ(callbacks_.headersComplete, 1);
1907  EXPECT_EQ(callbacks_.messageComplete, 1);
1908  EXPECT_EQ(callbacks_.streamErrors, 0);
1909  EXPECT_EQ(callbacks_.sessionErrors, 0);
1910  EXPECT_NE(callbacks_.msg, nullptr);
1911  EXPECT_EQ(callbacks_.trailers, 1);
1912  EXPECT_NE(callbacks_.msg->getTrailers(), nullptr);
1913  EXPECT_EQ("pico-de-gallo",
1914  callbacks_.msg->getTrailers()->getSingleOrEmpty("x-trailer-1"));
1916  callbacks_.msg->getTrailers()->getSingleOrEmpty("x-huge-trailer"));
1917 #ifndef NDEBUG
1918  EXPECT_EQ(downstreamCodec_.getReceivedFrameCount(), 3);
1919 #endif
1920 }
1921 
1922 TEST_F(HTTP2CodecTest, TrailersReply) {
1923  SetUpUpstreamTest();
1924  HTTPMessage resp;
1925  resp.setStatusCode(200);
1926  resp.setStatusMessage("nifty-nice");
1927  resp.getHeaders().add(HTTP_HEADER_CONTENT_TYPE, "x-coolio");
1928  downstreamCodec_.generateHeader(output_, 1, resp);
1929 
1930  string data("abcde");
1931  auto buf = folly::IOBuf::copyBuffer(data.data(), data.length());
1932  downstreamCodec_.generateBody(
1933  output_, 1, std::move(buf), HTTPCodec::NoPadding, false);
1934 
1935  HTTPHeaders trailers;
1936  trailers.add("x-trailer-1", "pico-de-gallo");
1937  trailers.add("x-trailer-2", "chicken-kyiv");
1938  downstreamCodec_.generateTrailers(output_, 1, trailers);
1939 
1940  parseUpstream();
1941 
1942  callbacks_.expectMessage(true, 2, 200);
1943  EXPECT_EQ(callbacks_.bodyCalls, 1);
1944  EXPECT_EQ(callbacks_.bodyLength, 5);
1945  const auto& headers = callbacks_.msg->getHeaders();
1946  EXPECT_TRUE(callbacks_.msg->getHeaders().exists(HTTP_HEADER_DATE));
1947  EXPECT_EQ("x-coolio", headers.getSingleOrEmpty(HTTP_HEADER_CONTENT_TYPE));
1948  EXPECT_EQ(1, callbacks_.trailers);
1949  EXPECT_NE(nullptr, callbacks_.msg->getTrailers());
1950  EXPECT_EQ("pico-de-gallo",
1951  callbacks_.msg->getTrailers()->getSingleOrEmpty("x-trailer-1"));
1952  EXPECT_EQ("chicken-kyiv",
1953  callbacks_.msg->getTrailers()->getSingleOrEmpty("x-trailer-2"));
1954 #ifndef NDEBUG
1955  EXPECT_EQ(upstreamCodec_.getReceivedFrameCount(), 4);
1956 #endif
1957 }
1958 
1959 TEST_F(HTTP2CodecTest, TrailersReplyWithNoData) {
1960  SetUpUpstreamTest();
1961  HTTPMessage resp;
1962  resp.setStatusCode(200);
1963  resp.setStatusMessage("nifty-nice");
1964  resp.getHeaders().add(HTTP_HEADER_CONTENT_TYPE, "x-coolio");
1965  downstreamCodec_.generateHeader(output_, 1, resp);
1966 
1967  HTTPHeaders trailers;
1968  trailers.add("x-trailer-1", "pico-de-gallo");
1969  downstreamCodec_.generateTrailers(output_, 1, trailers);
1970 
1971  parseUpstream();
1972 
1973  callbacks_.expectMessage(true, 2, 200);
1974  EXPECT_EQ(callbacks_.bodyCalls, 0);
1975  EXPECT_EQ(callbacks_.bodyLength, 0);
1976  const auto& headers = callbacks_.msg->getHeaders();
1977  EXPECT_TRUE(callbacks_.msg->getHeaders().exists(HTTP_HEADER_DATE));
1978  EXPECT_EQ("x-coolio", headers.getSingleOrEmpty(HTTP_HEADER_CONTENT_TYPE));
1979  EXPECT_EQ(1, callbacks_.trailers);
1980  EXPECT_NE(nullptr, callbacks_.msg->getTrailers());
1981  EXPECT_EQ("pico-de-gallo",
1982  callbacks_.msg->getTrailers()->getSingleOrEmpty("x-trailer-1"));
1983 #ifndef NDEBUG
1984  EXPECT_EQ(upstreamCodec_.getReceivedFrameCount(), 3);
1985 #endif
1986 }
1987 
1988 TEST_F(HTTP2CodecTest, TrailersReplyWithPseudoHeaders) {
1989  SetUpUpstreamTest();
1990  HTTPMessage resp;
1991  resp.setStatusCode(200);
1992  resp.setStatusMessage("nifty-nice");
1993  resp.getHeaders().add(HTTP_HEADER_CONTENT_TYPE, "x-coolio");
1994  downstreamCodec_.generateHeader(output_, 1, resp);
1995 
1996  string data("abcde");
1997  auto buf = folly::IOBuf::copyBuffer(data.data(), data.length());
1998  downstreamCodec_.generateBody(
1999  output_, 1, std::move(buf), HTTPCodec::NoPadding, false);
2000 
2002  std::string post("POST");
2003  std::vector<proxygen::compress::Header> trailers = {
2005  auto encodedTrailers = headerCodec.encode(trailers);
2006  http2::writeHeaders(output_,
2007  std::move(encodedTrailers),
2008  1,
2009  folly::none,
2011  true,
2012  true);
2013  parseUpstream();
2014 
2015  EXPECT_EQ(callbacks_.messageBegin, 1);
2016  EXPECT_EQ(callbacks_.headersComplete, 1);
2017  EXPECT_EQ(callbacks_.trailers, 0);
2018  EXPECT_EQ(nullptr, callbacks_.msg->getTrailers());
2019  EXPECT_EQ(callbacks_.streamErrors, 1);
2020  EXPECT_EQ(callbacks_.sessionErrors, 0);
2021 }
2022 
2023 TEST_F(HTTP2CodecTest, TrailersReplyContinuation) {
2024  SetUpUpstreamTest();
2025  HTTPMessage resp;
2026  resp.setStatusCode(200);
2027  downstreamCodec_.generateHeader(output_, 1, resp);
2028 
2029  HTTPHeaders trailers;
2030  trailers.add("x-trailer-1", "pico-de-gallo");
2031  trailers.add("x-huge-trailer",
2033  downstreamCodec_.generateTrailers(output_, 1, trailers);
2034 
2035  parseUpstream();
2036 
2037  EXPECT_EQ(callbacks_.messageBegin, 1);
2038  EXPECT_EQ(callbacks_.headersComplete, 1);
2039  EXPECT_EQ(callbacks_.messageComplete, 1);
2040  EXPECT_EQ(callbacks_.streamErrors, 0);
2041  EXPECT_EQ(callbacks_.sessionErrors, 0);
2042  EXPECT_NE(callbacks_.msg, nullptr);
2043  EXPECT_EQ(callbacks_.msg->getStatusCode(), 200);
2044  EXPECT_EQ(1, callbacks_.trailers);
2045  EXPECT_NE(nullptr, callbacks_.msg->getTrailers());
2046  EXPECT_EQ("pico-de-gallo",
2047  callbacks_.msg->getTrailers()->getSingleOrEmpty("x-trailer-1"));
2049  callbacks_.msg->getTrailers()->getSingleOrEmpty("x-huge-trailer"));
2050 #ifndef NDEBUG
2051  EXPECT_EQ(upstreamCodec_.getReceivedFrameCount(), 4);
2052 #endif
2053 }
2054 
2055 TEST_F(HTTP2CodecTest, TrailersReplyMissingContinuation) {
2056  SetUpUpstreamTest();
2057  HTTPMessage resp;
2058  resp.setStatusCode(200);
2059  downstreamCodec_.generateHeader(output_, 1, resp);
2060 
2061  HTTPHeaders trailers;
2062  trailers.add("x-trailer-1", "pico-de-gallo");
2063  trailers.add("x-huge-trailer",
2065  downstreamCodec_.generateTrailers(output_, 1, trailers);
2066  // empirically determined the size of continuation frame, and strip it
2067  output_.trimEnd(http2::kFrameHeaderSize + 4132);
2068 
2069  // insert a non-continuation (but otherwise valid) frame
2071 
2072  parseUpstream();
2073 
2074  EXPECT_EQ(callbacks_.messageBegin, 1);
2075  EXPECT_EQ(callbacks_.headersComplete, 1);
2076  EXPECT_EQ(callbacks_.messageComplete, 0);
2077  EXPECT_EQ(callbacks_.streamErrors, 0);
2078  EXPECT_EQ(callbacks_.sessionErrors, 1);
2079 #ifndef NDEBUG
2080  EXPECT_EQ(upstreamCodec_.getReceivedFrameCount(), 4);
2081 #endif
2082 }
void * ptr
std::unique_ptr< folly::IOBuf > makeBuf(uint32_t size)
Definition: TestUtils.cpp:36
static const folly::Optional< uint8_t > NoPadding
Definition: HTTPCodec.h:53
*than *hazptr_holder h
Definition: Hazptr.h:116
const std::string kProtocol
auto v
LogLevel max
Definition: LogLevel.cpp:31
auto add
Definition: BaseTest.cpp:70
void writeFrameHeaderManual(IOBufQueue &queue, uint32_t length, uint8_t type, uint8_t flags, uint32_t stream)
const uint32_t kFrameHeaderSize
const uint8_t kBufEmptyHeader[]
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
void setStatusMessage(T &&msg)
Definition: HTTPMessage.h:242
#define EXPECT_DEATH_NO_CORE(token, regex)
Definition: TestUtils.h:19
PskType type
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
HTTPMessage getBigGetRequest(const std::string &url)
Definition: TestUtils.cpp:85
void testHeaderListSize(bool oversized)
CodecFactory codec
STL namespace.
const uint32_t kMaxFramePayloadLength
void setNextEgressStreamId(StreamID nextEgressStreamID)
size_t getNumberOfValues(HTTPHeaderCode code) const
static http_parser_settings settings
Definition: test.c:1529
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
~DummyQueue() override
void addPriorityNode(HTTPCodec::StreamID id, HTTPCodec::StreamID) override
std::vector< HTTPCodec::StreamID > nodes_
bool isReusable() const override
void testFrameSizeLimit(bool oversized)
size_t writeContinuation(IOBufQueue &queue, uint32_t stream, bool endHeaders, std::unique_ptr< IOBuf > headers) noexcept
size_t writeSettings(IOBufQueue &queue, const std::deque< SettingPair > &settings)
const uint32_t kMaxWindowUpdateSize
static void requestUpgrade(HTTPMessage &request)
const std::string kScheme
void set(folly::StringPiece name, const std::string &value)
Definition: HTTPHeaders.h:119
const uint32_t kMaxFramePayloadLengthMin
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
bool checkForHeaderToken(const HTTPHeaderCode headerCode, char const *token, bool caseSensitive) const
void SetUp() override
void setSecure(bool secure)
Definition: HTTPMessage.h:534
void setHTTP2Priority(HTTPPriority h2Pri)
Definition: HTTPMessage.h:599
PolymorphicAction< internal::InvokeAction< FunctionImpl > > Invoke(FunctionImpl function_impl)
const uint32_t kFrameWindowUpdateSize
void dummy()
StreamID createStream() override
TEST(HTTP2CodecConstantsTest, HTTPContantsAreCommonHeaders)
std::pair< SettingsId, uint32_t > SettingPair
Definition: SettingsId.h:58
HTTPHeaders & getHeaders()
Definition: HTTPMessage.h:273
const std::string & getSingleOrEmpty(const T &nameOrCode) const
Definition: HTTPHeaders.h:420
const std::string kProtocolSettingsHeader
void setMethod(HTTPMethod method)
std::size_t computeChainDataLength() const
Definition: IOBuf.cpp:501
std::unique_ptr< IOBuf > copyBuffer(const folly::IOBuf &buf)
const std::string kHttp
std::tuple< uint32_t, bool, uint8_t > HTTPPriority
Definition: HTTPMessage.h:592
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
HTTPMessage getGetRequest(const std::string &url)
Definition: TestUtils.cpp:76
void skip(size_t len)
Definition: Cursor.h:371
const char * string
Definition: Conv.cpp:212
size_t writeGoaway(IOBufQueue &queue, uint32_t lastStreamID, ErrorCode errorCode, std::unique_ptr< IOBuf > debugData) noexcept
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
const std::string kStatus
HTTPMessage getPostRequest(uint32_t contentLength)
Definition: TestUtils.cpp:102
const std::string kPath
#define EXPECT_CALL(obj, call)
const std::string kConnectionPreface
uint64_t StreamID
Definition: HTTPCodec.h:49
const internal::AnythingMatcher _
TEST_F(HeaderTableTests, IndexTranslation)
const Padding kNoPadding
Definition: HTTP2Framer.cpp:20
void add(folly::StringPiece name, folly::StringPiece value)
Definition: HTTPHeaders.cpp:52
size_t parse(T *codec, const uint8_t *inputData, uint32_t length, int32_t atOnce=0, std::function< bool()> stopFn=[]{return false;})
Definition: TestUtils.h:28
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
std::unique_ptr< folly::IOBuf > encode(std::vector< compress::Header > &headers) noexcept
Definition: HPACKCodec.cpp:48
static FB_EXPORT HTTPHeaderCode hash(const char *name, size_t len)
const std::string kAuthority
void setEgressWebsocketUpgrade()
Definition: HTTPMessage.h:66
static uint32_t rand32()
Definition: Random.h:213
static std::unique_ptr< IOBuf > copyBuffer(const void *buf, std::size_t size, std::size_t headroom=0, std::size_t minTailroom=0)
Definition: IOBuf.h:1587
char c
uint32_t streamID
Definition: SPDYCodec.cpp:131
const std::string kWebsocketString
static constexpr uint64_t data[1]
Definition: Fingerprint.cpp:43
const std::string kMethod
static Header makeHeaderForTest(const std::string &n, const std::string &v)
Definition: Header.h:41
constexpr None none
Definition: Optional.h:87
#define EXPECT_GT(val1, val2)
Definition: gtest.h:1934
void setSetting(SettingsId id, SettingsValue val)
void writeBE(T value)
Definition: Cursor.h:744
void setStatusCode(uint16_t status)