proxygen
HTTPDownstreamSessionTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
10 #include <string>
11 #include <vector>
12 
13 #include <folly/Conv.h>
14 #include <folly/Range.h>
15 #include <folly/futures/Promise.h>
16 #include <folly/io/Cursor.h>
33 
34 using namespace folly::io;
35 using namespace wangle;
36 using namespace folly;
37 using namespace proxygen;
38 using namespace std;
39 using namespace testing;
40 using namespace std::chrono;
41 using folly::Promise;
42 
43 template <typename C>
45  public:
47  std::vector<int64_t> flowControl = { -1, -1, -1 },
48  bool startImmediately = true)
49  : eventBase_(),
50  transport_(new TestAsyncTransport(&eventBase_)),
51  transactionTimeouts_(makeTimeoutSet(&eventBase_)),
52  flowControl_(flowControl) {
53  EXPECT_CALL(mockController_, getGracefulShutdownTimeout())
54  .WillRepeatedly(Return(std::chrono::milliseconds(0)));
55  EXPECT_CALL(mockController_, attachSession(_))
56  .WillRepeatedly(Invoke([&] (HTTPSessionBase* session) {
57  session->setPrioritySampled(true);
58  }));
59  HTTPSession::setDefaultReadBufferLimit(65536);
60  auto codec = makeServerCodec<typename C::Codec>(C::version);
61  rawCodec_ = codec.get();
62 
63  // If the codec is H2, getHeaderIndexingStrategy will be called when setting
64  // up the codec
65  if (rawCodec_->getProtocol() == CodecProtocol::HTTP_2) {
66  EXPECT_CALL(mockController_, getHeaderIndexingStrategy())
67  .WillOnce(
68  Return(&testH2IndexingStrat_)
69  );
70  }
71 
72  httpSession_ = new HTTPDownstreamSession(
73  transactionTimeouts_.get(),
76  &mockController_,
78  mockTransportInfo /* no stats for now */,
79  nullptr);
80  for (auto& param: flowControl) {
81  if (param < 0) {
82  param = rawCodec_->getDefaultWindowSize();
83  }
84  }
85 
86  // Ensure the H2 header indexing strategy was setup correctly if applicable
87  if (rawCodec_->getProtocol() == CodecProtocol::HTTP_2) {
88  HTTP2Codec* recastedCodec = dynamic_cast<HTTP2Codec*>(rawCodec_);
89  EXPECT_EQ(
90  recastedCodec->getHeaderIndexingStrategy(), &testH2IndexingStrat_);
91  }
92 
93  httpSession_->setFlowControl(flowControl[0], flowControl[1],
94  flowControl[2]);
95  httpSession_->setEgressSettings({{ SettingsId::MAX_CONCURRENT_STREAMS, 80 },
96  { SettingsId::HEADER_TABLE_SIZE, 5555 },
97  { SettingsId::ENABLE_PUSH, 1 },
98  { SettingsId::ENABLE_EX_HEADERS, 1 }});
99  if (startImmediately) {
100  httpSession_->startNow();
101  }
102  clientCodec_ = makeClientCodec<typename C::Codec>(C::version);
103  if (clientCodec_->getProtocol() == CodecProtocol::HTTP_2) {
104  clientCodec_->getEgressSettings()->setSetting(
105  SettingsId::ENABLE_EX_HEADERS, 1);
106  }
107  clientCodec_->generateConnectionPreface(requests_);
108  clientCodec_->setCallback(&callbacks_);
109  }
110 
112  int8_t priority = 0,
113  bool eom = true) {
114  auto req = getGetRequest();
115  req.setURL(url);
116  req.setPriority(priority);
117  return sendRequest(req, eom);
118  }
119 
120  HTTPCodec::StreamID sendRequest(const HTTPMessage& req, bool eom = true) {
121  auto streamID = clientCodec_->createStream();
122  clientCodec_->generateHeader(requests_, streamID, req, eom);
123  return streamID;
124  }
125 
127  return sendRequest("/", 0, false);
128  }
129 
131  Promise<Unit> reqp;
132  reqp.getFuture().then(&eventBase_, [=] {
133  sendRequest(req);
134  transport_->addReadEvent(requests_, milliseconds(0));
135  if (eof) {
136  transport_->addReadEOF(milliseconds(0));
137  }
138  });
139  return reqp;
140  }
141 
142  void SetUp() override {
144  HTTPSession::setDefaultWriteBufferLimit(65536);
145  HTTP2PriorityQueue::setNodeLifetime(std::chrono::milliseconds(2));
146  }
147 
148  void cleanup() {
149  EXPECT_CALL(mockController_, detachSession(_));
150  httpSession_->dropConnection();
151  }
152 
153 
154  std::unique_ptr<testing::StrictMock<MockHTTPHandler>>
156  std::unique_ptr<testing::StrictMock<MockHTTPHandler>> handler =
157  std::make_unique<testing::StrictMock<MockHTTPHandler>>();
158 
159  // The ownership model here is suspect, but assume the callers won't destroy
160  // handler before it's requested
161  auto rawHandler = handler.get();
162  EXPECT_CALL(mockController_, getRequestHandler(testing::_, testing::_))
163  .WillOnce(testing::Return(rawHandler))
164  .RetiresOnSaturation();
165 
166  EXPECT_CALL(*handler, setTransaction(testing::_))
167  .WillOnce(testing::SaveArg<0>(&handler->txn_));
168 
169  return handler;
170  }
171 
172  std::unique_ptr<testing::NiceMock<MockHTTPHandler>>
174  std::unique_ptr<testing::NiceMock<MockHTTPHandler>> handler =
175  std::make_unique<testing::NiceMock<MockHTTPHandler>>();
176 
177  // See comment above
178  auto rawHandler = handler.get();
179  EXPECT_CALL(mockController_, getRequestHandler(testing::_, testing::_))
180  .WillOnce(testing::Return(rawHandler))
181  .RetiresOnSaturation();
182 
183  EXPECT_CALL(*handler, setTransaction(testing::_))
184  .WillOnce(testing::SaveArg<0>(&handler->txn_));
185 
186  return handler;
187  }
188 
190  handler.expectEOM([&] { handler.terminate(); });
191  handler.expectDetachTransaction();
192  expectDetachSession();
193  }
194 
196  EXPECT_CALL(mockController_, detachSession(testing::_));
197  }
198 
199  void addSingleByteReads(const char* data, milliseconds delay={}) {
200  for (const char* p = data; *p != '\0'; ++p) {
201  transport_->addReadEvent(p, 1, delay);
202  }
203  }
204 
206  bool eof=false, milliseconds eofDelay=milliseconds(0),
207  milliseconds initialDelay=milliseconds(0),
208  std::function<void()> extraEventsFn = std::function<void()>()) {
209  flushRequests(eof, eofDelay, initialDelay, extraEventsFn);
210  eventBase_.loop();
211  }
212 
214  bool eof=false, milliseconds eofDelay=milliseconds(0),
215  milliseconds initialDelay=milliseconds(0),
216  std::function<void()> extraEventsFn = std::function<void()>()) {
217  flushRequests(eof, eofDelay, initialDelay, extraEventsFn);
218  for (uint64_t i = 0; i < n; i++) {
219  eventBase_.loopOnce();
220  }
221  }
222 
224  bool eof=false, milliseconds eofDelay=milliseconds(0),
225  milliseconds initialDelay=milliseconds(0),
226  std::function<void()> extraEventsFn = std::function<void()>()) {
227  transport_->addReadEvent(requests_, initialDelay);
228  if (extraEventsFn) {
229  extraEventsFn();
230  }
231  if (eof) {
232  transport_->addReadEOF(eofDelay);
233  }
234  transport_->startReadEvents();
235  }
236 
237  void testSimpleUpgrade(
238  const std::string& upgradeHeader,
239  CodecProtocol expectedProtocol,
240  const std::string& expectedUpgradeHeader);
241 
244  clientCodec_->generateGoaway(this->requests_, 0, ErrorCode::NO_ERROR);
245  expectDetachSession();
246  flushRequestsAndLoop(true);
247  }
248 
249  void testPriorities(uint32_t numPriorities);
250 
251  void testChunks(bool trailers);
252 
253  void expect101(CodecProtocol expectedProtocol,
254  const std::string& expectedUpgrade,
255  bool expect100 = false) {
257 
258  EXPECT_CALL(callbacks, onMessageBegin(_, _));
259  EXPECT_CALL(callbacks, onNativeProtocolUpgrade(_, _, _, _))
260  .WillOnce(
261  Invoke([this, expectedUpgrade] (HTTPCodec::StreamID,
263  const std::string&,
264  HTTPMessage& msg) {
265  EXPECT_EQ(msg.getStatusCode(), 101);
266  EXPECT_EQ(msg.getStatusMessage(), "Switching Protocols");
268  expectedUpgrade);
269  // also connection and date
270  EXPECT_EQ(msg.getHeaders().size(), 3);
271  breakParseOutput_ = true;
272  return true;
273  }));
274  // this comes before 101, but due to gmock this is backwards
275  if (expect100) {
276  EXPECT_CALL(callbacks, onMessageBegin(_, _))
277  .RetiresOnSaturation();
278  EXPECT_CALL(callbacks, onHeadersComplete(_, _))
279  .WillOnce(Invoke([] (HTTPCodec::StreamID,
280  std::shared_ptr<HTTPMessage> msg) {
281  LOG(INFO) << "100 headers";
282  EXPECT_EQ(msg->getStatusCode(), 100);
283  }))
284  .RetiresOnSaturation();
285  EXPECT_CALL(callbacks, onMessageComplete(_, _))
286  .RetiresOnSaturation();
287  }
288  clientCodec_->setCallback(&callbacks);
289  parseOutput(*clientCodec_);
290  clientCodec_ = HTTPCodecFactory::getCodec(expectedProtocol,
291  TransportDirection::UPSTREAM);
292  }
293  void expectResponse(uint32_t code = 200,
294  ErrorCode errorCode = ErrorCode::NO_ERROR,
295  bool expect100 = false, bool expectGoaway = false) {
296  expectResponses(1, code, errorCode, expect100, expectGoaway);
297  }
298  void expectResponses(uint32_t n, uint32_t code = 200,
299  ErrorCode errorCode = ErrorCode::NO_ERROR,
300  bool expect100 = false, bool expectGoaway = false) {
301  clientCodec_->setCallback(&callbacks_);
302  if (isParallelCodecProtocol(clientCodec_->getProtocol())) {
303  EXPECT_CALL(callbacks_, onSettings(_))
304  .WillOnce(Invoke([this] (const SettingsList& settings) {
305  if (flowControl_[0] > 0) {
306  bool foundInitialWindow = false;
307  for (const auto& setting: settings) {
308  if (setting.id == SettingsId::INITIAL_WINDOW_SIZE) {
309  EXPECT_EQ(flowControl_[0], setting.value);
310  foundInitialWindow = true;
311  }
312  }
313  EXPECT_TRUE(foundInitialWindow);
314  }
315  }));
316  }
317  if (flowControl_[2] > 0) {
318  int64_t sessionDelta =
319  flowControl_[2] - clientCodec_->getDefaultWindowSize();
320  if (clientCodec_->supportsSessionFlowControl() && sessionDelta) {
321  EXPECT_CALL(callbacks_, onWindowUpdate(0, sessionDelta));
322  }
323  }
324  if (flowControl_[1] > 0) {
325  size_t initWindow = flowControl_[0] > 0 ?
326  flowControl_[0] : clientCodec_->getDefaultWindowSize();
327  int64_t streamDelta = flowControl_[1] - initWindow;
328  if (clientCodec_->supportsStreamFlowControl() && streamDelta) {
329  EXPECT_CALL(callbacks_, onWindowUpdate(1, streamDelta));
330  }
331  }
332 
333  if (expectGoaway) {
334  EXPECT_CALL(callbacks_, onGoaway(HTTPCodec::StreamID(1),
335  ErrorCode::NO_ERROR, _));
336  }
337 
338  for (uint32_t i = 0; i < n; i++) {
339  uint8_t times = (expect100) ? 2 : 1;
340  EXPECT_CALL(callbacks_, onMessageBegin(_, _))
341  .Times(times).RetiresOnSaturation();
342  EXPECT_CALL(callbacks_, onHeadersComplete(_, _))
343  .WillOnce(Invoke([code] (HTTPCodec::StreamID,
344  std::shared_ptr<HTTPMessage> msg) {
345  EXPECT_EQ(msg->getStatusCode(), code);
346  }));
347  if (expect100) {
348  EXPECT_CALL(callbacks_, onHeadersComplete(_, _))
349  .WillOnce(Invoke([] (HTTPCodec::StreamID,
350  std::shared_ptr<HTTPMessage> msg) {
351  EXPECT_EQ(msg->getStatusCode(), 100);
352  }))
353  .RetiresOnSaturation();
354  }
355  if (errorCode != ErrorCode::NO_ERROR) {
356  EXPECT_CALL(callbacks_, onAbort(_, _))
357  .WillOnce(Invoke([errorCode] (HTTPCodec::StreamID,
358  ErrorCode error) {
359  EXPECT_EQ(error, errorCode);
360  }));
361  }
362  EXPECT_CALL(callbacks_, onBody(_, _, _)).RetiresOnSaturation();
363  EXPECT_CALL(callbacks_, onMessageComplete(_, _)).RetiresOnSaturation();
364  }
365  parseOutput(*clientCodec_);
366  }
367 
368  void parseOutput(HTTPCodec& clientCodec) {
369  auto writeEvents = transport_->getWriteEvents();
370  while (!breakParseOutput_ &&
371  (!writeEvents->empty() || !parseOutputStream_.empty())) {
372  if (!writeEvents->empty()) {
373  auto event = writeEvents->front();
374  auto vec = event->getIoVec();
375  for (size_t i = 0; i < event->getCount(); i++) {
376  parseOutputStream_.append(
377  IOBuf::copyBuffer(vec[i].iov_base, vec[i].iov_len));
378  }
379  writeEvents->pop_front();
380  }
381  uint32_t consumed = clientCodec.onIngress(*parseOutputStream_.front());
382  parseOutputStream_.split(consumed);
383  }
384  if (!breakParseOutput_) {
385  EXPECT_EQ(parseOutputStream_.chainLength(), 0);
386  }
387  breakParseOutput_ = false;
388  }
389 
391  eventBase_.runInLoop([this] { transport_->resumeWrites(); });
392  }
393 
394  void resumeWritesAfterDelay(milliseconds delay) {
395  eventBase_.runAfterDelay([this] { transport_->resumeWrites(); },
396  delay.count());
397  }
398 
400  auto byteEventTracker = new MockByteEventTracker(nullptr);
401  httpSession_->setByteEventTracker(
402  std::unique_ptr<ByteEventTracker>(byteEventTracker));
403  EXPECT_CALL(*byteEventTracker, preSend(_, _, _))
404  .WillRepeatedly(Return(0));
405  EXPECT_CALL(*byteEventTracker, drainByteEvents())
406  .WillRepeatedly(Return(0));
407  EXPECT_CALL(*byteEventTracker, processByteEvents(_, _))
408  .WillRepeatedly(Invoke([]
409  (std::shared_ptr<ByteEventTracker> self,
410  uint64_t bytesWritten) {
411  return self->ByteEventTracker::processByteEvents(
412  self,
413  bytesWritten);
414  }));
415 
416  return byteEventTracker;
417  }
418 
419  protected:
421  TestAsyncTransport* transport_; // invalid once httpSession_ is destroyed
423  std::vector<int64_t> flowControl_;
427  unique_ptr<HTTPCodec> clientCodec_;
430  bool breakParseOutput_{false};
431  typename C::Codec* rawCodec_{nullptr};
433 };
434 
435 // Uses TestAsyncTransport
438 namespace {
439 class HTTP2DownstreamSessionTest : public HTTPDownstreamTest<HTTP2CodecPair> {
440  public:
441  HTTP2DownstreamSessionTest()
443 
444  void SetUp() override {
446  }
447 
448  void SetupControlStream(HTTPCodec::StreamID cStreamId) {
449  // enable EX_HEADERS
450  clientCodec_->getEgressSettings()->setSetting(
451  SettingsId::ENABLE_EX_HEADERS, 1);
452  clientCodec_->generateSettings(requests_);
453  // create a control stream
454  clientCodec_->generateHeader(requests_, cStreamId, getGetRequest("/cc"),
455  true, nullptr);
456  }
457 
458  void TearDown() override {
459  }
460 };
461 }
462 
463 namespace {
464 class HTTP2DownstreamSessionEarlyShutdownTest :
465 public HTTPDownstreamTest<HTTP2CodecPair> {
466  public:
467  HTTP2DownstreamSessionEarlyShutdownTest()
468  : HTTPDownstreamTest<HTTP2CodecPair>({-1, -1, -1}, false) {}
469 
470  void SetUp() override {
472  }
473 
474  void TearDown() override {
475  }
476 };
477 }
478 
479 TEST_F(HTTP2DownstreamSessionEarlyShutdownTest, EarlyShutdown) {
481 
482  // Try shutting down the session and then starting it. This should be properly
483  // handled by the HTTPSession such that no HTTP/2 frames are sent in the
484  // wrong order.
486  clientCodec_->setCallback(&callbacks);
487  EXPECT_CALL(callbacks, onFrameHeader(_, _, _, _, _)).Times(2);
488  EXPECT_CALL(callbacks, onSettings(_)).Times(1);
489  EXPECT_CALL(callbacks, onGoaway(_, _, _)).Times(1);
490  expectDetachSession();
491  httpSession_->notifyPendingShutdown();
492  httpSession_->startNow();
493  eventBase_.loop();
494  parseOutput(*clientCodec_);
495 }
496 
498  // Send EOF without any request data
499  EXPECT_CALL(mockController_, getRequestHandler(_, _)).Times(0);
500  expectDetachSession();
501 
502  flushRequestsAndLoop(true, milliseconds(0));
503 }
504 
506  InSequence enforceOrder;
507 
508  auto handler = addSimpleNiceHandler();
509  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
510  EXPECT_FALSE(msg->getIsChunked());
511  EXPECT_FALSE(msg->getIsUpgraded());
512  EXPECT_EQ("/", msg->getURL());
513  EXPECT_EQ("/", msg->getPath());
514  EXPECT_EQ("", msg->getQueryString());
515  EXPECT_EQ(1, msg->getHTTPVersion().first);
516  EXPECT_EQ(0, msg->getHTTPVersion().second);
517  });
518  onEOMTerminateHandlerExpectShutdown(*handler);
519 
520  auto req = getGetRequest();
521  req.setHTTPVersion(1, 0);
522  sendRequest(req);
523  flushRequestsAndLoop();
524 }
525 
526 TEST_F(HTTPDownstreamSessionTest, Http10NoHeadersEof) {
527  InSequence enforceOrder;
528 
529  auto handler = addSimpleNiceHandler();
530  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
531  EXPECT_FALSE(msg->getIsChunked());
532  EXPECT_FALSE(msg->getIsUpgraded());
533  EXPECT_EQ("http://example.com/foo?bar", msg->getURL());
534  EXPECT_EQ("/foo", msg->getPath());
535  EXPECT_EQ("bar", msg->getQueryString());
536  EXPECT_EQ(1, msg->getHTTPVersion().first);
537  EXPECT_EQ(0, msg->getHTTPVersion().second);
538  });
539  onEOMTerminateHandlerExpectShutdown(*handler);
540 
541  const char *req = "GET http://example.com/foo?bar HTTP/1.0\r\n\r\n";
542  requests_.append(req, strlen(req));
543  flushRequestsAndLoop(true, milliseconds(0));
544 }
545 
547  InSequence enforceOrder;
548 
549  auto handler = addSimpleNiceHandler();
550  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
551  const HTTPHeaders& hdrs = msg->getHeaders();
552  EXPECT_EQ(2, hdrs.size());
553  EXPECT_TRUE(hdrs.exists("host"));
554  EXPECT_TRUE(hdrs.exists("connection"));
555 
556  EXPECT_FALSE(msg->getIsChunked());
557  EXPECT_FALSE(msg->getIsUpgraded());
558  EXPECT_EQ("/somepath.php?param=foo", msg->getURL());
559  EXPECT_EQ("/somepath.php", msg->getPath());
560  EXPECT_EQ("param=foo", msg->getQueryString());
561  EXPECT_EQ(1, msg->getHTTPVersion().first);
562  EXPECT_EQ(1, msg->getHTTPVersion().second);
563  });
564  onEOMTerminateHandlerExpectShutdown(*handler);
565 
566  addSingleByteReads("GET /somepath.php?param=foo HTTP/1.1\r\n"
567  "Host: example.com\r\n"
568  "Connection: close\r\n"
569  "\r\n");
570  transport_->addReadEOF(milliseconds(0));
571  transport_->startReadEvents();
572  eventBase_.loop();
573 }
574 
575 TEST_F(HTTPDownstreamSessionTest, SingleBytesWithBody) {
576  InSequence enforceOrder;
577 
578  auto handler = addSimpleNiceHandler();
579  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
580  const HTTPHeaders& hdrs = msg->getHeaders();
581  EXPECT_EQ(3, hdrs.size());
582  EXPECT_TRUE(hdrs.exists("host"));
583  EXPECT_TRUE(hdrs.exists("content-length"));
584  EXPECT_TRUE(hdrs.exists("myheader"));
585 
586  EXPECT_FALSE(msg->getIsChunked());
587  EXPECT_FALSE(msg->getIsUpgraded());
588  EXPECT_EQ("/somepath.php?param=foo", msg->getURL());
589  EXPECT_EQ("/somepath.php", msg->getPath());
590  EXPECT_EQ("param=foo", msg->getQueryString());
591  EXPECT_EQ(1, msg->getHTTPVersion().first);
592  EXPECT_EQ(1, msg->getHTTPVersion().second);
593  });
594  EXPECT_CALL(*handler, onBody(_))
595  .WillOnce(ExpectString("1"))
596  .WillOnce(ExpectString("2"))
597  .WillOnce(ExpectString("3"))
598  .WillOnce(ExpectString("4"))
599  .WillOnce(ExpectString("5"));
600  onEOMTerminateHandlerExpectShutdown(*handler);
601 
602  addSingleByteReads("POST /somepath.php?param=foo HTTP/1.1\r\n"
603  "Host: example.com\r\n"
604  "MyHeader: FooBar\r\n"
605  "Content-Length: 5\r\n"
606  "\r\n"
607  "12345");
608  transport_->addReadEOF(milliseconds(0));
609  transport_->startReadEvents();
610  eventBase_.loop();
611 }
612 
614  InSequence enforceOrder;
615 
616  auto handler = addSimpleNiceHandler();
617  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
618  const HTTPHeaders& hdrs = msg->getHeaders();
619  EXPECT_EQ(2, hdrs.size());
620  });
621  EXPECT_CALL(*handler, onBody(_))
622  .WillOnce(ExpectString("12345"))
623  .WillOnce(ExpectString("abcde"));
624  onEOMTerminateHandlerExpectShutdown(*handler);
625 
626  transport_->addReadEvent("POST / HTTP/1.1\r\n"
627  "Host: example.com\r\n"
628  "Content-Length: 10\r\n"
629  "\r\n"
630  "12345", milliseconds(0));
631  transport_->addReadEvent("abcde", milliseconds(5));
632  transport_->addReadEOF(milliseconds(0));
633  transport_->startReadEvents();
634  eventBase_.loop();
635 }
636 
638  InSequence enforceOrder;
639 
640  auto handler = addSimpleNiceHandler();
641  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
642  const HTTPHeaders& hdrs = msg->getHeaders();
643  EXPECT_EQ(3, hdrs.size());
644  EXPECT_TRUE(hdrs.exists("host"));
645  EXPECT_TRUE(hdrs.exists("content-type"));
646  EXPECT_TRUE(hdrs.exists("transfer-encoding"));
647  EXPECT_TRUE(msg->getIsChunked());
648  EXPECT_FALSE(msg->getIsUpgraded());
649  EXPECT_EQ("http://example.com/cgi-bin/foo.aspx?abc&def",
650  msg->getURL());
651  EXPECT_EQ("/cgi-bin/foo.aspx", msg->getPath());
652  EXPECT_EQ("abc&def", msg->getQueryString());
653  EXPECT_EQ(1, msg->getHTTPVersion().first);
654  EXPECT_EQ(1, msg->getHTTPVersion().second);
655  });
656  EXPECT_CALL(*handler, onChunkHeader(3));
657  EXPECT_CALL(*handler, onBody(_))
658  .WillOnce(ExpectString("bar"));
659  EXPECT_CALL(*handler, onChunkComplete());
660  EXPECT_CALL(*handler, onChunkHeader(0x22));
661  EXPECT_CALL(*handler, onBody(_))
662  .WillOnce(ExpectString("0123456789abcdef\nfedcba9876543210\n"));
663  EXPECT_CALL(*handler, onChunkComplete());
664  EXPECT_CALL(*handler, onChunkHeader(3));
665  EXPECT_CALL(*handler, onBody(_))
666  .WillOnce(ExpectString("foo"));
667  EXPECT_CALL(*handler, onChunkComplete());
668  onEOMTerminateHandlerExpectShutdown(*handler);
669 
670  transport_->addReadEvent("POST http://example.com/cgi-bin/foo.aspx?abc&def "
671  "HTTP/1.1\r\n"
672  "Host: example.com\r\n"
673  "Content-Type: text/pla", milliseconds(0));
674  transport_->addReadEvent("in; charset=utf-8\r\n"
675  "Transfer-encoding: chunked\r\n"
676  "\r", milliseconds(2));
677  transport_->addReadEvent("\n"
678  "3\r\n"
679  "bar\r\n"
680  "22\r\n"
681  "0123456789abcdef\n"
682  "fedcba9876543210\n"
683  "\r\n"
684  "3\r", milliseconds(3));
685  transport_->addReadEvent("\n"
686  "foo\r\n"
687  "0\r\n\r\n", milliseconds(1));
688  transport_->startReadEvents();
689  eventBase_.loop();
690 }
691 
693  InSequence enforceOrder;
694 
695  auto handler1 = addSimpleNiceHandler();
696  handler1->expectHeaders();
697  EXPECT_CALL(*handler1, onBody(_))
698  .WillOnce(ExpectString("foo"))
699  .WillOnce(ExpectString("bar9876"));
700  handler1->expectEOM([&] { handler1->sendReply(); });
701  handler1->expectDetachTransaction();
702 
703  auto handler2 = addSimpleNiceHandler();
704  handler2->expectHeaders();
705  EXPECT_CALL(*handler2, onChunkHeader(0xa));
706  EXPECT_CALL(*handler2, onBody(_))
707  .WillOnce(ExpectString("some "))
708  .WillOnce(ExpectString("data\n"));
709  EXPECT_CALL(*handler2, onChunkComplete());
710  onEOMTerminateHandlerExpectShutdown(*handler2);
711 
712  transport_->addReadEvent("POST / HTTP/1.1\r\n"
713  "Host: example.com\r\n"
714  "Content-Length: 10\r\n"
715  "\r\n"
716  "foo", milliseconds(0));
717  transport_->addReadEvent("bar9876"
718  "POST /foo HTTP/1.1\r\n"
719  "Host: exa", milliseconds(2));
720  transport_->addReadEvent("mple.com\r\n"
721  "Connection: close\r\n"
722  "Trans", milliseconds(0));
723  transport_->addReadEvent("fer-encoding: chunked\r\n"
724  "\r\n", milliseconds(2));
725  transport_->addReadEvent("a\r\nsome ", milliseconds(0));
726  transport_->addReadEvent("data\n\r\n0\r\n\r\n", milliseconds(2));
727  transport_->addReadEOF(milliseconds(0));
728  transport_->startReadEvents();
729  eventBase_.loop();
730 }
731 
733  InSequence enforceOrder;
734 
735  auto handler = addSimpleStrictHandler();
736  // Send HTTP 200 OK to accept the CONNECT request
737  handler->expectHeaders([&handler] {
738  handler->sendHeaders(200, 100);
739  });
740 
741  EXPECT_CALL(*handler, onUpgrade(_));
742 
743  // Data should be received using onBody
744  EXPECT_CALL(*handler, onBody(_))
745  .WillOnce(ExpectString("12345"))
746  .WillOnce(ExpectString("abcde"));
747  onEOMTerminateHandlerExpectShutdown(*handler);
748 
749  transport_->addReadEvent("CONNECT test HTTP/1.1\r\n"
750  "\r\n"
751  "12345", milliseconds(0));
752  transport_->addReadEvent("abcde", milliseconds(5));
753  transport_->addReadEOF(milliseconds(0));
754  transport_->startReadEvents();
755  eventBase_.loop();
756 }
757 
759  InSequence enforceOrder;
760 
761  auto handler = addSimpleStrictHandler();
762  // Send HTTP 400 to reject the CONNECT request
763  handler->expectHeaders([&handler] {
764  handler->sendReplyCode(400);
765  });
766 
767  onEOMTerminateHandlerExpectShutdown(*handler);
768 
769  transport_->addReadEvent("CONNECT test HTTP/1.1\r\n"
770  "\r\n"
771  "12345", milliseconds(0));
772  transport_->addReadEvent("abcde", milliseconds(5));
773  transport_->addReadEOF(milliseconds(0));
774  transport_->startReadEvents();
775  eventBase_.loop();
776 }
777 
779  InSequence enforceOrder;
780 
781  auto handler = addSimpleStrictHandler();
782  // Send HTTP 101 Switching Protocls to accept the upgrade request
783  handler->expectHeaders([&handler] {
784  handler->sendHeaders(101, 100);
785  });
786 
787  // Send the response in the new protocol after upgrade
788  EXPECT_CALL(*handler, onUpgrade(_))
789  .WillOnce(Invoke([&handler](UpgradeProtocol /*protocol*/) {
790  handler->sendReplyCode(100);
791  }));
792 
793  onEOMTerminateHandlerExpectShutdown(*handler);
794 
795  HTTPMessage req = getGetRequest();
796  req.getHeaders().add(HTTP_HEADER_UPGRADE, "TEST/1.0");
797  req.getHeaders().add(HTTP_HEADER_CONNECTION, "upgrade");
798  sendRequest(req);
799  flushRequestsAndLoop(true, milliseconds(0));
800 }
801 
802 TEST(HTTPDownstreamTest, ParseErrorNoTxn) {
803  // 1) Get a parse error on SYN_STREAM for streamID == 1
804  // 2) Expect that the codec should be asked to generate an abort on
805  // streamID==1
806  EventBase evb;
807 
808  // Setup the controller and its expecations.
809  NiceMock<MockController> mockController;
810 
811  // Setup the codec, its callbacks, and its expectations.
813  HTTPCodec::Callback* codecCallback = nullptr;
814  EXPECT_CALL(*codec, setCallback(_))
815  .WillRepeatedly(SaveArg<0>(&codecCallback));
816  // Expect egress abort for streamID == 1
817  EXPECT_CALL(*codec, generateRstStream(_, 1, _));
818 
819  // Setup transport
820  bool transportGood = true;
821  auto transport = newMockTransport(&evb);
822  EXPECT_CALL(*transport, good())
823  .WillRepeatedly(ReturnPointee(&transportGood));
824  EXPECT_CALL(*transport, closeNow())
825  .WillRepeatedly(Assign(&transportGood, false));
826  EXPECT_CALL(*transport, writeChain(_, _, _))
827  .WillRepeatedly(
829  const shared_ptr<IOBuf>&, WriteFlags) {
830  callback->writeSuccess();
831  }));
832 
833  // Create the downstream session, thus initializing codecCallback
834  auto transactionTimeouts = makeInternalTimeoutSet(&evb);
835  auto session = new HTTPDownstreamSession(
836  transactionTimeouts.get(),
839  &mockController, std::move(codec),
841  nullptr);
842  session->startNow();
843  HTTPException ex(HTTPException::Direction::INGRESS_AND_EGRESS, "foo");
845  ex.setCodecStatusCode(ErrorCode::REFUSED_STREAM);
846  codecCallback->onError(HTTPCodec::StreamID(1), ex, true);
847 
848  // cleanup
849  session->dropConnection();
850  evb.loop();
851 }
852 
853 TEST(HTTPDownstreamTest, ByteEventsDrained) {
854  // Test that byte events are drained before socket is closed
855  EventBase evb;
856 
857  NiceMock<MockController> mockController;
859  auto byteEventTracker = new MockByteEventTracker(nullptr);
860  auto transport = newMockTransport(&evb);
861  auto transactionTimeouts = makeInternalTimeoutSet(&evb);
862 
863  // Create the downstream session
864  auto session = new HTTPDownstreamSession(
865  transactionTimeouts.get(),
868  &mockController, std::move(codec),
870  nullptr);
871  session->setByteEventTracker(
872  std::unique_ptr<ByteEventTracker>(byteEventTracker));
873 
874  InSequence enforceOrder;
875 
876  session->startNow();
877 
878  // Byte events should be drained first
879  EXPECT_CALL(*byteEventTracker, drainByteEvents())
880  .Times(1);
881  EXPECT_CALL(*transport, closeNow())
882  .Times(AtLeast(1));
883 
884  // Close the socket
885  session->dropConnection();
886  evb.loop();
887 }
888 
889 TEST_F(HTTPDownstreamSessionTest, HttpWithAckTiming) {
890  // This is to test cases where holding a byte event to a finished HTTP/1.1
891  // transaction does not masquerade as HTTP pipelining.
892  auto byteEventTracker = setMockByteEventTracker();
893  InSequence enforceOrder;
894 
895  auto handler1 = addSimpleStrictHandler();
896  handler1->expectHeaders();
897  handler1->expectEOM([&handler1] () {
898  handler1->sendChunkedReplyWithBody(200, 100, 100, false);
899  });
900  // Hold a pending byte event
901  EXPECT_CALL(*byteEventTracker, addLastByteEvent(_, _))
902  .WillOnce(Invoke([] (HTTPTransaction* txn,
903  uint64_t /*byteNo*/) {
905  }));
906  sendRequest();
907  flushRequestsAndLoop();
908  expectResponse();
909 
910  // Send the secode request after receiving the first response (eg: clearly
911  // not pipelined)
912  auto handler2 = addSimpleStrictHandler();
913  handler2->expectHeaders();
914  handler2->expectEOM([&handler2] () {
915  handler2->sendChunkedReplyWithBody(200, 100, 100, false);
916  });
917  // This txn processed and destroyed before txn1
918  EXPECT_CALL(*byteEventTracker, addLastByteEvent(_, _));
919  handler2->expectDetachTransaction();
920 
921  sendRequest();
922  flushRequestsAndLoop();
923  expectResponse();
924 
925  // Now clear the pending byte event (simulate ack) and the first txn
926  // goes away too
927  handler1->expectDetachTransaction();
928  handler1->txn_->decrementPendingByteEvents();
929  gracefulShutdown();
930 }
931 
932 TEST_F(HTTPDownstreamSessionTest, TestOnContentMismatch) {
933  // Test the behavior when the reported content-length on the header
934  // is different from the actual length of the body.
935  // The expectation is simply to log the behavior, such as:
936  // ".. HTTPTransaction.cpp ] Content-Length/body mismatch: expected: .. "
937  folly::EventBase base;
938  InSequence enforceOrder;
939  auto handler1 = addSimpleNiceHandler();
940  handler1->expectHeaders();
941  handler1->expectEOM([&handler1] () {
942  // over-estimate the content-length on the header
943  handler1->sendHeaders(200, 105);
944  handler1->sendBody(100);
945  handler1->txn_->sendEOM();
946  });
947  sendRequest();
948  flushRequestsAndLoop();
949 
950  auto handler2 = addSimpleNiceHandler();
951  handler2->expectHeaders();
952  handler2->expectEOM([&handler2] () {
953  // under-estimate the content-length on the header
954  handler2->sendHeaders(200, 95);
955  handler2->sendBody(100);
956  handler2->txn_->sendEOM();
957  });
958  sendRequest();
959  flushRequestsAndLoop();
960  gracefulShutdown();
961 }
962 
963 TEST_F(HTTPDownstreamSessionTest, HttpWithAckTimingPipeline) {
964  // Test a real pipelining case as well. First request is done waiting for
965  // ack, then receive two pipelined requests.
966  auto byteEventTracker = setMockByteEventTracker();
967  InSequence enforceOrder;
968 
969  auto handler1 = addSimpleStrictHandler();
970  handler1->expectHeaders();
971  handler1->expectEOM([&handler1] () {
972  handler1->sendChunkedReplyWithBody(200, 100, 100, false);
973  });
974  EXPECT_CALL(*byteEventTracker, addLastByteEvent(_, _))
975  .WillOnce(Invoke([] (HTTPTransaction* txn,
976  uint64_t /*byteNo*/) {
978  }));
979  sendRequest();
980  auto handler2 = addSimpleStrictHandler();
981  handler2->expectHeaders();
982  handler2->expectEOM([&handler2] () {
983  handler2->sendChunkedReplyWithBody(200, 100, 100, false);
984  });
985  EXPECT_CALL(*byteEventTracker, addLastByteEvent(_, _));
986  handler2->expectDetachTransaction();
987 
988  sendRequest();
989  sendRequest();
990  auto handler3 = addSimpleStrictHandler();
991  handler3->expectHeaders();
992  handler3->expectEOM([&handler3] () {
993  handler3->sendChunkedReplyWithBody(200, 100, 100, false);
994  });
995  EXPECT_CALL(*byteEventTracker, addLastByteEvent(_, _));
996  handler3->expectDetachTransaction();
997  flushRequestsAndLoop();
998  expectResponses(3);
999  handler1->expectDetachTransaction();
1000  handler1->txn_->decrementPendingByteEvents();
1001  gracefulShutdown();
1002 }
1003 
1004 /*
1005  * The sequence of streams are generated in the following order:
1006  * - [client --> server] regular request 1st stream (getGetRequest())
1007  * - [server --> client] respond 1st stream (res, 100 bytes, without EOM)
1008  * - [server --> client] request 2nd stream (pub, 200 bytes, EOM)
1009  * - [client --> server] respond 2nd stream (OK, EOM)
1010  * - [client --> server] EOM on the 1st stream
1011  */
1012 TEST_F(HTTP2DownstreamSessionTest, ExheaderFromServer) {
1013  auto cStreamId = HTTPCodec::StreamID(1);
1014  SetupControlStream(cStreamId);
1015 
1016  // Create a dummy request and a dummy response messages
1017  auto pub = getGetRequest("/sub/fyi");
1018  // set up the priority for fun
1019  pub.setHTTP2Priority(std::make_tuple(0, false, 7));
1020 
1021  InSequence handlerSequence;
1022  auto cHandler = addSimpleStrictHandler();
1023  StrictMock<MockHTTPHandler> pubHandler;
1024 
1025  cHandler->expectHeaders([&] {
1026  cHandler->txn_->pauseIngress();
1027  // Generate response for the control stream
1028  cHandler->txn_->sendHeaders(getResponse(200, 0));
1029  cHandler->txn_->sendBody(makeBuf(100));
1030 
1031  auto* pubTxn = cHandler->txn_->newExTransaction(&pubHandler);
1032  // Generate a pub request (encapsulated in EX_HEADERS frame)
1033  pubTxn->sendHeaders(pub);
1034  pubTxn->sendBody(makeBuf(200));
1035  pubTxn->sendEOM();
1036  });
1037 
1038  EXPECT_CALL(pubHandler, setTransaction(_));
1039  EXPECT_CALL(callbacks_, onMessageBegin(cStreamId, _));
1040  EXPECT_CALL(callbacks_, onHeadersComplete(cStreamId, _));
1041  EXPECT_CALL(callbacks_, onExMessageBegin(2, _, _, _));
1042  EXPECT_CALL(callbacks_, onHeadersComplete(2, _));
1043  EXPECT_CALL(callbacks_, onMessageComplete(2, _));
1044 
1045  EXPECT_CALL(pubHandler, onHeadersComplete(_));
1046  EXPECT_CALL(pubHandler, onEOM());
1047  EXPECT_CALL(pubHandler, detachTransaction());
1048 
1049  EXPECT_CALL(*cHandler, onEOM());
1050  EXPECT_CALL(*cHandler, detachTransaction());
1051 
1052  transport_->addReadEvent(requests_, milliseconds(0));
1053  transport_->startReadEvents();
1054 
1055  eventBase_.runAfterDelay([&] {
1056  parseOutput(*clientCodec_);
1057  // send a response from client to server
1058  clientCodec_->generateExHeader(requests_, 2, getResponse(200, 0),
1059  HTTPCodec::ExAttributes(cStreamId, false),
1060  true, nullptr);
1061  transport_->addReadEvent(requests_, milliseconds(0));
1062  transport_->startReadEvents();
1063  parseOutput(*clientCodec_);
1064  cHandler->txn_->resumeIngress();
1065  cHandler->txn_->sendEOM();
1066  transport_->addReadEOF(milliseconds(0));
1067  }, 100);
1068 
1069  HTTPSession::DestructorGuard g(httpSession_);
1070  expectDetachSession();
1071  eventBase_.loop();
1072 }
1073 
1074 /*
1075  * The sequence of streams are generated in the following order:
1076  * - [client --> server] regular request on control stream 1
1077  * - [client --> server] Pub request on stream 3
1078  * - [server --> client] response on stream 1 (OK, )
1079  * - [server --> client] response on stream 3 (OK, EOM)
1080  * - [server --> client] response on stream 1 (EOM)
1081  */
1082 TEST_F(HTTP2DownstreamSessionTest, ExheaderFromClient) {
1083  auto cStreamId = HTTPCodec::StreamID(1);
1084  SetupControlStream(cStreamId);
1085 
1086  // generate an EX_HEADERS
1087  auto exStreamId = cStreamId + 2;
1088  clientCodec_->generateExHeader(requests_, exStreamId, getGetRequest("/pub"),
1089  HTTPCodec::ExAttributes(cStreamId, false),
1090  true, nullptr);
1091 
1092  auto cHandler = addSimpleStrictHandler();
1093  cHandler->expectHeaders([&] {
1094  // send back the response for control stream, but EOM
1095  cHandler->txn_->sendHeaders(getResponse(200, 0));
1096  });
1097  EXPECT_CALL(*cHandler, onEOM());
1098 
1099  StrictMock<MockHTTPHandler> pubHandler;
1100  EXPECT_CALL(*cHandler, onExTransaction(_))
1101  .WillOnce(Invoke([&pubHandler] (HTTPTransaction* exTxn) {
1102  exTxn->setHandler(&pubHandler);
1103  pubHandler.txn_ = exTxn;
1104  }));
1105 
1106  InSequence handlerSequence;
1107  EXPECT_CALL(pubHandler, setTransaction(_));
1108  pubHandler.expectHeaders([&] {
1109  // send back the response for the pub request
1110  pubHandler.txn_->sendHeadersWithEOM(getResponse(200, 0));
1111  });
1112  EXPECT_CALL(pubHandler, onEOM());
1113  EXPECT_CALL(pubHandler, detachTransaction());
1114  cHandler->expectDetachTransaction();
1115 
1116  EXPECT_CALL(callbacks_, onMessageBegin(cStreamId, _));
1117  EXPECT_CALL(callbacks_, onHeadersComplete(cStreamId, _));
1118  EXPECT_CALL(callbacks_, onExMessageBegin(exStreamId, _, _, _));
1119  EXPECT_CALL(callbacks_, onHeadersComplete(exStreamId, _));
1120  EXPECT_CALL(callbacks_, onMessageComplete(exStreamId, _));
1121  EXPECT_CALL(callbacks_, onMessageComplete(cStreamId, _));
1122 
1123  transport_->addReadEvent(requests_, milliseconds(0));
1124  transport_->startReadEvents();
1125  transport_->addReadEOF(milliseconds(0));
1126  eventBase_.loop();
1127 
1128  HTTPSession::DestructorGuard g(httpSession_);
1129  expectDetachSession();
1130  cHandler->txn_->sendEOM();
1131  eventBase_.loop();
1132  parseOutput(*clientCodec_);
1133 }
1134 
1135 /*
1136  * The sequence of streams are generated in the following order:
1137  * - [client --> server] regular request 1st stream (getGetRequest())
1138  * - [server --> client] request 2nd stream (unidirectional)
1139  * - [server --> client] response + EOM on the 1st stream
1140  */
1141 TEST_F(HTTP2DownstreamSessionTest, UnidirectionalExTransaction) {
1142  auto cStreamId = HTTPCodec::StreamID(1);
1143  SetupControlStream(cStreamId);
1144  InSequence handlerSequence;
1145  auto cHandler = addSimpleStrictHandler();
1146  StrictMock<MockHTTPHandler> uniHandler;
1147 
1148  cHandler->expectHeaders([&] {
1149  auto* uniTxn = cHandler->txn_->newExTransaction(&uniHandler, true);
1150  EXPECT_TRUE(uniTxn->isIngressComplete());
1151  uniTxn->sendHeaders(getGetRequest("/uni"));
1152  uniTxn->sendEOM();
1153 
1154  // close control stream
1155  cHandler->txn_->sendHeadersWithEOM(getResponse(200, 0));
1156  });
1157 
1158  EXPECT_CALL(uniHandler, setTransaction(_));
1159  EXPECT_CALL(*cHandler, onEOM());
1160  EXPECT_CALL(uniHandler, detachTransaction());
1161  EXPECT_CALL(*cHandler, detachTransaction());
1162 
1163  transport_->addReadEvent(requests_, milliseconds(0));
1164  transport_->startReadEvents();
1165  eventBase_.runAfterDelay([&] {
1166  transport_->addReadEOF(milliseconds(0));
1167  }, 100);
1168 
1169  HTTPSession::DestructorGuard g(httpSession_);
1170  expectDetachSession();
1171  eventBase_.loop();
1172 }
1173 
1174 TEST_F(HTTP2DownstreamSessionTest, PauseResumeControlStream) {
1175  auto cStreamId = HTTPCodec::StreamID(1);
1176  SetupControlStream(cStreamId);
1177 
1178  // generate an EX_HEADERS
1179  clientCodec_->generateExHeader(requests_, cStreamId + 2, getGetRequest(),
1180  HTTPCodec::ExAttributes(cStreamId, false),
1181  true, nullptr);
1182 
1183  auto cHandler = addSimpleStrictHandler();
1184  cHandler->expectHeaders([&] {
1185  cHandler->txn_->pauseIngress();
1186  // send back the response for control stream, but EOM
1187  cHandler->txn_->sendHeaders(getResponse(200, 0));
1188  });
1189  EXPECT_CALL(*cHandler, onEOM());
1190 
1191  StrictMock<MockHTTPHandler> pubHandler;
1192  EXPECT_CALL(*cHandler, onExTransaction(_))
1193  .WillOnce(Invoke([&pubHandler] (HTTPTransaction* exTxn) {
1194  exTxn->setHandler(&pubHandler);
1195  pubHandler.txn_ = exTxn;
1196  }));
1197 
1198  InSequence handlerSequence;
1199  EXPECT_CALL(pubHandler, setTransaction(_));
1200  pubHandler.expectHeaders([&] {
1201  // send back the response for the pub request
1202  pubHandler.txn_->sendHeadersWithEOM(getResponse(200, 0));
1203  });
1204  EXPECT_CALL(pubHandler, onEOM());
1205  EXPECT_CALL(pubHandler, detachTransaction());
1206  cHandler->expectDetachTransaction();
1207 
1208  EXPECT_CALL(callbacks_, onMessageBegin(cStreamId, _));
1209  EXPECT_CALL(callbacks_, onHeadersComplete(cStreamId, _));
1210  EXPECT_CALL(callbacks_, onHeadersComplete(cStreamId + 2, _));
1211  EXPECT_CALL(callbacks_, onMessageComplete(cStreamId + 2, _));
1212  EXPECT_CALL(callbacks_, onMessageComplete(cStreamId, _));
1213 
1214  HTTPSession::DestructorGuard g(httpSession_);
1215  transport_->addReadEvent(requests_, milliseconds(0));
1216  transport_->addReadEOF(milliseconds(0));
1217  transport_->startReadEvents();
1218  eventBase_.loop();
1219 
1220  cHandler->txn_->resumeIngress();
1221  cHandler->txn_->sendEOM();
1222  eventBase_.loop();
1223 
1224  expectDetachSession();
1225  parseOutput(*clientCodec_);
1226 }
1227 
1228 TEST_F(HTTP2DownstreamSessionTest, InvalidControlStream) {
1229  auto cStreamId = HTTPCodec::StreamID(1);
1230  SetupControlStream(cStreamId);
1231 
1232  // generate an EX_HEADERS, but with a non-existing control stream
1233  clientCodec_->generateExHeader(requests_, cStreamId + 2, getGetRequest(),
1234  HTTPCodec::ExAttributes(cStreamId + 4, false),
1235  true, nullptr);
1236 
1237  auto cHandler = addSimpleStrictHandler();
1238  InSequence handlerSequence;
1239  cHandler->expectHeaders([&] {
1240  // send back the response for control stream, but EOM
1241  cHandler->txn_->sendHeaders(getResponse(200, 0));
1242  });
1243  EXPECT_CALL(*cHandler, onExTransaction(_)).Times(0);
1244  EXPECT_CALL(*cHandler, onEOM());
1245  cHandler->expectDetachTransaction();
1246 
1247  EXPECT_CALL(callbacks_, onMessageBegin(cStreamId, _));
1248  EXPECT_CALL(callbacks_, onHeadersComplete(cStreamId, _));
1249  EXPECT_CALL(callbacks_, onAbort(cStreamId + 2, _));
1250 
1251  HTTPSession::DestructorGuard g(httpSession_);
1252  transport_->addReadEvent(requests_, milliseconds(0));
1253  transport_->addReadEOF(milliseconds(0));
1254  transport_->startReadEvents();
1255  eventBase_.loop();
1256 
1257  cHandler->txn_->sendEOM();
1258  eventBase_.loop();
1259 
1260  expectDetachSession();
1261  parseOutput(*clientCodec_);
1262 }
1263 
1264 TEST_F(HTTP2DownstreamSessionTest, SetByteEventTracker) {
1265  InSequence enforceOrder;
1266 
1267  // Send two requests with writes paused, which will queue several byte events,
1268  // including last byte events which are holding a reference to the
1269  // transaction.
1270  transport_->pauseWrites();
1271  auto handler1 = addSimpleStrictHandler();
1272  handler1->expectHeaders();
1273  handler1->expectEOM([&handler1] () {
1274  handler1->sendReplyWithBody(200, 100);
1275  });
1276  auto handler2 = addSimpleStrictHandler();
1277  handler2->expectHeaders();
1278  handler2->expectEOM([&handler2] () {
1279  handler2->sendReplyWithBody(200, 100);
1280  });
1281 
1282  sendRequest();
1283  sendRequest();
1284  // Resume writes from the loop callback
1285  eventBase_.runInLoop([this] {
1286  transport_->resumeWrites();
1287  });
1288 
1289  // Graceful shutdown will notify of GOAWAY
1290  EXPECT_CALL(*handler1, onGoaway(ErrorCode::NO_ERROR));
1291  EXPECT_CALL(*handler2, onGoaway(ErrorCode::NO_ERROR));
1292  // The original byteEventTracker will process the last byte event of the
1293  // first transaction, and detach by deleting the event. Swap out the tracker.
1294  handler1->expectDetachTransaction([this] {
1295  auto tracker = std::make_unique<ByteEventTracker>(httpSession_);
1296  httpSession_->setByteEventTracker(std::move(tracker));
1297  });
1298  // handler2 should also be detached immediately because the new
1299  // ByteEventTracker continues procesing where the old one left off.
1300  handler2->expectDetachTransaction();
1301  gracefulShutdown();
1302 }
1303 
1304 TEST_F(HTTPDownstreamSessionTest, TestTrackedByteEventTracker) {
1305  auto byteEventTracker = setMockByteEventTracker();
1306  InSequence enforceOrder;
1307 
1308  auto handler1 = addSimpleStrictHandler();
1309  size_t bytesToSend = 200;
1310  size_t expectedTrackedByteOffset = bytesToSend + 99;
1311  handler1->expectHeaders();
1312  handler1->expectEOM([&handler1, &bytesToSend] () {
1313  handler1->sendHeaders(200, 200);
1314  handler1->sendBodyWithLastByteTracking(bytesToSend);
1315  handler1->txn_->sendEOM();
1316  });
1317 
1318  EXPECT_CALL(*byteEventTracker,
1319  addTrackedByteEvent(_, expectedTrackedByteOffset))
1320  .WillOnce(Invoke([] (HTTPTransaction* txn,
1321  uint64_t /*byteNo*/) {
1323  }));
1324  sendRequest();
1325  flushRequestsAndLoop();
1326  handler1->expectDetachTransaction();
1327  handler1->txn_->decrementPendingByteEvents();
1328  gracefulShutdown();
1329 }
1330 
1331 TEST_F(HTTP2DownstreamSessionTest, Trailers) {
1332  InSequence enforceOrder;
1333 
1334  auto handler = addSimpleStrictHandler();
1335  handler->expectHeaders();
1336  handler->expectEOM([&handler]() {
1337  handler->sendReplyWithBody(
1338  200, 100, true /* keepalive */, true /* sendEOM */, true /*trailers*/);
1339  });
1340  handler->expectDetachTransaction();
1341 
1342  HTTPSession::DestructorGuard g(httpSession_);
1343  sendRequest();
1344  flushRequestsAndLoop(true, milliseconds(0));
1345 
1346  EXPECT_CALL(callbacks_, onMessageBegin(1, _)).Times(1);
1347  EXPECT_CALL(callbacks_, onHeadersComplete(1, _)).Times(1);
1348  EXPECT_CALL(callbacks_, onBody(1, _, _));
1349  EXPECT_CALL(callbacks_, onTrailersComplete(1, _));
1350  EXPECT_CALL(callbacks_, onMessageComplete(1, _));
1351 
1352  parseOutput(*clientCodec_);
1353  expectDetachSession();
1354 }
1355 
1357  testChunks(true);
1358 }
1359 
1361  testChunks(false);
1362 }
1363 
1364 template <class C>
1366  InSequence enforceOrder;
1367 
1368  auto handler = addSimpleStrictHandler();
1369  handler->expectHeaders();
1370  handler->expectEOM([&handler, trailers] () {
1371  handler->sendChunkedReplyWithBody(200, 100, 17, trailers);
1372  });
1373  handler->expectDetachTransaction();
1374 
1375  HTTPSession::DestructorGuard g(httpSession_);
1376  sendRequest();
1377  flushRequestsAndLoop(true, milliseconds(0));
1378 
1379  EXPECT_CALL(callbacks_, onMessageBegin(1, _))
1380  .Times(1);
1381  EXPECT_CALL(callbacks_, onHeadersComplete(1, _))
1382  .Times(1);
1383  for (int i = 0; i < 6; i++) {
1384  EXPECT_CALL(callbacks_, onChunkHeader(1, _));
1385  EXPECT_CALL(callbacks_, onBody(1, _, _));
1386  EXPECT_CALL(callbacks_, onChunkComplete(1));
1387  }
1388  if (trailers) {
1389  EXPECT_CALL(callbacks_, onTrailersComplete(1, _));
1390  }
1391  EXPECT_CALL(callbacks_, onMessageComplete(1, _));
1392 
1393  parseOutput(*clientCodec_);
1394  expectDetachSession();
1395 }
1396 
1398  InSequence enforceOrder;
1399 
1400  auto handler1 = addSimpleStrictHandler();
1401  handler1->expectHeaders([this, &handler1] {
1402  handler1->sendHeaders(200, 100);
1403  httpSession_->notifyPendingShutdown();
1404  });
1405  handler1->expectEOM([&handler1] {
1406  handler1->sendBody(100);
1407  handler1->txn_->sendEOM();
1408  });
1409  handler1->expectDetachTransaction();
1410 
1411  auto handler2 = addSimpleStrictHandler();
1412  handler2->expectHeaders([&handler2] {
1413  handler2->sendHeaders(200, 100);
1414  });
1415  handler2->expectEOM([&handler2] {
1416  handler2->sendBody(100);
1417  handler2->txn_->sendEOM();
1418  });
1419  handler2->expectDetachTransaction();
1420 
1421  expectDetachSession();
1422 
1423  sendRequest();
1424  sendRequest();
1425  flushRequestsAndLoop();
1426 }
1427 
1428 // 1) receive full request
1429 // 2) notify pending shutdown
1430 // 3) wait for session read timeout -> should be ignored
1431 // 4) response completed
1432 TEST_F(HTTPDownstreamSessionTest, HttpDrainLongRunning) {
1433  InSequence enforceSequence;
1434 
1435  auto handler = addSimpleStrictHandler();
1436  handler->expectHeaders([this, &handler] {
1437  httpSession_->notifyPendingShutdown();
1438  eventBase_.tryRunAfterDelay([this] {
1439  // simulate read timeout
1440  httpSession_->timeoutExpired();
1441  }, 100);
1442  eventBase_.tryRunAfterDelay([&handler] {
1443  handler->sendReplyWithBody(200, 100);
1444  }, 200);
1445  });
1446  handler->expectEOM();
1447  handler->expectDetachTransaction();
1448 
1449  expectDetachSession();
1450 
1451  sendRequest();
1452  flushRequestsAndLoop();
1453 }
1454 
1457 
1458  InSequence enforceOrder;
1459  EXPECT_CALL(mockController_, getRequestHandler(_, _))
1460  .WillOnce(Return(&handler));
1461 
1462  EXPECT_CALL(handler, setTransaction(_))
1463  .WillOnce(Invoke([&] (HTTPTransaction* txn) {
1464  handler.txn_ = txn;
1465  handler.txn_->sendAbort();
1466  }));
1467  handler.expectDetachTransaction();
1468  expectDetachSession();
1469 
1470  addSingleByteReads("GET /somepath.php?param=foo HTTP/1.1\r\n"
1471  "Host: example.com\r\n"
1472  "Connection: close\r\n"
1473  "\r\n");
1474  transport_->addReadEOF(milliseconds(0));
1475  transport_->startReadEvents();
1476  eventBase_.loop();
1477 }
1478 
1479 TEST_F(SPDY3DownstreamSessionTest, HttpPausedBuffered) {
1481  auto s = sendRequest();
1482  clientCodec_->generateRstStream(rst, s, ErrorCode::CANCEL);
1483  sendRequest();
1484 
1485  InSequence handlerSequence;
1486  auto handler1 = addSimpleNiceHandler();
1487  handler1->expectHeaders();
1488  handler1->expectEOM([&handler1, this] {
1489  transport_->pauseWrites();
1490  handler1->sendHeaders(200, 65536 * 2);
1491  handler1->sendBody(65536 * 2);
1492  });
1493  handler1->expectEgressPaused();
1494  auto handler2 = addSimpleNiceHandler();
1495  handler2->expectEgressPaused();
1496  handler2->expectHeaders();
1497  handler2->expectEOM([&] {
1498  eventBase_.runInLoop([&] {
1499  transport_->addReadEvent(rst, milliseconds(0)); });
1500  });
1501  handler1->expectError([&] (const HTTPException& ex) {
1503  resumeWritesInLoop();
1504  });
1505  handler1->expectDetachTransaction();
1506  handler2->expectEgressResumed([&] {
1507  handler2->sendReplyWithBody(200, 32768);
1508  });
1509  handler2->expectDetachTransaction([this] {
1510  eventBase_.runInLoop([&] { transport_->addReadEOF(milliseconds(0)); });
1511  });
1512  expectDetachSession();
1513 
1514  flushRequestsAndLoop();
1515 }
1516 
1517 TEST_F(HTTPDownstreamSessionTest, HttpWritesDrainingTimeout) {
1518  sendRequest();
1519  sendHeader();
1520 
1521  InSequence handlerSequence;
1522  auto handler1 = addSimpleNiceHandler();
1523  handler1->expectHeaders();
1524  handler1->expectEOM([&handler1, this] {
1525  transport_->pauseWrites();
1526  handler1->sendHeaders(200, 1000);
1527  });
1528  handler1->expectError([&] (const HTTPException& ex) {
1530  ASSERT_EQ(
1531  folly::to<std::string>("WriteTimeout on transaction id: ",
1532  handler1->txn_->getID()),
1533  std::string(ex.what()));
1534  handler1->txn_->sendAbort();
1535  });
1536  handler1->expectDetachTransaction();
1537  expectDetachSession();
1538 
1539  flushRequestsAndLoop();
1540 }
1541 
1542 TEST_F(HTTPDownstreamSessionTest, HttpRateLimitNormal) {
1543  // The rate-limiting code grabs the event base from the EventBaseManager,
1544  // so we need to set it.
1545  folly::EventBaseManager::get()->setEventBase(&eventBase_, false);
1546 
1547  // Create a request
1548  sendRequest();
1549 
1550  InSequence handlerSequence;
1551 
1552  // Set a low rate-limit on the transaction
1553  auto handler1 = addSimpleNiceHandler();
1554  handler1->expectHeaders([&] {
1555  uint32_t rateLimit_kbps = 640;
1556  handler1->txn_->setEgressRateLimit(rateLimit_kbps * 1024);
1557  });
1558  // Send a somewhat big response that we know will get rate-limited
1559  handler1->expectEOM([&handler1] {
1560  // At 640kbps, this should take slightly over 800ms
1561  uint32_t rspLengthBytes = 100000;
1562  handler1->sendHeaders(200, rspLengthBytes);
1563  handler1->sendBody(rspLengthBytes);
1564  handler1->txn_->sendEOM();
1565  });
1566  handler1->expectDetachTransaction();
1567 
1568  // Keep the session around even after the event base loop completes so we can
1569  // read the counters on a valid object.
1570  HTTPSession::DestructorGuard g(httpSession_);
1571  flushRequestsAndLoop();
1572 
1573  proxygen::TimePoint timeFirstWrite =
1574  transport_->getWriteEvents()->front()->getTime();
1575  proxygen::TimePoint timeLastWrite =
1576  transport_->getWriteEvents()->back()->getTime();
1577  int64_t writeDuration =
1578  (int64_t)millisecondsBetween(timeLastWrite, timeFirstWrite).count();
1579  EXPECT_GE(writeDuration, 800);
1580 
1581  cleanup();
1582 }
1583 
1584 TEST_F(SPDY3DownstreamSessionTest, SpdyRateLimitNormal) {
1585  // The rate-limiting code grabs the event base from the EventBaseManager,
1586  // so we need to set it.
1587  folly::EventBaseManager::get()->setEventBase(&eventBase_, false);
1588 
1589  clientCodec_->getEgressSettings()->setSetting(SettingsId::INITIAL_WINDOW_SIZE,
1590  100000);
1591  clientCodec_->generateSettings(requests_);
1592  sendRequest();
1593 
1594  InSequence handlerSequence;
1595  auto handler1 = addSimpleNiceHandler();
1596  handler1->expectHeaders([&] {
1597  uint32_t rateLimit_kbps = 640;
1598  handler1->txn_->setEgressRateLimit(rateLimit_kbps * 1024);
1599  });
1600 
1601  handler1->expectEOM([&handler1] {
1602  // At 640kbps, this should take slightly over 800ms
1603  uint32_t rspLengthBytes = 100000;
1604  handler1->sendHeaders(200, rspLengthBytes);
1605  handler1->sendBody(rspLengthBytes);
1606  handler1->txn_->sendEOM();
1607  });
1608  handler1->expectDetachTransaction();
1609 
1610  // Keep the session around even after the event base loop completes so we can
1611  // read the counters on a valid object.
1612  HTTPSession::DestructorGuard g(httpSession_);
1613  flushRequestsAndLoop(true, milliseconds(50));
1614 
1615  proxygen::TimePoint timeFirstWrite =
1616  transport_->getWriteEvents()->front()->getTime();
1617  proxygen::TimePoint timeLastWrite =
1618  transport_->getWriteEvents()->back()->getTime();
1619  int64_t writeDuration =
1620  (int64_t)millisecondsBetween(timeLastWrite, timeFirstWrite).count();
1621  EXPECT_GE(writeDuration, 800);
1622  expectDetachSession();
1623 }
1624 
1630  // The rate-limiting code grabs the event base from the EventBaseManager,
1631  // so we need to set it.
1632  folly::EventBaseManager::get()->setEventBase(&eventBase_, false);
1633 
1635  clientCodec_->getEgressSettings()->setSetting(SettingsId::INITIAL_WINDOW_SIZE,
1636  100000);
1637  clientCodec_->generateSettings(requests_);
1638  auto streamID = sendRequest();
1639  clientCodec_->generateRstStream(rst, streamID, ErrorCode::CANCEL);
1640 
1641  InSequence handlerSequence;
1642  auto handler1 = addSimpleNiceHandler();
1643  handler1->expectHeaders([&] {
1644  uint32_t rateLimit_kbps = 640;
1645  handler1->txn_->setEgressRateLimit(rateLimit_kbps * 1024);
1646  });
1647  handler1->expectEOM([&handler1] {
1648  uint32_t rspLengthBytes = 100000;
1649  handler1->sendHeaders(200, rspLengthBytes);
1650  handler1->sendBody(rspLengthBytes);
1651  handler1->txn_->sendEOM();
1652  });
1653  handler1->expectError();
1654  handler1->expectDetachTransaction();
1655  expectDetachSession();
1656 
1657  flushRequestsAndLoop(true, milliseconds(50), milliseconds(0), [&] {
1658  transport_->addReadEvent(rst, milliseconds(10));
1659  });
1660 }
1661 
1662 // Send a 1.0 request, egress the EOM with the last body chunk on a paused
1663 // socket, and let it timeout. dropConnection()
1664 // to removeTransaction with writesDraining_=true
1666  HTTPMessage req = getGetRequest();
1667  req.setHTTPVersion(1, 0);
1668  sendRequest(req);
1669 
1670  InSequence handlerSequence;
1671  auto handler1 = addSimpleNiceHandler();
1672  handler1->expectHeaders();
1673  handler1->expectEOM([&handler1, this] {
1674  handler1->sendHeaders(200, 100);
1675  eventBase_.tryRunAfterDelay([&handler1, this] {
1676  transport_->pauseWrites();
1677  handler1->sendBody(100);
1678  handler1->txn_->sendEOM();
1679  }, 50);
1680  });
1681  handler1->expectError([&] (const HTTPException& ex) {
1683  ASSERT_EQ(folly::to<std::string>("WriteTimeout on transaction id: ",
1684  handler1->txn_->getID()),
1685  std::string(ex.what()));
1686  });
1687  handler1->expectDetachTransaction();
1688 
1689  expectDetachSession();
1690 
1691  flushRequestsAndLoop();
1692 }
1693 
1694 // Send an abort from the write timeout path while pipelining
1695 TEST_F(HTTPDownstreamSessionTest, WriteTimeoutPipeline) {
1696  const char* buf = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"
1697  "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n";
1698  requests_.append(buf, strlen(buf));
1699 
1700  InSequence handlerSequence;
1701  auto handler1 = addSimpleNiceHandler();
1702  handler1->expectHeaders();
1703  handler1->expectEOM([&handler1, this] {
1704  handler1->sendHeaders(200, 100);
1705  eventBase_.tryRunAfterDelay([&handler1, this] {
1706  transport_->pauseWrites();
1707  handler1->sendBody(100);
1708  handler1->txn_->sendEOM();
1709  }, 50);
1710  });
1711  auto handler2 = addSimpleNiceHandler();
1712  handler2->expectHeaders();
1713  handler2->expectEOM();
1714  handler1->expectError([&] (const HTTPException& ex) {
1716  ASSERT_EQ(folly::to<std::string>("WriteTimeout on transaction id: ",
1717  handler1->txn_->getID()),
1718  std::string(ex.what()));
1719  handler1->txn_->sendAbort();
1720  });
1721  handler2->expectError([&] (const HTTPException& ex) {
1723  ASSERT_EQ(folly::to<std::string>("WriteTimeout on transaction id: ",
1724  handler2->txn_->getID()),
1725  std::string(ex.what()));
1726  handler2->txn_->sendAbort();
1727  });
1728  handler2->expectDetachTransaction();
1729  handler1->expectDetachTransaction();
1730  expectDetachSession();
1731 
1732  flushRequestsAndLoop();
1733 }
1734 
1735 TEST_F(HTTPDownstreamSessionTest, BodyPacketization) {
1736  HTTPMessage req = getGetRequest();
1737  req.setHTTPVersion(1, 0);
1738  req.setWantsKeepalive(false);
1739  sendRequest(req);
1740 
1741  InSequence handlerSequence;
1742  auto handler1 = addSimpleNiceHandler();
1743  handler1->expectHeaders();
1744  handler1->expectEOM([&handler1] {
1745  handler1->sendReplyWithBody(200, 32768);
1746  });
1747  handler1->expectDetachTransaction();
1748 
1749  expectDetachSession();
1750 
1751  // Keep the session around even after the event base loop completes so we can
1752  // read the counters on a valid object.
1753  HTTPSession::DestructorGuard g(httpSession_);
1754  flushRequestsAndLoop();
1755 
1756  EXPECT_EQ(transport_->getWriteEvents()->size(), 1);
1757 }
1758 
1759 TEST_F(HTTPDownstreamSessionTest, HttpMalformedPkt1) {
1760  // Create a HTTP connection and keep sending just '\n' to the HTTP1xCodec.
1761  std::string data(90000, '\n');
1762  requests_.append(data.data(), data.length());
1763 
1764  expectDetachSession();
1765 
1766  flushRequestsAndLoop(true, milliseconds(0));
1767 }
1768 
1769 TEST_F(HTTPDownstreamSessionTest, BigExplcitChunkWrite) {
1770  // even when the handler does a massive write, the transport only gets small
1771  // writes
1772  sendRequest();
1773 
1774  auto handler = addSimpleNiceHandler();
1775  handler->expectHeaders([&handler] {
1776  handler->sendHeaders(200, 100, false);
1777  size_t len = 16 * 1024 * 1024;
1778  handler->txn_->sendChunkHeader(len);
1779  auto chunk = makeBuf(len);
1780  handler->txn_->sendBody(std::move(chunk));
1781  handler->txn_->sendChunkTerminator();
1782  handler->txn_->sendEOM();
1783  });
1784  handler->expectDetachTransaction();
1785 
1786  expectDetachSession();
1787 
1788  // Keep the session around even after the event base loop completes so we can
1789  // read the counters on a valid object.
1790  HTTPSession::DestructorGuard g(httpSession_);
1791  flushRequestsAndLoop();
1792 
1793  EXPECT_GT(transport_->getWriteEvents()->size(), 250);
1794 }
1795 
1796 
1797 // ==== upgrade tests ====
1798 
1799 // Test upgrade to a protocol unknown to HTTPSession
1800 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNonNative) {
1801  auto handler = addSimpleStrictHandler();
1802 
1803  handler->expectHeaders([&handler] {
1804  handler->sendHeaders(101, 0, true, {{"Upgrade", "blarf"}});
1805  });
1806  EXPECT_CALL(*handler, onUpgrade(UpgradeProtocol::TCP));
1807  handler->expectEOM([&handler] {
1808  handler->txn_->sendEOM();
1809  });
1810  handler->expectDetachTransaction();
1811 
1812  sendRequest(getUpgradeRequest("blarf"));
1813  expectDetachSession();
1814  flushRequestsAndLoop(true);
1815 }
1816 
1817 // Test upgrade to a protocol unknown to HTTPSession, but don't switch
1818 // protocols
1819 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNonNativeIgnore) {
1820  auto handler = addSimpleStrictHandler();
1821 
1822  handler->expectHeaders([&handler] {
1823  handler->sendReplyWithBody(200, 100);
1824  });
1825  handler->expectEOM();
1826  handler->expectDetachTransaction();
1827 
1828  sendRequest(getUpgradeRequest("blarf"));
1829 
1830  expectDetachSession();
1831  flushRequestsAndLoop(true);
1832 }
1833 
1834 
1835 // Test upgrade to a protocol unknown to HTTPSession
1836 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNonNativePipeline) {
1837  auto handler1 = addSimpleStrictHandler();
1838 
1839  handler1->expectHeaders([&handler1] (std::shared_ptr<HTTPMessage> msg) {
1840  EXPECT_EQ(msg->getHeaders().getSingleOrEmpty(HTTP_HEADER_UPGRADE),
1841  "blarf");
1842  handler1->sendReplyWithBody(200, 100);
1843  });
1844  handler1->expectEOM();
1845  handler1->expectDetachTransaction();
1846 
1847  auto handler2 = addSimpleStrictHandler();
1848  handler2->expectHeaders([&handler2] {
1849  handler2->sendReplyWithBody(200, 100);
1850  });
1851  handler2->expectEOM();
1852  handler2->expectDetachTransaction();
1853 
1854  sendRequest(getUpgradeRequest("blarf"));
1855  transport_->addReadEvent("GET / HTTP/1.1\r\n"
1856  "\r\n");
1857  expectDetachSession();
1858  flushRequestsAndLoop(true);
1859 }
1860 
1861 // Helper that does a simple upgrade test - request an upgrade, receive a 101
1862 // and an upgraded response
1863 template <class C>
1865  const std::string& upgradeHeader,
1866  CodecProtocol expectedProtocol,
1867  const std::string& expectedUpgradeHeader) {
1868  this->rawCodec_->setAllowedUpgradeProtocols({expectedUpgradeHeader});
1869 
1870  auto handler = addSimpleStrictHandler();
1871 
1872  HeaderIndexingStrategy testH2IndexingStrat;
1873  handler->expectHeaders();
1874  EXPECT_CALL(mockController_, onSessionCodecChange(httpSession_));
1875  handler->expectEOM(
1876  [&handler, expectedProtocol, expectedUpgradeHeader, &testH2IndexingStrat] {
1877  EXPECT_FALSE(handler->txn_->getSetupTransportInfo().secure);
1878  EXPECT_EQ(*handler->txn_->getSetupTransportInfo().appProtocol,
1879  expectedUpgradeHeader);
1880  if (expectedProtocol == CodecProtocol::HTTP_2) {
1881  const HTTP2Codec* codec = dynamic_cast<const HTTP2Codec*>(
1882  &handler->txn_->getTransport().getCodec());
1883  ASSERT_NE(codec, nullptr);
1884  EXPECT_EQ(codec->getHeaderIndexingStrategy(), &testH2IndexingStrat);
1885  }
1886  handler->sendReplyWithBody(200, 100);
1887  });
1888  handler->expectDetachTransaction();
1889 
1890  if (expectedProtocol == CodecProtocol::HTTP_2) {
1891  EXPECT_CALL(mockController_, getHeaderIndexingStrategy())
1892  .WillOnce(
1893  Return(&testH2IndexingStrat)
1894  );
1895  }
1896 
1897  HTTPMessage req = getUpgradeRequest(upgradeHeader);
1898  if (upgradeHeader == http2::kProtocolCleartextString) {
1899  HTTP2Codec::requestUpgrade(req);
1900  }
1901  sendRequest(req);
1902  flushRequestsAndLoop();
1903 
1904  expect101(expectedProtocol, expectedUpgradeHeader);
1905  expectResponse();
1906 
1907  gracefulShutdown();
1908 }
1909 
1910 // Upgrade to SPDY/3
1911 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNative3) {
1912  testSimpleUpgrade("spdy/3", CodecProtocol::SPDY_3, "spdy/3");
1913 }
1914 
1915 // Upgrade to SPDY/3.1
1916 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNative31) {
1917  testSimpleUpgrade("spdy/3.1", CodecProtocol::SPDY_3_1, "spdy/3.1");
1918 }
1919 
1920 // Upgrade to HTTP/2
1921 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNativeH2) {
1922  testSimpleUpgrade("h2c", CodecProtocol::HTTP_2, "h2c");
1923 }
1924 
1926  public HTTPDownstreamSessionTest {
1927  public:
1929  : HTTPDownstreamSessionTest({100000, 105000, 110000}) {}
1930 };
1931 
1932 // Upgrade to HTTP/2, with non-default flow control settings
1934  testSimpleUpgrade("h2c", CodecProtocol::HTTP_2, "h2c");
1935 }
1936 
1937 // Upgrade to SPDY/3.1 with a non-native proto in the list
1938 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNativeUnknown) {
1939  // This is maybe weird, the client asked for non-native as first choice,
1940  // but we go native
1941  testSimpleUpgrade("blarf, spdy/3.1, spdy/3",
1942  CodecProtocol::SPDY_3_1, "spdy/3.1");
1943 }
1944 
1945 // Upgrade header with extra whitespace
1946 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNativeWhitespace) {
1947  testSimpleUpgrade(" \tspdy/3.1\t , spdy/3",
1948  CodecProtocol::SPDY_3_1, "spdy/3.1");
1949 }
1950 
1951 // Upgrade header with random junk
1952 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNativeJunk) {
1953  testSimpleUpgrade(",,,, ,,\t~^%$(*&@(@$^^*(,spdy/3",
1954  CodecProtocol::SPDY_3, "spdy/3");
1955 }
1956 
1957 // Attempt to upgrade on second txn
1958 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNativeTxn2) {
1959  this->rawCodec_->setAllowedUpgradeProtocols({"spdy/3"});
1960  auto handler1 = addSimpleStrictHandler();
1961  handler1->expectHeaders();
1962  handler1->expectEOM([&handler1] {
1963  handler1->sendReplyWithBody(200, 100);
1964  });
1965  handler1->expectDetachTransaction();
1966  sendRequest(getGetRequest());
1967  flushRequestsAndLoop();
1968  expectResponse();
1969 
1970  auto handler2 = addSimpleStrictHandler();
1971  handler2->expectHeaders();
1972  handler2->expectEOM([&handler2] {
1973  handler2->sendReplyWithBody(200, 100);
1974  });
1975  handler2->expectDetachTransaction();
1976 
1977  sendRequest(getUpgradeRequest("spdy/3"));
1978  flushRequestsAndLoop();
1979  expectResponse();
1980  gracefulShutdown();
1981 }
1982 
1983 // Upgrade on POST
1984 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNativePost) {
1985  this->rawCodec_->setAllowedUpgradeProtocols({"spdy/3"});
1986  auto handler = addSimpleStrictHandler();
1987  handler->expectHeaders();
1988  handler->expectBody();
1989  EXPECT_CALL(mockController_, onSessionCodecChange(httpSession_));
1990  handler->expectEOM([&handler] {
1991  handler->sendReplyWithBody(200, 100);
1992  });
1993  handler->expectDetachTransaction();
1994 
1995  HTTPMessage req = getUpgradeRequest("spdy/3", HTTPMethod::POST, 10);
1996  auto streamID = sendRequest(req, false);
1997  clientCodec_->generateBody(requests_, streamID, makeBuf(10),
1998  HTTPCodec::NoPadding, true);
1999  // cheat and not sending EOM, it's a no-op
2000  flushRequestsAndLoop();
2001  expect101(CodecProtocol::SPDY_3, "spdy/3");
2002  expectResponse();
2003  gracefulShutdown();
2004 }
2005 
2006 // Upgrade on POST with a reply that comes before EOM, don't switch protocols
2007 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNativePostEarlyResp) {
2008  this->rawCodec_->setAllowedUpgradeProtocols({"spdy/3"});
2009  auto handler = addSimpleStrictHandler();
2010  handler->expectHeaders([&handler] {
2011  handler->sendReplyWithBody(200, 100);
2012  });
2013  handler->expectBody();
2014  handler->expectEOM();
2015  handler->expectDetachTransaction();
2016 
2017  HTTPMessage req = getUpgradeRequest("spdy/3", HTTPMethod::POST, 10);
2018  auto streamID = sendRequest(req, false);
2019  clientCodec_->generateBody(requests_, streamID, makeBuf(10),
2020  HTTPCodec::NoPadding, true);
2021  flushRequestsAndLoop();
2022  expectResponse();
2023  gracefulShutdown();
2024 }
2025 
2026 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNativePostEarlyPartialResp) {
2027  this->rawCodec_->setAllowedUpgradeProtocols({"spdy/3"});
2028  auto handler = addSimpleStrictHandler();
2029  handler->expectHeaders([&handler] {
2030  handler->sendHeaders(200, 100);
2031  });
2032  handler->expectBody();
2033  handler->expectEOM([&handler] {
2034  handler->sendBody(100);
2035  handler->txn_->sendEOM();
2036  });
2037  handler->expectDetachTransaction();
2038 
2039  HTTPMessage req = getUpgradeRequest("spdy/3", HTTPMethod::POST, 10);
2040  auto streamID = sendRequest(req, false);
2041  clientCodec_->generateBody(requests_, streamID, makeBuf(10),
2042  HTTPCodec::NoPadding, true);
2043  flushRequestsAndLoop();
2044  expectResponse();
2045  gracefulShutdown();
2046 }
2047 
2048 // Upgrade but with a pipelined HTTP request. It is parsed as SPDY and
2049 // rejected
2050 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNativeExtra) {
2051  this->rawCodec_->setAllowedUpgradeProtocols({"spdy/3"});
2052  auto handler = addSimpleStrictHandler();
2053  handler->expectHeaders();
2054  EXPECT_CALL(mockController_, onSessionCodecChange(httpSession_));
2055  handler->expectEOM([&handler] {
2056  handler->sendReplyWithBody(200, 100);
2057  });
2058  handler->expectDetachTransaction();
2059 
2060  sendRequest(getUpgradeRequest("spdy/3"));
2061  // It's a fatal to send this out on the HTTP1xCodec, so hack it manually
2062  transport_->addReadEvent("GET / HTTP/1.1\r\n"
2063  "Upgrade: spdy/3\r\n"
2064  "\r\n");
2065  flushRequestsAndLoop();
2066  expect101(CodecProtocol::SPDY_3, "spdy/3");
2067  expectResponse(200, ErrorCode::_SPDY_INVALID_STREAM);
2068  gracefulShutdown();
2069 }
2070 
2071 // Upgrade on POST with Expect: 100-Continue. If the 100 goes out
2072 // before the EOM is parsed, the 100 will be in HTTP. This should be the normal
2073 // case since the client *should* wait a bit for the 100 continue to come back
2074 // before sending the POST. But if the 101 is delayed beyond EOM, the 101
2075 // will come via SPDY.
2076 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNativePost100) {
2077  this->rawCodec_->setAllowedUpgradeProtocols({"spdy/3"});
2078  auto handler = addSimpleStrictHandler();
2079  handler->expectHeaders([&handler] {
2080  handler->sendHeaders(100, 0);
2081  });
2082  handler->expectBody();
2083  EXPECT_CALL(mockController_, onSessionCodecChange(httpSession_));
2084  handler->expectEOM([&handler] {
2085  handler->sendReplyWithBody(200, 100);
2086  });
2087  handler->expectDetachTransaction();
2088 
2089  HTTPMessage req = getUpgradeRequest("spdy/3", HTTPMethod::POST, 10);
2090  req.getHeaders().add(HTTP_HEADER_EXPECT, "100-continue");
2091  auto streamID = sendRequest(req, false);
2092  clientCodec_->generateBody(requests_, streamID, makeBuf(10),
2093  HTTPCodec::NoPadding, true);
2094  flushRequestsAndLoop();
2095  expect101(CodecProtocol::SPDY_3, "spdy/3", true /* expect 100 continue */);
2096  expectResponse();
2097  gracefulShutdown();
2098 }
2099 
2100 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeNativePost100Late) {
2101  this->rawCodec_->setAllowedUpgradeProtocols({"spdy/3"});
2102  auto handler = addSimpleStrictHandler();
2103  handler->expectHeaders();
2104  handler->expectBody();
2105  EXPECT_CALL(mockController_, onSessionCodecChange(httpSession_));
2106  handler->expectEOM([&handler] {
2107  handler->sendHeaders(100, 0);
2108  handler->sendReplyWithBody(200, 100);
2109  });
2110  handler->expectDetachTransaction();
2111 
2112  HTTPMessage req = getUpgradeRequest("spdy/3", HTTPMethod::POST, 10);
2113  req.getHeaders().add(HTTP_HEADER_EXPECT, "100-continue");
2114  auto streamID = sendRequest(req, false);
2115  clientCodec_->generateBody(requests_, streamID, makeBuf(10),
2116  HTTPCodec::NoPadding, true);
2117  flushRequestsAndLoop();
2118  expect101(CodecProtocol::SPDY_3, "spdy/3");
2119  expectResponse(200, ErrorCode::NO_ERROR, true /* expect 100 via SPDY */);
2120  gracefulShutdown();
2121 }
2122 
2123 
2125  testPriorities(8);
2126 
2127  cleanup();
2128 }
2129 
2130 // Test sending a GOAWAY while the downstream session is still processing
2131 // the request that was an upgrade. The reply GOAWAY should have last good
2132 // stream = 1, not 0.
2133 TEST_F(HTTPDownstreamSessionTest, HttpUpgradeGoawayDrain) {
2134  this->rawCodec_->setAllowedUpgradeProtocols({"h2c"});
2135  auto handler = addSimpleStrictHandler();
2136  handler->expectHeaders();
2137  handler->expectBody();
2138  EXPECT_CALL(mockController_, onSessionCodecChange(httpSession_));
2139  handler->expectEOM();
2140  handler->expectGoaway();
2141  handler->expectDetachTransaction();
2142 
2143  EXPECT_CALL(mockController_, getHeaderIndexingStrategy())
2144  .WillOnce(
2145  Return(&testH2IndexingStrat_)
2146  );
2147 
2148  HTTPMessage req = getUpgradeRequest("h2c", HTTPMethod::POST, 10);
2149  HTTP2Codec::requestUpgrade(req);
2150  auto streamID = sendRequest(req, false);
2151  clientCodec_->generateBody(requests_, streamID, makeBuf(10),
2152  HTTPCodec::NoPadding, true);
2153  // cheat and not sending EOM, it's a no-op
2154 
2155  flushRequestsAndLoop();
2156  expect101(CodecProtocol::HTTP_2, "h2c");
2157  clientCodec_->generateConnectionPreface(requests_);
2158  clientCodec_->generateGoaway(requests_, 0, ErrorCode::NO_ERROR);
2159  flushRequestsAndLoop();
2160  eventBase_.runInLoop([&handler] {
2161  handler->sendReplyWithBody(200, 100);
2162  });
2163  HTTPSession::DestructorGuard g(httpSession_);
2164  eventBase_.loop();
2165  expectResponse(200, ErrorCode::NO_ERROR, false, true);
2166  expectDetachSession();
2167 }
2168 
2169 template <class C>
2171  uint32_t iterations = 10;
2172  uint32_t maxPriority = numPriorities - 1;
2173  std::vector<std::unique_ptr<testing::NiceMock<MockHTTPHandler>>> handlers;
2174  for (int pri = numPriorities - 1; pri >= 0; pri--) {
2175  for (uint32_t i = 0; i < iterations; i++) {
2176  sendRequest("/", pri * (8 / numPriorities));
2177  InSequence handlerSequence;
2178  auto handler = addSimpleNiceHandler();
2179  auto rawHandler = handler.get();
2180  handlers.push_back(std::move(handler));
2181  rawHandler->expectHeaders();
2182  rawHandler->expectEOM([rawHandler] {
2183  rawHandler->sendReplyWithBody(200, 1000);
2184  });
2185  rawHandler->expectDetachTransaction([] { });
2186  }
2187  }
2188 
2189  auto buf = requests_.move();
2190  buf->coalesce();
2191  requests_.append(std::move(buf));
2192 
2193  flushRequestsAndLoop();
2194 
2195  std::list<HTTPCodec::StreamID> streams;
2196  EXPECT_CALL(callbacks_, onMessageBegin(_, _))
2197  .Times(iterations * numPriorities);
2198  EXPECT_CALL(callbacks_, onHeadersComplete(_, _))
2199  .Times(iterations * numPriorities);
2200  // body is variable and hence ignored
2201  EXPECT_CALL(callbacks_, onMessageComplete(_, _))
2202  .Times(iterations * numPriorities)
2203  .WillRepeatedly(Invoke([&](HTTPCodec::StreamID stream, bool /*upgrade*/) {
2204  streams.push_back(stream);
2205  }));
2206 
2207  parseOutput(*clientCodec_);
2208 
2209  // transactions finish in priority order (higher streamIDs first)
2210  EXPECT_EQ(streams.size(), iterations * numPriorities);
2211  auto txn = streams.begin();
2212  for (int band = maxPriority; band >= 0; band--) {
2213  auto upperID = iterations * 2 * (band + 1);
2214  auto lowerID = iterations * 2 * band;
2215  for (uint32_t i = 0; i < iterations; i++) {
2216  EXPECT_LE(lowerID, (uint32_t)*txn);
2217  EXPECT_GE(upperID, (uint32_t)*txn);
2218  ++txn;
2219  }
2220  }
2221 }
2222 
2223 // Verifies that the read timeout is not running when no ingress is expected/
2224 // required to proceed
2226  sendRequest();
2227  sendRequest();
2228 
2229  httpSession_->setWriteBufferLimit(512);
2230 
2231  InSequence handlerSequence;
2232  auto handler1 = addSimpleStrictHandler();
2233  handler1->expectHeaders([this] { transport_->pauseWrites(); });
2234  handler1->expectEOM([&] {
2235  handler1->sendHeaders(200, 1000);
2236  handler1->sendBody(1000);
2237  });
2238  handler1->expectEgressPaused();
2239  auto handler2 = addSimpleStrictHandler();
2240  // handler2 is paused before it gets headers
2241  handler2->expectEgressPaused();
2242  handler2->expectHeaders();
2243  handler2->expectEOM([this] {
2244  // This transaction should start egress paused. We've received the
2245  // EOM, so the timeout shouldn't be running delay 400ms and resume
2246  // writes, this keeps txn1 from getting a write timeout
2247  resumeWritesAfterDelay(milliseconds(400));
2248  });
2249  handler1->expectEgressResumed([&handler1] { handler1->txn_->sendEOM(); });
2250  handler2->expectEgressResumed([&handler2, this] {
2251  // delay an additional 200ms. The total 600ms delay shouldn't fire
2252  // onTimeout
2253  eventBase_.tryRunAfterDelay([&handler2] {
2254  handler2->sendReplyWithBody(200, 400); }, 200
2255  );
2256  });
2257  handler1->expectDetachTransaction();
2258  handler2->expectDetachTransaction();
2259 
2260  flushRequestsAndLoop(false, milliseconds(0), milliseconds(10));
2261 
2262  cleanup();
2263 }
2264 
2265 // Verifies that the read timer is running while a transaction is blocked
2266 // on a window update
2268  clientCodec_->getEgressSettings()->setSetting(SettingsId::INITIAL_WINDOW_SIZE,
2269  500);
2270  clientCodec_->generateSettings(requests_);
2271  auto streamID = sendRequest();
2272 
2273  InSequence handlerSequence;
2274  auto handler = addSimpleStrictHandler();
2275  handler->expectHeaders();
2276  handler->expectEOM([&] {
2277  handler->sendReplyWithBody(200, 1000);
2278  });
2279  handler->expectEgressPaused();
2280  handler->expectError([&] (const HTTPException& ex) {
2282  ASSERT_EQ(
2283  folly::to<std::string>("ingress timeout, streamID=", streamID),
2284  std::string(ex.what()));
2285  handler->terminate();
2286  });
2287  handler->expectDetachTransaction();
2288 
2289  flushRequestsAndLoop();
2290 
2291  cleanup();
2292 }
2293 
2295 
2296 TYPED_TEST_P(HTTPDownstreamTest, TestWritesDraining) {
2297  auto badCodec =
2298  makeServerCodec<typename TypeParam::Codec>(TypeParam::version);
2299  this->sendRequest();
2300  badCodec->generatePushPromise(this->requests_, 2 /* bad */, getGetRequest(),
2301  1);
2302 
2303  this->expectDetachSession();
2304 
2305  InSequence handlerSequence;
2306  auto handler1 = this->addSimpleNiceHandler();
2307  handler1->expectHeaders();
2308  handler1->expectEOM();
2309  handler1->expectError([&](const HTTPException& ex) {
2311  ASSERT_TRUE(
2312  folly::StringPiece(ex.what()).startsWith("Shutdown transport: EOF"))
2313  << ex.what();
2314  });
2315  handler1->expectDetachTransaction();
2316 
2317  this->flushRequestsAndLoop();
2318 }
2319 
2320 TYPED_TEST_P(HTTPDownstreamTest, TestBodySizeLimit) {
2321  this->clientCodec_->generateWindowUpdate(this->requests_, 0, 65536);
2322  this->sendRequest();
2323  this->sendRequest();
2324 
2325  InSequence handlerSequence;
2326  auto handler1 = this->addSimpleNiceHandler();
2327  handler1->expectHeaders();
2328  handler1->expectEOM();
2329  auto handler2 = this->addSimpleNiceHandler();
2330  handler2->expectHeaders();
2331  handler2->expectEOM([&] {
2332  handler1->sendReplyWithBody(200, 33000);
2333  handler2->sendReplyWithBody(200, 33000);
2334  });
2335  handler1->expectDetachTransaction();
2336  handler2->expectDetachTransaction();
2337 
2338  this->flushRequestsAndLoop();
2339 
2340  std::list<HTTPCodec::StreamID> streams;
2341  EXPECT_CALL(this->callbacks_, onMessageBegin(1, _));
2342  EXPECT_CALL(this->callbacks_, onHeadersComplete(1, _));
2343  EXPECT_CALL(this->callbacks_, onMessageBegin(3, _));
2344  EXPECT_CALL(this->callbacks_, onHeadersComplete(3, _));
2345  for (uint32_t i = 0; i < 8; i++) {
2346  EXPECT_CALL(this->callbacks_, onBody(1, _, _));
2347  EXPECT_CALL(this->callbacks_, onBody(3, _, _));
2348  }
2349  EXPECT_CALL(this->callbacks_, onBody(1, _, _));
2350  EXPECT_CALL(this->callbacks_, onMessageComplete(1, _));
2351  EXPECT_CALL(this->callbacks_, onBody(3, _, _));
2352  EXPECT_CALL(this->callbacks_, onMessageComplete(3, _));
2353 
2354  this->parseOutput(*this->clientCodec_);
2355 
2356  this->cleanup();
2357 }
2358 
2359 #define IF_HTTP2(X) \
2360  if (this->clientCodec_->getProtocol() == CodecProtocol::HTTP_2) { X; }
2361 
2362 TYPED_TEST_P(HTTPDownstreamTest, TestUniformPauseState) {
2363  this->httpSession_->setWriteBufferLimit(12000);
2364  this->clientCodec_->getEgressSettings()->setSetting(
2365  SettingsId::INITIAL_WINDOW_SIZE, 1000000);
2366  this->clientCodec_->generateSettings(this->requests_);
2367  this->clientCodec_->generateWindowUpdate(this->requests_, 0, 1000000);
2368  this->sendRequest("/", 1);
2369  this->sendRequest("/", 1);
2370  this->sendRequest("/", 2);
2371 
2372  InSequence handlerSequence;
2373  auto handler1 = this->addSimpleStrictHandler();
2374  handler1->expectHeaders();
2375  handler1->expectEOM();
2376  auto handler2 = this->addSimpleStrictHandler();
2377  handler2->expectHeaders();
2378  handler2->expectEOM([&] {
2379  handler1->sendHeaders(200, 24002);
2380  // triggers pause of all txns
2381  this->transport_->pauseWrites();
2382  handler1->txn_->sendBody(std::move(makeBuf(12001)));
2383  this->resumeWritesAfterDelay(milliseconds(50));
2384  });
2385  handler1->expectEgressPaused();
2386  handler2->expectEgressPaused();
2387  auto handler3 = this->addSimpleStrictHandler();
2388  handler3->expectEgressPaused();
2389  handler3->expectHeaders();
2390  handler3->expectEOM();
2391 
2392  handler1->expectEgressResumed([&] {
2393  // resume does not trigger another pause,
2394  handler1->txn_->sendBody(std::move(makeBuf(12001)));
2395  });
2396  // handler2 gets a fair shot, handler3 is not resumed
2397  // HTTP/2 priority is not implemented, so handler3 is like another 0 pri txn
2398  handler2->expectEgressResumed();
2399  IF_HTTP2(handler3->expectEgressResumed());
2400  handler1->expectEgressPaused();
2401  handler2->expectEgressPaused();
2402  IF_HTTP2(handler3->expectEgressPaused());
2403 
2404  handler1->expectEgressResumed();
2405  handler2->expectEgressResumed([&] {
2406  handler2->sendHeaders(200, 12001);
2407  handler2->txn_->sendBody(std::move(makeBuf(12001)));
2408  this->transport_->pauseWrites();
2409  this->resumeWritesAfterDelay(milliseconds(50));
2410  });
2411  // handler3 not resumed
2412  IF_HTTP2(handler3->expectEgressResumed());
2413 
2414  handler1->expectEgressPaused();
2415  handler2->expectEgressPaused();
2416  IF_HTTP2(handler3->expectEgressPaused());
2417 
2418  handler1->expectEgressResumed();
2419  handler2->expectEgressResumed([&] {
2420  handler1->txn_->sendEOM();
2421  handler2->txn_->sendEOM();
2422  });
2423  handler3->expectEgressResumed([&] {
2424  handler3->txn_->sendAbort();
2425  });
2426 
2427  handler3->expectDetachTransaction();
2428  handler1->expectDetachTransaction();
2429  handler2->expectDetachTransaction();
2430 
2431  this->flushRequestsAndLoop();
2432 
2433  this->cleanup();
2434 }
2435 
2436 // Test exceeding the MAX_CONCURRENT_STREAMS setting. The txn should get
2437 // REFUSED_STREAM, and other streams can complete normally
2439  auto settings = this->rawCodec_->getEgressSettings();
2440  auto maxTxns = settings->getSetting(SettingsId::MAX_CONCURRENT_STREAMS,
2441  100);
2442  std::list<unique_ptr<StrictMock<MockHTTPHandler>>> handlers;
2443  {
2444  InSequence enforceOrder;
2445  for (auto i = 0U; i < maxTxns; i++) {
2446  this->sendRequest();
2447  auto handler = this->addSimpleStrictHandler();
2448  handler->expectHeaders();
2449  handler->expectEOM();
2450  handlers.push_back(std::move(handler));
2451  }
2452  auto streamID = this->sendRequest();
2453  this->clientCodec_->generateGoaway(this->requests_, 0, ErrorCode::NO_ERROR);
2454 
2455  for (auto& handler: handlers) {
2456  EXPECT_CALL(*handler, onGoaway(ErrorCode::NO_ERROR));
2457  }
2458 
2459  this->flushRequestsAndLoop();
2460 
2461  EXPECT_CALL(this->callbacks_, onSettings(_));
2462  EXPECT_CALL(this->callbacks_, onAbort(streamID, ErrorCode::REFUSED_STREAM));
2463 
2464  this->parseOutput(*this->clientCodec_);
2465  }
2466  // handlers can finish out of order?
2467  for (auto& handler: handlers) {
2468  handler->sendReplyWithBody(200, 100);
2469  handler->expectDetachTransaction();
2470  }
2471  this->expectDetachSession();
2472  this->eventBase_.loop();
2473 }
2474 
2475 // Set max streams=1
2476 // send two spdy requests a few ms apart.
2477 // Block writes
2478 // generate a complete response for txn=1 before parsing txn=3
2479 // HTTPSession should allow the txn=3 to be served rather than refusing it
2480 TEST_F(SPDY3DownstreamSessionTest, SpdyMaxConcurrentStreams) {
2481  HTTPMessage req = getGetRequest();
2482  req.setHTTPVersion(1, 0);
2483  req.setWantsKeepalive(false);
2484  sendRequest(req);
2485  auto req2p = sendRequestLater(req, true);
2486 
2487  httpSession_->setEgressSettings({{
2488  SettingsId::MAX_CONCURRENT_STREAMS, 1}});
2489 
2490  InSequence handlerSequence;
2491  auto handler1 = addSimpleStrictHandler();
2492  handler1->expectHeaders();
2493  handler1->expectEOM([&handler1, req, this, &req2p] {
2494  transport_->pauseWrites();
2495  handler1->sendReplyWithBody(200, 100);
2496  req2p.setValue();
2497  });
2498  auto handler2 = addSimpleStrictHandler();
2499  handler2->expectHeaders();
2500  handler2->expectEOM([&handler2, this] {
2501  handler2->sendReplyWithBody(200, 100);
2502  resumeWritesInLoop();
2503  });
2504  handler1->expectDetachTransaction();
2505  handler2->expectDetachTransaction();
2506 
2507  expectDetachSession();
2508 
2509  flushRequestsAndLoop();
2510 }
2511 
2513  TestWritesDraining, TestBodySizeLimit,
2514  TestUniformPauseState, TestMaxTxns);
2515 
2516 typedef ::testing::Types<SPDY3CodecPair, SPDY3_1CodecPair,
2518 INSTANTIATE_TYPED_TEST_CASE_P(ParallelCodecs,
2520  ParallelCodecs);
2521 
2522 class SPDY31DownstreamTest : public HTTPDownstreamTest<SPDY3_1CodecPair> {
2523  public:
2525  : HTTPDownstreamTest<SPDY3_1CodecPair>({-1, -1,
2526  2 * spdy::kInitialWindow}) {}
2527 };
2528 
2529 TEST_F(SPDY31DownstreamTest, TestSessionFlowControl) {
2530  eventBase_.loopOnce();
2531 
2532  InSequence sequence;
2533  EXPECT_CALL(callbacks_, onSettings(_));
2534  EXPECT_CALL(callbacks_, onWindowUpdate(0, spdy::kInitialWindow));
2535  parseOutput(*clientCodec_);
2536 
2537  cleanup();
2538 }
2539 
2540 TEST_F(SPDY3DownstreamSessionTest, TestEOFOnBlockedStream) {
2541  sendRequest();
2542 
2543  auto handler1 = addSimpleStrictHandler();
2544 
2545  InSequence handlerSequence;
2546  handler1->expectHeaders();
2547  handler1->expectEOM([&handler1] {
2548  handler1->sendReplyWithBody(200, 80000);
2549  });
2550  handler1->expectEgressPaused();
2551 
2552  handler1->expectError([&] (const HTTPException& ex) {
2553  // Not optimal to have a different error code here than the session
2554  // flow control case, but HTTPException direction is immutable and
2555  // building another one seems not future proof.
2556  EXPECT_EQ(ex.getDirection(), HTTPException::Direction::INGRESS);
2557  });
2558  handler1->expectDetachTransaction();
2559 
2560  expectDetachSession();
2561 
2562  flushRequestsAndLoop(true, milliseconds(10));
2563 }
2564 
2565 TEST_F(SPDY31DownstreamTest, TestEOFOnBlockedSession) {
2566  sendRequest();
2567  sendRequest();
2568 
2569  InSequence handlerSequence;
2570  auto handler1 = addSimpleStrictHandler();
2571  handler1->expectHeaders();
2572  handler1->expectEOM([&handler1] {
2573  handler1->sendHeaders(200, 40000);
2574  handler1->sendBody(32769);
2575  });
2576  auto handler2 = addSimpleStrictHandler();
2577  handler2->expectHeaders();
2578  handler2->expectEOM([&handler2, this] {
2579  handler2->sendHeaders(200, 40000);
2580  handler2->sendBody(32768);
2581  eventBase_.runInLoop([this] { transport_->addReadEOF(milliseconds(0)); });
2582  });
2583 
2584  handler1->expectEgressPaused();
2585  handler2->expectEgressPaused();
2586  handler1->expectEgressResumed();
2587  handler2->expectEgressResumed();
2588  handler1->expectError([&] (const HTTPException& ex) {
2589  EXPECT_EQ(ex.getDirection(),
2590  HTTPException::Direction::INGRESS_AND_EGRESS);
2591  });
2592  handler1->expectDetachTransaction();
2593  handler2->expectError([&] (const HTTPException& ex) {
2594  EXPECT_EQ(ex.getDirection(),
2595  HTTPException::Direction::INGRESS_AND_EGRESS);
2596  });
2597  handler2->expectDetachTransaction();
2598 
2599  expectDetachSession();
2600 
2601  flushRequestsAndLoop();
2602 }
2603 
2604 
2605 TEST_F(SPDY3DownstreamSessionTest, NewTxnEgressPaused) {
2606  // Send 1 request with prio=0
2607  // Have egress pause while sending the first response
2608  // Send a second request with prio=1
2609  // -- the new txn should start egress paused
2610  // Finish the body and eom both responses
2611  // Unpause egress
2612  // The first txn should complete first
2613 
2614  sendRequest("/", 0);
2615  auto req2 = getGetRequest();
2616  req2.setPriority(1);
2617  auto req2p = sendRequestLater(req2, true);
2618 
2619  unique_ptr<StrictMock<MockHTTPHandler>> handler1;
2620  unique_ptr<StrictMock<MockHTTPHandler>> handler2;
2621 
2622  httpSession_->setWriteBufferLimit(200); // lower the per session buffer limit
2623  {
2624  InSequence handlerSequence;
2625  handler1 = addSimpleStrictHandler();
2626  handler1->expectHeaders();
2627  handler1->expectEOM([&handler1, this, &req2p] {
2628  this->transport_->pauseWrites();
2629  handler1->sendHeaders(200, 1000);
2630  handler1->sendBody(100); // headers + 100 bytes - over the limit
2631  req2p.setValue();
2632  });
2633  handler1->expectEgressPaused([] { LOG(INFO) << "paused 1"; });
2634 
2635  handler2 = addSimpleStrictHandler();
2636  handler2->expectEgressPaused(); // starts paused
2637  handler2->expectHeaders();
2638  handler2->expectEOM([&] {
2639  // Technically shouldn't send while handler is egress paused, but meh.
2640  handler1->sendBody(900);
2641  handler1->txn_->sendEOM();
2642  handler2->sendReplyWithBody(200, 1000);
2643  resumeWritesInLoop();
2644  });
2645  handler1->expectDetachTransaction();
2646  handler2->expectDetachTransaction();
2647  }
2648  HTTPSession::DestructorGuard g(httpSession_);
2649  flushRequestsAndLoop();
2650 
2651  std::list<HTTPCodec::StreamID> streams;
2652  EXPECT_CALL(callbacks_, onMessageBegin(_, _))
2653  .Times(2);
2654  EXPECT_CALL(callbacks_, onHeadersComplete(_, _))
2655  .Times(2);
2656  // body is variable and hence ignored;
2657  EXPECT_CALL(callbacks_, onMessageComplete(_, _))
2658  .WillRepeatedly(Invoke([&](HTTPCodec::StreamID stream, bool /*upgrade*/) {
2659  streams.push_back(stream);
2660  }));
2661  parseOutput(*clientCodec_);
2662 
2663  cleanup();
2664 }
2665 
2666 TEST_F(HTTP2DownstreamSessionTest, ZeroDeltaWindowUpdate) {
2667  // generateHeader() will create a session and a transaction
2668  auto streamID = sendHeader();
2669  // First generate a frame with delta=1 so as to pass the checks, and then
2670  // hack the frame so that delta=0 without modifying other checks
2671  clientCodec_->generateWindowUpdate(requests_, streamID, 1);
2672  requests_.trimEnd(http2::kFrameWindowUpdateSize);
2673  QueueAppender appender(&requests_, http2::kFrameWindowUpdateSize);
2674  appender.writeBE<uint32_t>(0);
2675 
2676  auto handler = addSimpleStrictHandler();
2677 
2678  InSequence handlerSequence;
2679  handler->expectHeaders();
2680  handler->expectError([&] (const HTTPException& ex) {
2681  ASSERT_EQ(ex.getCodecStatusCode(), ErrorCode::PROTOCOL_ERROR);
2682  ASSERT_EQ(
2683  "streamID=1 with HTTP2Codec stream error: window update delta=0",
2684  std::string(ex.what()));
2685  });
2686  handler->expectDetachTransaction();
2687  expectDetachSession();
2688 
2689  flushRequestsAndLoop();
2690 }
2691 
2692 TEST_F(HTTP2DownstreamSessionTest, PaddingFlowControl) {
2693  // generateHeader() will create a session and a transaction
2694  auto streamID = sendHeader();
2695  // This sends a total of 33kb including padding, so we should get a session
2696  // and stream window update
2697  for (auto i = 0; i < 129; i++) {
2698  clientCodec_->generateBody(requests_, streamID, makeBuf(1), 255, false);
2699  }
2700 
2701  auto handler = addSimpleStrictHandler();
2702 
2703  InSequence handlerSequence;
2704  handler->expectHeaders([&] {
2705  handler->txn_->pauseIngress();
2706  eventBase_.runAfterDelay([&] { handler->txn_->resumeIngress(); },
2707  100);
2708  });
2709  EXPECT_CALL(*handler, onBody(_))
2710  .Times(129);
2711  handler->expectError();
2712  handler->expectDetachTransaction();
2713 
2714  HTTPSession::DestructorGuard g(httpSession_);
2715  flushRequestsAndLoop(false, milliseconds(0), milliseconds(0), [&] {
2716  clientCodec_->generateRstStream(requests_, streamID, ErrorCode::CANCEL);
2717  clientCodec_->generateGoaway(requests_, 0, ErrorCode::NO_ERROR);
2718  transport_->addReadEvent(requests_, milliseconds(110));
2719  });
2720 
2721  std::list<HTTPCodec::StreamID> streams;
2722  EXPECT_CALL(callbacks_, onWindowUpdate(0, _));
2723  EXPECT_CALL(callbacks_, onWindowUpdate(1, _));
2724  parseOutput(*clientCodec_);
2725  expectDetachSession();
2726 }
2727 
2728 TEST_F(HTTP2DownstreamSessionTest, GracefulDrainOnTimeout) {
2729  InSequence handlerSequence;
2730  std::chrono::milliseconds gracefulTimeout(200);
2731  httpSession_->enableDoubleGoawayDrain();
2732  EXPECT_CALL(mockController_, getGracefulShutdownTimeout())
2733  .WillOnce(InvokeWithoutArgs([&] {
2734  // Once session asks for graceful shutdown timeout, expect the client
2735  // to receive the first GOAWAY
2736  eventBase_.runInLoop([&] {
2737  EXPECT_CALL(callbacks_,
2739  ErrorCode::NO_ERROR, _));
2740  parseOutput(*clientCodec_);
2741  });
2742  return gracefulTimeout;
2743  }));
2744 
2745 
2746  // Simulate ConnectionManager idle timeout
2747  eventBase_.runAfterDelay([&] { httpSession_->timeoutExpired(); },
2748  transactionTimeouts_->getDefaultTimeout().count());
2749  HTTPSession::DestructorGuard g(httpSession_);
2750  auto start = getCurrentTime();
2751  eventBase_.loop();
2752  auto finish = getCurrentTime();
2753  auto minDuration =
2754  gracefulTimeout + transactionTimeouts_->getDefaultTimeout();
2755  EXPECT_GE((finish - start).count(), minDuration.count());
2756  EXPECT_CALL(callbacks_, onGoaway(0, ErrorCode::NO_ERROR, _));
2757  parseOutput(*clientCodec_);
2758  expectDetachSession();
2759 }
2760 
2761 /*
2762  * The sequence of streams are generated in the following order:
2763  * - [client --> server] request 1st stream (getGetRequest())
2764  * - [server --> client] respond 1st stream (res with length 100)
2765  * - [server --> client] request 2nd stream (req)
2766  * - [server --> client] respond 2nd stream (res with length 200 + EOM)
2767  * - [client --> server] RST_STREAM on the 1st stream
2768  */
2769 TEST_F(HTTP2DownstreamSessionTest, ServerPush) {
2770  // Create a dummy request and a dummy response messages
2771  HTTPMessage req, res;
2772  req.getHeaders().set("HOST", "www.foo.com");
2773  req.setURL("https://www.foo.com/");
2774  res.setStatusCode(200);
2775  res.setStatusMessage("Ohai");
2776 
2777  // enable server push
2778  clientCodec_->getEgressSettings()->setSetting(SettingsId::ENABLE_PUSH, 1);
2779  clientCodec_->generateSettings(requests_);
2780  // generateHeader() will create a session and a transaction
2781  auto assocStreamId = HTTPCodec::StreamID(1);
2782  clientCodec_->generateHeader(requests_, assocStreamId, getGetRequest(),
2783  false, nullptr);
2784 
2785  auto handler = addSimpleStrictHandler();
2786  StrictMock<MockHTTPPushHandler> pushHandler;
2787 
2788  InSequence handlerSequence;
2789  handler->expectHeaders([&] {
2790  // Generate response for the associated stream
2791  handler->txn_->sendHeaders(res);
2792  handler->txn_->sendBody(makeBuf(100));
2793  handler->txn_->pauseIngress();
2794 
2795  auto* pushTxn = handler->txn_->newPushedTransaction(&pushHandler);
2796  ASSERT_NE(pushTxn, nullptr);
2797  // Generate a push request (PUSH_PROMISE)
2798  auto outgoingStreams = httpSession_->getNumOutgoingStreams();
2799  pushTxn->sendHeaders(req);
2800  EXPECT_EQ(httpSession_->getNumOutgoingStreams(), outgoingStreams);
2801  // Generate a push response
2802  auto pri = handler->txn_->getPriority();
2803  res.setHTTP2Priority(std::make_tuple(pri.streamDependency,
2804  pri.exclusive, pri.weight));
2805  pushTxn->sendHeaders(res);
2806  EXPECT_EQ(httpSession_->getNumOutgoingStreams(), outgoingStreams + 1);
2807  pushTxn->sendBody(makeBuf(200));
2808  pushTxn->sendEOM();
2809 
2810  eventBase_.runAfterDelay([&] { handler->txn_->resumeIngress(); },
2811  100);
2812  });
2813  EXPECT_CALL(pushHandler, setTransaction(_))
2814  .WillOnce(Invoke([&] (HTTPTransaction* txn) {
2815  pushHandler.txn_ = txn; }));
2816  EXPECT_CALL(pushHandler, detachTransaction());
2817  handler->expectError();
2818  handler->expectDetachTransaction();
2819 
2820  transport_->addReadEvent(requests_, milliseconds(0));
2821  clientCodec_->generateRstStream(requests_, assocStreamId, ErrorCode::CANCEL);
2822  clientCodec_->generateGoaway(requests_, 2, ErrorCode::NO_ERROR);
2823  transport_->addReadEvent(requests_, milliseconds(200));
2824  transport_->startReadEvents();
2825  HTTPSession::DestructorGuard g(httpSession_);
2826  eventBase_.loop();
2827 
2828  EXPECT_CALL(callbacks_, onMessageBegin(1, _));
2829  EXPECT_CALL(callbacks_, onHeadersComplete(1, _));
2830  EXPECT_CALL(callbacks_, onPushMessageBegin(2, 1, _));
2831  EXPECT_CALL(callbacks_, onHeadersComplete(2, _));
2832  EXPECT_CALL(callbacks_, onMessageBegin(2, _));
2833  EXPECT_CALL(callbacks_, onHeadersComplete(2, _));
2834  EXPECT_CALL(callbacks_, onMessageComplete(2, _));
2835 
2836  parseOutput(*clientCodec_);
2837  expectDetachSession();
2838 }
2839 
2840 TEST_F(HTTP2DownstreamSessionTest, ServerPushAbortPaused) {
2841  // Create a dummy request and a dummy response messages
2842  HTTPMessage req, res;
2843  req.getHeaders().set("HOST", "www.foo.com");
2844  req.setURL("https://www.foo.com/");
2845  res.setStatusCode(200);
2846  res.setStatusMessage("Ohai");
2847 
2848  // enable server push
2849  clientCodec_->getEgressSettings()->setSetting(SettingsId::ENABLE_PUSH, 1);
2850  clientCodec_->generateSettings(requests_);
2851  // generateHeader() will create a session and a transaction
2852  auto assocStreamId = HTTPCodec::StreamID(1);
2853  clientCodec_->generateHeader(requests_, assocStreamId, getGetRequest(),
2854  false, nullptr);
2855 
2856  auto handler = addSimpleStrictHandler();
2857  StrictMock<MockHTTPPushHandler> pushHandler;
2858 
2859  InSequence handlerSequence;
2860  handler->expectHeaders([&] {
2861  // Generate response for the associated stream
2862  this->transport_->pauseWrites();
2863  handler->txn_->sendHeaders(res);
2864  handler->txn_->sendBody(makeBuf(100));
2865  handler->txn_->pauseIngress();
2866 
2867  auto* pushTxn = handler->txn_->newPushedTransaction(&pushHandler);
2868  ASSERT_NE(pushTxn, nullptr);
2869  // Generate a push request (PUSH_PROMISE)
2870  pushTxn->sendHeaders(req);
2871  });
2872  EXPECT_CALL(pushHandler, setTransaction(_))
2873  .WillOnce(Invoke([&] (HTTPTransaction* txn) {
2874  pushHandler.txn_ = txn; }));
2875  EXPECT_CALL(pushHandler, onError(_));
2876  EXPECT_CALL(pushHandler, detachTransaction());
2877  handler->expectError();
2878  handler->expectDetachTransaction();
2879 
2880  transport_->addReadEvent(requests_, milliseconds(0));
2881  // Cancels everything
2882  clientCodec_->generateRstStream(requests_, assocStreamId, ErrorCode::CANCEL);
2883  transport_->addReadEvent(requests_, milliseconds(10));
2884  transport_->startReadEvents();
2885  HTTPSession::DestructorGuard g(httpSession_);
2886  eventBase_.loop();
2887 
2888  parseOutput(*clientCodec_);
2889  expectDetachSession();
2890 }
2891 
2892 TEST_F(HTTP2DownstreamSessionTest, TestPriorityWeightsTinyRatio) {
2893  // Create a transaction with egress and a ratio small enough that
2894  // ratio*4096 < 1.
2895  //
2896  // root
2897  // / \ level 1
2898  // 256 1 (no egress)
2899  // / \ level 2
2900  // 256 1 <-- has ratio (1/257)^2
2901  InSequence enforceOrder;
2902  auto req1 = getGetRequest();
2903  auto req2 = getGetRequest();
2904  req1.setHTTP2Priority(HTTPMessage::HTTPPriority{0, false, 255});
2905  req2.setHTTP2Priority(HTTPMessage::HTTPPriority{0, false, 0});
2906 
2907  sendRequest(req1);
2908  auto id2 = sendRequest(req2);
2909  req1.setHTTP2Priority(HTTPMessage::HTTPPriority{id2, false, 255});
2910  req2.setHTTP2Priority(HTTPMessage::HTTPPriority{id2, false, 0});
2911  sendRequest(req1);
2912  sendRequest(req2);
2913 
2914  auto handler1 = addSimpleStrictHandler();
2915  handler1->expectHeaders();
2916  handler1->expectEOM([&] {
2917  handler1->sendReplyWithBody(200, 4 * 1024);
2918  });
2919  auto handler2 = addSimpleStrictHandler();
2920  handler2->expectHeaders();
2921  handler2->expectEOM();
2922  auto handler3 = addSimpleStrictHandler();
2923  handler3->expectHeaders();
2924  handler3->expectEOM([&] {
2925  handler3->sendReplyWithBody(200, 15);
2926  });
2927  auto handler4 = addSimpleStrictHandler();
2928  handler4->expectHeaders();
2929  handler4->expectEOM([&] {
2930  handler4->sendReplyWithBody(200, 1);
2931  });
2932 
2933  handler1->expectDetachTransaction([&] {
2935  EXPECT_EQ(handler1->txn_->getPrioritySampleSummary(summary), true);
2936  EXPECT_EQ(handler1->txn_->getTransport().getHTTP2PrioritiesEnabled(),
2937  true);
2938  // id1 had no egress when id2 was running, so id1 was contending only with
2939  // id3 and id4. Average number of contentions for id1 is 3
2942  // this is a first level transaction, depth == 1
2943  EXPECT_EQ(summary.depth_.byTransactionBytes_, 1);
2944  EXPECT_EQ(summary.depth_.bySessionBytes_, 1);
2945  // the expected relative weight is 256/257 ~= 0.9961
2946  EXPECT_GT(summary.expected_weight_, 0.996);
2947  EXPECT_LT(summary.expected_weight_, 0.9962);
2948  // the measured relative weight is 4096/(4096+15) ~= 0.99635
2949  // This value is higher than the expected relative weight of 0.9961.
2950  // Due to the arithmetical rounding to the lowest integer, the measured
2951  // relative weight tends to be higher for transactions with high relative
2952  // weights and lower for transactions with the low relative weights.
2953  EXPECT_GT(summary.measured_weight_, 0.9963);
2954  EXPECT_LT(summary.measured_weight_, 0.9964);
2955  });
2956  handler3->expectDetachTransaction([&] {
2958  EXPECT_EQ(handler3->txn_->getPrioritySampleSummary(summary), true);
2959  EXPECT_EQ(handler3->txn_->getTransport().getHTTP2PrioritiesEnabled(),
2960  true);
2961  // Similarly, id3 was contenting with id1 and id4
2962  // Average number of contentions for id3 is 3
2965  // this is a second level transaction where parent has
2966  // no egress, depth == 2
2967  EXPECT_EQ(summary.depth_.byTransactionBytes_, 2);
2968  EXPECT_EQ(summary.depth_.bySessionBytes_, 2);
2969  // the expected relative weight should be
2970  // 1/257 * 256/257 ~= 0.00388. However, in the calculation of the
2971  // allowed bytes to send we rounding to the lowest positive integer.
2972  // Therefore, the measured relative weight tends to be less than
2973  // it should be. In this example, the allowed bytes sent is
2974  // 4096 * 0.00388 ~= 15.89, which is rounded to 15. Hence the measured
2975  // relative weight is 15/(4096+15) ~= 0.00365
2976  EXPECT_GT(summary.expected_weight_, 0.00388);
2977  EXPECT_LT(summary.expected_weight_, 0.0039);
2978  EXPECT_GT(summary.measured_weight_, 0.00364);
2979  EXPECT_LT(summary.measured_weight_, 0.00366);
2980  });
2981  handler4->expectDetachTransaction([&] {
2983  EXPECT_EQ(handler4->txn_->getPrioritySampleSummary(summary), true);
2984  EXPECT_EQ(handler4->txn_->getTransport().getHTTP2PrioritiesEnabled(),
2985  true);
2986  // This is the priority-based blocking situation. id4 was blocked by
2987  // higher priority transactions id1 and id3. Only when id1 and id3
2988  // finished, id4 had a chance to transfer its data.
2989  // Average contention number weighted by transaction bytes is 1, which
2990  // means that when id4 had a chance to transfer bytes it did not contend
2991  // with any other transactions.
2992  // id4 was waiting for id1 and id3 during transfer of 4256 bytes (encoded)
2993  // after which it tranferred 10 bytes (encoded) without contention.
2994  // Therefore, the average number contentions weighted by session bytes is
2995  // (4111*3 + 1*1)/(4111 + 1) = 12334/4112 ~= 2.999
2996  // The difference in average contentions weighted by transaction and
2997  // session bytes tells that id4 was mostly blocked by rather than blocking
2998  // other transactions.
3000  EXPECT_GT(summary.contentions_.bySessionBytes_, 2.99);
3001  EXPECT_LT(summary.contentions_.bySessionBytes_, 3.00);
3002  // this is a second level transaction where parent has
3003  // no egress, depth == 2
3004  EXPECT_EQ(summary.depth_.byTransactionBytes_, 2);
3005  EXPECT_EQ(summary.depth_.bySessionBytes_, 2);
3006  // the expected relative weight should be
3007  // 1/257 * 1/257 ~= 0.000015.
3008  // Because no bytes of this transaction were sent during the previous
3009  // egress, the expected relative weight was calculated as:
3010  // (0*4111 + 1*1)/(4111 + 1) ~= 0.000243
3011  EXPECT_GT(summary.expected_weight_, 0.000243);
3012  EXPECT_LT(summary.expected_weight_, 0.000244);
3013  // The measured weight is (0+1)/(4111+1) ~= 0.000243
3014  // The difference between the theoretical value of 0.000015 and the
3015  // measured one is not because of the arithmetical rounding, but because
3016  // all other transactions are completed and the relative waight for the
3017  // only survived transaction was elevated to 1.0
3018  EXPECT_GT(summary.measured_weight_, 0.000243);
3019  EXPECT_LT(summary.measured_weight_, 0.000244);
3020  handler2->txn_->sendAbort();
3021  });
3022  handler2->expectDetachTransaction();
3023  flushRequestsAndLoop();
3024  httpSession_->closeWhenIdle();
3025  expectDetachSession();
3026  eventBase_.loop();
3027 }
3028 
3029 TEST_F(HTTP2DownstreamSessionTest, TestPriorityDependentTransactions) {
3030  // Create a dependent transaction to test the priority blocked by dependency.
3031  // ratio*4096 < 1.
3032  //
3033  // root
3034  // \ level 1
3035  // 16
3036  // \ level 2
3037  // 16
3038  InSequence enforceOrder;
3039  auto req1 = getGetRequest();
3040  req1.setHTTP2Priority(HTTPMessage::HTTPPriority{0, false, 15});
3041  auto id1 = sendRequest(req1);
3042 
3043  auto req2 = getGetRequest();
3044  req2.setHTTP2Priority(HTTPMessage::HTTPPriority{id1, false, 15});
3045  sendRequest(req2);
3046 
3047  auto handler1 = addSimpleStrictHandler();
3048  handler1->expectHeaders();
3049  handler1->expectEOM([&] {
3050  handler1->sendReplyWithBody(200, 1024);
3051  });
3052  auto handler2 = addSimpleStrictHandler();
3053  handler2->expectHeaders();
3054  handler2->expectEOM([&] {
3055  handler2->sendReplyWithBody(200, 1024);
3056  });
3057 
3058  handler1->expectDetachTransaction([&] {
3060  EXPECT_EQ(handler1->txn_->getPrioritySampleSummary(summary), true);
3061  EXPECT_EQ(handler1->txn_->getTransport().getHTTP2PrioritiesEnabled(),
3062  true);
3063  // id1 is contending with id2 during the entire transfer.
3064  // Average number of contentions for id1 is 2 in both cases.
3065  // The same number of average contentions weighted by both transaction
3066  // and session bytes tells that id1 was not blocked by any other
3067  // transaction during the entire transfer.
3070  // this is a first level transaction, depth == 1
3071  EXPECT_EQ(summary.depth_.byTransactionBytes_, 1);
3072  EXPECT_EQ(summary.depth_.bySessionBytes_, 1);
3073  // dependent transaction is blocked, the parent is egressing on 100%
3074  EXPECT_EQ(summary.expected_weight_, 1);
3075  EXPECT_EQ(summary.measured_weight_, 1);
3076  });
3077  handler2->expectDetachTransaction([&] {
3079  EXPECT_EQ(handler2->txn_->getPrioritySampleSummary(summary), true);
3080  EXPECT_EQ(handler2->txn_->getTransport().getHTTP2PrioritiesEnabled(),
3081  true);
3082  // This is the dependency-based blocking. id2 is blocked by id1.
3083  // When id2 had a chance to transfer bytes, it was no longer contended
3084  // with any other transaction. Hence the average contention weighted by
3085  // transaction bytes is 1.
3086  // The average number of contentions weighted by the session bytes is
3087  // computed as (1024*2 + 1024*1)/(1024 + 1024) = 3072/2048 = 1.5
3089  EXPECT_EQ(summary.contentions_.bySessionBytes_, 1.5);
3090  // The transaction transferred bytes only when its parent transaction
3091  // completed. At that time its level decreased to 1. The average depth
3092  // weighted by session bytes is (2*1024 + 1*1024)/(2048) = 1.5.
3093  EXPECT_EQ(summary.depth_.byTransactionBytes_, 1);
3094  EXPECT_EQ(summary.depth_.bySessionBytes_, 1.5);
3095  // this dependent transaction was bloted, so it was egressiong only 1/2
3096  // of the session bytes.
3097  EXPECT_EQ(summary.expected_weight_, 0.5);
3098  EXPECT_EQ(summary.measured_weight_, 0.5);
3099  handler2->txn_->sendAbort();
3100  });
3101  flushRequestsAndLoop();
3102  httpSession_->closeWhenIdle();
3103  expectDetachSession();
3104  eventBase_.loop();
3105 }
3106 
3107 TEST_F(HTTP2DownstreamSessionTest, TestDisablePriorities) {
3108  // turn off HTTP2 priorities
3109  httpSession_->setHTTP2PrioritiesEnabled(false);
3110 
3111  InSequence enforceOrder;
3112  HTTPMessage req1 = getGetRequest();
3113  req1.setHTTP2Priority(HTTPMessage::HTTPPriority{0, false, 0});
3114  sendRequest(req1);
3115 
3116  HTTPMessage req2 = getGetRequest();
3117  req2.setHTTP2Priority(HTTPMessage::HTTPPriority{0, false, 255});
3118  sendRequest(req2);
3119 
3120  auto handler1 = addSimpleStrictHandler();
3121  handler1->expectHeaders();
3122  handler1->expectEOM([&] {
3123  handler1->sendReplyWithBody(200, 4 * 1024);
3124  });
3125 
3126  auto handler2 = addSimpleStrictHandler();
3127  handler2->expectHeaders();
3128  handler2->expectEOM([&] {
3129  handler2->sendReplyWithBody(200, 4 * 1024);
3130  });
3131 
3132  // expecting handler 1 to finish first irrespective of
3133  // request 2 having higher weight
3134  handler1->expectDetachTransaction();
3135  handler2->expectDetachTransaction();
3136 
3137  flushRequestsAndLoop();
3138  httpSession_->closeWhenIdle();
3139  expectDetachSession();
3140  eventBase_.loop();
3141 }
3142 
3143 TEST_F(HTTP2DownstreamSessionTest, TestPriorityWeights) {
3144  // virtual priority node with pri=4
3145  auto priGroupID = clientCodec_->createStream();
3146  clientCodec_->generatePriority(
3147  requests_, priGroupID, HTTPMessage::HTTPPriority(0, false, 3));
3148  // Both txn's are at equal pri=16
3149  auto id1 = sendRequest();
3150  auto id2 = sendRequest();
3151 
3152  auto handler1 = addSimpleStrictHandler();
3153 
3154  handler1->expectHeaders();
3155  handler1->expectEOM([&] {
3156  handler1->sendHeaders(200, 12 * 1024);
3157  handler1->txn_->sendBody(makeBuf(4 * 1024));
3158  });
3159  auto handler2 = addSimpleStrictHandler();
3160  handler2->expectHeaders();
3161  handler2->expectEOM([&] {
3162  handler2->sendHeaders(200, 12 * 1024);
3163  handler2->txn_->sendBody(makeBuf(4 * 1024));
3164  });
3165 
3166  // twice- once to send and once to receive
3167  flushRequestsAndLoopN(2);
3168  EXPECT_CALL(callbacks_, onSettings(_));
3169  EXPECT_CALL(callbacks_, onMessageBegin(id1, _));
3170  EXPECT_CALL(callbacks_, onHeadersComplete(id1, _));
3171  EXPECT_CALL(callbacks_, onMessageBegin(id2, _));
3172  EXPECT_CALL(callbacks_, onHeadersComplete(id2, _));
3173  EXPECT_CALL(callbacks_, onBody(id1, _, _))
3174  .WillOnce(ExpectBodyLen(4 * 1024));
3175  EXPECT_CALL(callbacks_, onBody(id2, _, _))
3176  .WillOnce(ExpectBodyLen(4 * 1024));
3177  parseOutput(*clientCodec_);
3178 
3179  // update handler2 to be in the pri-group (which has lower weight)
3180  clientCodec_->generatePriority(
3181  requests_, id2, HTTPMessage::HTTPPriority(priGroupID, false, 15));
3182 
3183  eventBase_.runInLoop([&] {
3184  handler1->txn_->sendBody(makeBuf(4 * 1024));
3185  handler2->txn_->sendBody(makeBuf(4 * 1024));
3186  });
3187  flushRequestsAndLoopN(2);
3188 
3189  EXPECT_CALL(callbacks_, onBody(id1, _, _))
3190  .WillOnce(ExpectBodyLen(4 * 1024));
3191  EXPECT_CALL(callbacks_, onBody(id2, _, _))
3192  .WillOnce(ExpectBodyLen(1 * 1024))
3193  .WillOnce(ExpectBodyLen(3 * 1024));
3194  parseOutput(*clientCodec_);
3195 
3196  // update vnode weight to match txn1 weight
3197  clientCodec_->generatePriority(requests_, priGroupID,
3198  HTTPMessage::HTTPPriority(0, false, 15));
3199  eventBase_.runInLoop([&] {
3200  handler1->txn_->sendBody(makeBuf(4 * 1024));
3201  handler1->txn_->sendEOM();
3202  handler2->txn_->sendBody(makeBuf(4 * 1024));
3203  handler2->txn_->sendEOM();
3204  });
3205  handler1->expectDetachTransaction();
3206  handler2->expectDetachTransaction();
3207  flushRequestsAndLoopN(2);
3208 
3209  // expect 32/32
3210  EXPECT_CALL(callbacks_, onBody(id1, _, _))
3211  .WillOnce(ExpectBodyLen(4 * 1024));
3212  EXPECT_CALL(callbacks_, onMessageComplete(id1, _));
3213  EXPECT_CALL(callbacks_, onBody(id2, _, _))
3214  .WillOnce(ExpectBodyLen(4 * 1024));
3215  EXPECT_CALL(callbacks_, onMessageComplete(id2, _));
3216  parseOutput(*clientCodec_);
3217 
3218  httpSession_->closeWhenIdle();
3219  expectDetachSession();
3220  this->eventBase_.loop();
3221 }
3222 
3223 TEST_F(HTTP2DownstreamSessionTest, TestPriorityWeightsTinyWindow) {
3224  httpSession_->setWriteBufferLimit(2 * 65536);
3225  InSequence enforceOrder;
3226  auto id1 = sendRequest();
3227  auto id2 = sendRequest();
3228 
3229  auto handler1 = addSimpleStrictHandler();
3230 
3231  handler1->expectHeaders();
3232  handler1->expectEOM([&] {
3233  handler1->sendReplyWithBody(200, 32 * 1024);
3234  });
3235  auto handler2 = addSimpleStrictHandler();
3236  handler2->expectHeaders();
3237  handler2->expectEOM([&] {
3238  handler2->sendReplyWithBody(200, 32 * 1024);
3239  });
3240 
3241  handler1->expectDetachTransaction();
3242 
3243  // twice- once to send and once to receive
3244  flushRequestsAndLoopN(2);
3245  EXPECT_CALL(callbacks_, onSettings(_));
3246  EXPECT_CALL(callbacks_, onMessageBegin(id1, _));
3247  EXPECT_CALL(callbacks_, onHeadersComplete(id1, _));
3248  EXPECT_CALL(callbacks_, onMessageBegin(id2, _));
3249  EXPECT_CALL(callbacks_, onHeadersComplete(id2, _));
3250  for (auto i = 0; i < 7; i++) {
3251  EXPECT_CALL(callbacks_, onBody(id1, _, _))
3252  .WillOnce(ExpectBodyLen(4 * 1024));
3253  EXPECT_CALL(callbacks_, onBody(id2, _, _))
3254  .WillOnce(ExpectBodyLen(4 * 1024));
3255  }
3256  EXPECT_CALL(callbacks_, onBody(id1, _, _))
3257  .WillOnce(ExpectBodyLen(4 * 1024 - 1));
3258  EXPECT_CALL(callbacks_, onBody(id2, _, _))
3259  .WillOnce(ExpectBodyLen(4 * 1024 - 1));
3260  EXPECT_CALL(callbacks_, onBody(id1, _, _))
3261  .WillOnce(ExpectBodyLen(1));
3262  EXPECT_CALL(callbacks_, onMessageComplete(id1, _));
3263  parseOutput(*clientCodec_);
3264 
3265  // open the window
3266  clientCodec_->generateWindowUpdate(requests_, 0, 100);
3267  handler2->expectDetachTransaction();
3268  flushRequestsAndLoopN(2);
3269 
3270  EXPECT_CALL(callbacks_, onBody(id2, _, _))
3271  .WillOnce(ExpectBodyLen(1));
3272  EXPECT_CALL(callbacks_, onMessageComplete(id2, _));
3273  parseOutput(*clientCodec_);
3274 
3275  httpSession_->closeWhenIdle();
3276  expectDetachSession();
3277  this->eventBase_.loop();
3278 }
3279 
3280 TEST_F(HTTP2DownstreamSessionTest, TestShortContentLength) {
3281  auto req = getPostRequest(10);
3282  auto streamID = sendRequest(req, false);
3283  clientCodec_->generateBody(requests_, streamID, makeBuf(20),
3284  HTTPCodec::NoPadding, true);
3285  auto handler1 = addSimpleStrictHandler();
3286 
3287  InSequence enforceOrder;
3288  handler1->expectHeaders();
3289  handler1->expectError([&handler1] (const HTTPException& ex) {
3291  handler1->txn_->sendAbort();
3292  });
3293  handler1->expectDetachTransaction();
3294  flushRequestsAndLoop();
3295 
3296  gracefulShutdown();
3297 }
3298 
3303 TEST_F(HTTP2DownstreamSessionTest, TestBadContentLengthUntieHandler) {
3304  auto req = getPostRequest(10);
3305  auto streamID = sendRequest(req, false);
3306  clientCodec_->generateBody(
3307  requests_,
3308  streamID,
3309  makeBuf(20),
3310  HTTPCodec::NoPadding,
3311  true);
3312  auto handler1 = addSimpleStrictHandler();
3313 
3314  InSequence enforceOrder;
3315  handler1->expectHeaders();
3316  handler1->expectError([&] (const HTTPException&) {
3317  if (handler1->txn_) {
3318  handler1->txn_->setHandler(nullptr);
3319  }
3320  handler1->txn_ = nullptr;
3321  });
3322  flushRequestsAndLoop();
3323 
3324  gracefulShutdown();
3325 }
3326 
3327 TEST_F(HTTP2DownstreamSessionTest, TestLongContentLength) {
3328  auto req = getPostRequest(30);
3329  auto streamID = sendRequest(req, false);
3330  clientCodec_->generateBody(requests_, streamID, makeBuf(20),
3331  HTTPCodec::NoPadding, true);
3332  auto handler1 = addSimpleStrictHandler();
3333 
3334  InSequence enforceOrder;
3335  handler1->expectHeaders();
3336  handler1->expectBody();
3337  handler1->expectError([&handler1] (const HTTPException& ex) {
3339  handler1->txn_->sendAbort();
3340  });
3341  handler1->expectDetachTransaction();
3342  flushRequestsAndLoop();
3343 
3344  gracefulShutdown();
3345 }
3346 
3347 TEST_F(HTTP2DownstreamSessionTest, TestMalformedContentLength) {
3348  auto req = getPostRequest();
3349  req.getHeaders().set(HTTP_HEADER_CONTENT_LENGTH, "malformed");
3350  auto streamID = sendRequest(req, false);
3351  clientCodec_->generateBody(requests_, streamID, makeBuf(20),
3352  HTTPCodec::NoPadding, true);
3353  auto handler1 = addSimpleStrictHandler();
3354 
3355  InSequence enforceOrder;
3356  handler1->expectHeaders();
3357  handler1->expectBody();
3358  handler1->expectEOM([&handler1] {
3359  handler1->sendReplyWithBody(200, 100);
3360  });
3361  handler1->expectDetachTransaction();
3362  flushRequestsAndLoop();
3363 
3364  gracefulShutdown();
3365 }
3366 
3367 TEST_F(HTTP2DownstreamSessionTest, TestHeadContentLength) {
3368  InSequence enforceOrder;
3369  auto req = getGetRequest();
3370  req.setMethod(HTTPMethod::HEAD);
3371  sendRequest(req);
3372  auto handler1 = addSimpleStrictHandler();
3373 
3374  handler1->expectHeaders();
3375  handler1->expectEOM([&handler1] {
3376  handler1->sendHeaders(200, 100);
3377  // no body for head
3378  handler1->txn_->sendEOM();
3379  });
3380  handler1->expectDetachTransaction();
3381  flushRequestsAndLoop();
3382 
3383  gracefulShutdown();
3384 }
3385 
3386 TEST_F(HTTP2DownstreamSessionTest, Test304ContentLength) {
3387  InSequence enforceOrder;
3388  auto req = getGetRequest();
3389  req.setMethod(HTTPMethod::HEAD);
3390  sendRequest(req);
3391  auto handler1 = addSimpleStrictHandler();
3392 
3393  handler1->expectHeaders();
3394  handler1->expectEOM([&handler1] {
3395  handler1->sendHeaders(304, 100);
3396  handler1->txn_->sendEOM();
3397  });
3398  handler1->expectDetachTransaction();
3399  flushRequestsAndLoop();
3400 
3401  gracefulShutdown();
3402 }
3403 
3404 // chunked with wrong content-length
3405 TEST_F(HTTPDownstreamSessionTest, HttpShortContentLength) {
3406  InSequence enforceOrder;
3407  auto req = getPostRequest(10);
3408  req.setIsChunked(true);
3409  req.getHeaders().add(HTTP_HEADER_TRANSFER_ENCODING, "chunked");
3410  auto streamID = sendRequest(req, false);
3411  clientCodec_->generateChunkHeader(requests_, streamID, 20);
3412  clientCodec_->generateBody(requests_, streamID, makeBuf(20),
3413  HTTPCodec::NoPadding, false);
3414  clientCodec_->generateChunkTerminator(requests_, streamID);
3415  clientCodec_->generateEOM(requests_, streamID);
3416  auto handler1 = addSimpleStrictHandler();
3417 
3418  handler1->expectHeaders();
3419  EXPECT_CALL(*handler1, onChunkHeader(20));
3420 
3421  handler1->expectError([&handler1] (const HTTPException& ex) {
3423  handler1->txn_->sendAbort();
3424  });
3425  handler1->expectDetachTransaction();
3426  expectDetachSession();
3427  flushRequestsAndLoop();
3428 
3429 }
3430 
3431 TEST_F(HTTP2DownstreamSessionTest, TestSessionStallByFlowControl) {
3433  // By default the send and receive windows are 64K each.
3434  // If we use only a single transaction, that transaction
3435  // will be paused on reaching 64K. Therefore, to pause the session,
3436  // it is used 2 transactions each sending 32K.
3437 
3438  // Make write buffer limit exceding 64K, for example 128K
3439  httpSession_->setWriteBufferLimit(128 * 1024);
3440  httpSession_->setSessionStats(&stats);
3441 
3442  InSequence enforceOrder;
3443  sendRequest();
3444  sendRequest();
3445 
3446  auto handler1 = addSimpleStrictHandler();
3447 
3448  handler1->expectHeaders();
3449  handler1->expectEOM([&] {
3450  handler1->sendReplyWithBody(200, 32 * 1024);
3451  });
3452 
3453  auto handler2 = addSimpleStrictHandler();
3454  handler2->expectHeaders();
3455  handler2->expectEOM([&] {
3456  handler2->sendReplyWithBody(200, 32 * 1024);
3457  });
3458 
3459  EXPECT_CALL(stats, recordSessionStalled()).Times(1);
3460 
3461  handler1->expectDetachTransaction();
3462 
3463  // twice- once to send and once to receive
3464  flushRequestsAndLoopN(2);
3465 
3466  // open the window
3467  clientCodec_->generateWindowUpdate(requests_, 0, 100);
3468  handler2->expectDetachTransaction();
3469  flushRequestsAndLoopN(2);
3470 
3471  httpSession_->closeWhenIdle();
3472  expectDetachSession();
3473  flushRequestsAndLoop();
3474 }
3475 
3476 TEST_F(HTTP2DownstreamSessionTest, TestTransactionStallByFlowControl) {
3478 
3479  httpSession_->setSessionStats(&stats);
3480 
3481  // Set the client side stream level flow control wind to 500 bytes,
3482  // and try to send 1000 bytes through it.
3483  // Then the flow control kicks in and stalls the transaction.
3484  clientCodec_->getEgressSettings()->setSetting(SettingsId::INITIAL_WINDOW_SIZE,
3485  500);
3486  clientCodec_->generateSettings(requests_);
3487 
3488  auto streamID = sendRequest();
3489 
3490  EXPECT_CALL(stats, recordTransactionOpened());
3491 
3492  InSequence handlerSequence;
3493  auto handler = addSimpleStrictHandler();
3494  handler->expectHeaders();
3495  handler->expectEOM([&] {
3496  handler->sendReplyWithBody(200, 1000);
3497  });
3498 
3499  EXPECT_CALL(stats, recordTransactionStalled());
3500  handler->expectEgressPaused();
3501 
3502  handler->expectError([&] (const HTTPException& ex) {
3504  ASSERT_EQ(
3505  folly::to<std::string>("ingress timeout, streamID=", streamID),
3506  std::string(ex.what()));
3507  handler->terminate();
3508  });
3509 
3510  handler->expectDetachTransaction();
3511 
3512  EXPECT_CALL(stats, recordTransactionClosed());
3513 
3514  flushRequestsAndLoop();
3515  gracefulShutdown();
3516 }
3517 
3518 TEST_F(HTTP2DownstreamSessionTest, TestTransactionNotStallByFlowControl) {
3520 
3521  httpSession_->setSessionStats(&stats);
3522 
3523  clientCodec_->getEgressSettings()->setSetting(SettingsId::INITIAL_WINDOW_SIZE,
3524  500);
3525  clientCodec_->generateSettings(requests_);
3526 
3527  sendRequest();
3528 
3529  EXPECT_CALL(stats, recordTransactionOpened());
3530 
3531  InSequence handlerSequence;
3532  auto handler = addSimpleStrictHandler();
3533  handler->expectHeaders();
3534  handler->expectEOM([&] {
3535  handler->sendReplyWithBody(200, 500);
3536  });
3537 
3538  // The egtress paused is notified due to existing logics,
3539  // but egress transaction should not be counted as stalled by flow control,
3540  // because there is nore more bytes to send
3541  handler->expectEgressPaused();
3542 
3543  handler->expectDetachTransaction();
3544 
3545  EXPECT_CALL(stats, recordTransactionClosed());
3546 
3547  flushRequestsAndLoop();
3548  gracefulShutdown();
3549 }
3550 
3551 TEST_F(HTTP2DownstreamSessionTest, TestSetEgressSettings) {
3552  SettingsList settings = {{ SettingsId::HEADER_TABLE_SIZE, 5555 },
3553  { SettingsId::MAX_FRAME_SIZE, 16384 },
3554  { SettingsId::ENABLE_PUSH, 1 }};
3555 
3556  const HTTPSettings* codecSettings = rawCodec_->getEgressSettings();
3557  for (const auto& setting: settings) {
3558  const HTTPSetting* currSetting = codecSettings->getSetting(setting.id);
3559  if (currSetting) {
3560  EXPECT_EQ(setting.value, currSetting->value);
3561  }
3562  }
3563 
3564  flushRequestsAndLoop();
3565  gracefulShutdown();
3566 }
void expect101(CodecProtocol expectedProtocol, const std::string &expectedUpgrade, bool expect100=false)
folly::HHWheelTimer::UniquePtr makeInternalTimeoutSet(EventBase *evb)
Definition: TestUtils.cpp:22
#define EXPECT_LE(val1, val2)
Definition: gtest.h:1928
virtual void setHandler(Handler *handler)
StrictMock< MockController > mockController_
std::unique_ptr< testing::NiceMock< MockHTTPCodec > > makeDownstreamParallelCodec()
Definition: TestUtils.cpp:67
virtual size_t onIngress(const folly::IOBuf &buf)=0
std::chrono::milliseconds millisecondsBetween(std::chrono::time_point< ClockType > finish, std::chrono::time_point< ClockType > start)
Definition: Time.h:85
const uint32_t kInitialWindow
void parseOutput(HTTPCodec &clientCodec)
bool exists(folly::StringPiece name) const
Definition: HTTPHeaders.cpp:86
virtual void onError(StreamID stream, const HTTPException &error, bool newTxn=false)=0
GTEST_API_ Cardinality AtLeast(int n)
HTTPCodec::StreamID sendRequest(const std::string &url="/", int8_t priority=0, bool eom=true)
void setWantsKeepalive(bool wantsKeepaliveVal)
Definition: HTTPMessage.h:343
ProxygenError getProxygenError() const
Definition: Exception.h:50
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
LogLevel max
Definition: LogLevel.cpp:31
const SocketAddress peerAddr
Definition: TestUtils.cpp:20
void testSimpleUpgrade(const std::string &upgradeHeader, CodecProtocol expectedProtocol, const std::string &expectedUpgradeHeader)
const std::string & getStatusMessage() const
Definition: HTTPMessage.h:245
void setEventBase(EventBase *eventBase, bool takeOwnership)
const std::string kProtocolCleartextString
std::vector< int64_t > flowControl_
void setStatusMessage(T &&msg)
Definition: HTTPMessage.h:242
uint16_t getStatusCode() const
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
void onEOMTerminateHandlerExpectShutdown(MockHTTPHandler &handler)
TestAsyncTransport * transport_
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
CodecFactory codec
::testing::Types< SPDY3CodecPair, SPDY3_1CodecPair, HTTP2CodecPair > ParallelCodecs
STL namespace.
void resumeWritesAfterDelay(milliseconds delay)
void setProxygenError(ProxygenError proxygenError)
Definition: Exception.h:46
static http_parser_settings settings
Definition: test.c:1529
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void setCodecStatusCode(ErrorCode statusCode)
Definition: HTTPException.h:98
void setByteEventTracker(std::shared_ptr< ByteEventTracker > byteEventTracker)
const wangle::TransportInfo mockTransportInfo
Definition: TestUtils.cpp:18
MockByteEventTracker * setMockByteEventTracker()
#define EXPECT_GE(val1, val2)
Definition: gtest.h:1932
INSTANTIATE_TYPED_TEST_CASE_P(ParallelCodecs, HTTPDownstreamTest, ParallelCodecs)
requires And< SemiMovable< VN >... > &&SemiMovable< E > auto error(E e)
Definition: error.h:48
tuple make_tuple()
Definition: gtest-tuple.h:675
PolymorphicAction< internal::InvokeWithoutArgsAction< FunctionImpl > > InvokeWithoutArgs(FunctionImpl function_impl)
const HeaderIndexingStrategy * getHeaderIndexingStrategy() const
Definition: HTTP2Codec.h:174
static EventBaseManager * get()
void testPriorities(uint32_t numPriorities)
void handler(int, siginfo_t *, void *)
ProtocolVersion version
std::unique_ptr< folly::IOBuf > makeBuf(uint32_t size)
Definition: ZlibTests.cpp:26
HTTPCodec::StreamID sendRequest(const HTTPMessage &req, bool eom=true)
void set(folly::StringPiece name, const std::string &value)
Definition: HTTPHeaders.h:119
void flushRequestsAndLoop(bool eof=false, milliseconds eofDelay=milliseconds(0), milliseconds initialDelay=milliseconds(0), std::function< void()> extraEventsFn=std::function< void()>())
std::unique_ptr< AsyncTransportWrapper, Destructor > UniquePtr
ParseURL setURL(T &&url)
Definition: HTTPMessage.h:183
folly::HHWheelTimer::UniquePtr transactionTimeouts_
static Options cacheChainLength()
Definition: IOBufQueue.h:83
void setHTTP2Priority(HTTPPriority h2Pri)
Definition: HTTPMessage.h:599
folly::HHWheelTimer::UniquePtr makeTimeoutSet(EventBase *evb)
Definition: TestUtils.cpp:31
Direction getDirection() const
Definition: HTTPException.h:67
PolymorphicAction< internal::InvokeAction< FunctionImpl > > Invoke(FunctionImpl function_impl)
void setPrioritySampled(bool sampled)
NiceMock< MockHTTPCodecCallback > callbacks_
const uint32_t kFrameWindowUpdateSize
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
HTTPCodec::StreamID sendHeader()
ErrorCode getCodecStatusCode() const
Future< T > getFuture()
Definition: Promise-inl.h:97
void expectEOM(std::function< void()> callback=std::function< void()>())
REGISTER_TYPED_TEST_CASE_P(HTTPDownstreamTest, TestWritesDraining, TestBodySizeLimit, TestUniformPauseState, TestMaxTxns)
HTTPMessage getResponse(uint32_t code, uint32_t bodyLen)
Definition: TestUtils.cpp:137
void expectResponse(uint32_t code=200, ErrorCode errorCode=ErrorCode::NO_ERROR, bool expect100=false, bool expectGoaway=false)
Definition: Traits.h:588
TYPED_TEST_P(HTTPDownstreamTest, TestWritesDraining)
void addSingleByteReads(const char *data, milliseconds delay={})
#define IF_HTTP2(X)
HTTPHeaders & getHeaders()
Definition: HTTPMessage.h:273
void expectDetachTransaction(std::function< void()> callback=std::function< void()>())
const std::string & getSingleOrEmpty(const T &nameOrCode) const
Definition: HTTPHeaders.h:420
std::unique_ptr< HHWheelTimer, Destructor > UniquePtr
Definition: HHWheelTimer.h:57
auto start
TEST_F(AsyncSSLSocketWriteTest, write_coalescing1)
int * count
size_t size() const
std::tuple< uint32_t, bool, uint8_t > HTTPPriority
Definition: HTTPMessage.h:592
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
SteadyClock::time_point TimePoint
Definition: Time.h:25
std::vector< HTTPSetting > SettingsList
Definition: HTTPSettings.h:81
HeaderIndexingStrategy testH2IndexingStrat_
bool isParallelCodecProtocol(CodecProtocol protocol)
HTTPMessage getGetRequest(const std::string &url)
Definition: TestUtils.cpp:76
const char * string
Definition: Conv.cpp:212
unique_ptr< HTTPCodec > clientCodec_
void flushRequests(bool eof=false, milliseconds eofDelay=milliseconds(0), milliseconds initialDelay=milliseconds(0), std::function< void()> extraEventsFn=std::function< void()>())
g_t g(f_t)
AsyncFizzClient::UniquePtr transport_
static set< string > s
HTTPMessage getPostRequest(uint32_t contentLength)
Definition: TestUtils.cpp:102
std::chrono::time_point< ClockType > getCurrentTime()
Definition: Time.h:41
const SocketAddress localAddr
Definition: TestUtils.cpp:19
testing::NiceMock< MockAsyncTransport > * newMockTransport(EventBase *evb)
Definition: TestUtils.cpp:40
void setHTTPVersion(uint8_t major, uint8_t minor)
PolymorphicAction< internal::AssignAction< T1, T2 > > Assign(T1 *ptr, T2 val)
void flushRequestsAndLoopN(uint64_t n, bool eof=false, milliseconds eofDelay=milliseconds(0), milliseconds initialDelay=milliseconds(0), std::function< void()> extraEventsFn=std::function< void()>())
Promise< Unit > sendRequestLater(HTTPMessage req, bool eof=false)
std::unique_ptr< testing::NiceMock< MockHTTPHandler > > addSimpleNiceHandler()
SettingsValue value
Definition: HTTPSettings.h:32
#define EXPECT_CALL(obj, call)
uint64_t StreamID
Definition: HTTPCodec.h:49
const internal::AnythingMatcher _
virtual void writeSuccess() noexcept=0
std::unique_ptr< testing::StrictMock< MockHTTPHandler > > addSimpleStrictHandler()
void add(folly::StringPiece name, folly::StringPiece value)
Definition: HTTPHeaders.cpp:52
#define ASSERT_NE(val1, val2)
Definition: gtest.h:1960
HTTPDownstreamSession * httpSession_
HTTPMessage getUpgradeRequest(const std::string &upgradeHeader, HTTPMethod method, uint32_t bodyLen)
Definition: TestUtils.cpp:161
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
void expectResponses(uint32_t n, uint32_t code=200, ErrorCode errorCode=ErrorCode::NO_ERROR, bool expect100=false, bool expectGoaway=false)
#define EXPECT_LT(val1, val2)
Definition: gtest.h:1930
TYPED_TEST_CASE_P(HTTPDownstreamTest)
Future< Unit > times(const int n, F &&thunk)
Definition: Future-inl.h:2348
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
const char * what(void) const noexceptoverride
Definition: Exception.cpp:26
#define ASSERT_TRUE(condition)
Definition: gtest.h:1865
uint32_t streamID
Definition: SPDYCodec.cpp:131
std::unique_ptr< Codec > getCodec(CodecType type, int level)
TEST(SequencedExecutor, CPUThreadPoolExecutor)
void cleanup()
Definition: Init.cpp:59
HTTPDownstreamTest(std::vector< int64_t > flowControl={-1,-1,-1}, bool startImmediately=true)
internal::ReturnAction< R > Return(R value)
const HTTPSetting * getSetting(SettingsId id) const
#define EXPECT_GT(val1, val2)
Definition: gtest.h:1934
void writeBE(T value)
Definition: Cursor.h:744
void setStatusCode(uint16_t status)