proxygen
HTTPUpstreamSessionTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
10 #include <folly/io/Cursor.h>
24 #include <string>
26 #include <vector>
27 
29 
30 using namespace folly;
31 using namespace proxygen;
32 using namespace testing;
33 
34 using std::string;
35 using std::unique_ptr;
36 using std::vector;
37 
38 class TestPriorityMapBuilder : public HTTPUpstreamSession::PriorityMapFactory {
39 public:
40  virtual std::unique_ptr<HTTPUpstreamSession::PriorityAdapter>
41  createVirtualStreams(HTTPPriorityMapFactoryProvider* session) const
42  override;
43  virtual ~TestPriorityMapBuilder() = default;
44 
45  uint8_t hiPriWeight_{18};
46  uint8_t hiPriLevel_{0};
47  uint8_t loPriWeight_{2};
48  uint8_t loPriLevel_{2};
49 };
50 
51 class TestPriorityAdapter : public HTTPUpstreamSession::PriorityAdapter {
52 public:
54  uint8_t level) override {
55  if (priorityMap_.empty()) {
56  return folly::none;
57  }
58  auto it = priorityMap_.find(level);
59  if (it == priorityMap_.end()) {
60  return minPriority_;
61  }
62  return it->second;
63  }
64 
65  virtual ~TestPriorityAdapter() = default;
66 
67  std::map<uint8_t, HTTPMessage::HTTPPriority> priorityMap_;
68  HTTPMessage::HTTPPriority minPriority_{std::make_tuple(0, false, 0)};
69  HTTPCodec::StreamID parentId_{0};
70  HTTPCodec::StreamID hiPriId_{0};
71  HTTPCodec::StreamID loPriId_{0};
74 };
75 
76 std::unique_ptr<HTTPUpstreamSession::PriorityAdapter>
78  HTTPPriorityMapFactoryProvider* session) const {
79  std::unique_ptr<TestPriorityAdapter> a =
80  std::make_unique<TestPriorityAdapter>();
81  a->parentId_ = session->sendPriority({0, false, 1});
82 
83  std::get<0>(a->hiPri_) = a->parentId_;
84  std::get<2>(a->hiPri_) = hiPriWeight_;
85  a->hiPriId_ = session->sendPriority({(uint32_t)a->parentId_, false, hiPriWeight_});
86  a->priorityMap_[hiPriLevel_] = a->hiPri_;
87 
88  std::get<0>(a->loPri_) = a->parentId_;
89  std::get<2>(a->loPri_) = loPriWeight_;
90  a->loPriId_ = session->sendPriority({(uint32_t)a->parentId_, false, loPriWeight_});
91  a->priorityMap_[loPriLevel_] = a->loPri_;
92 
93  a->minPriority_ = a->loPri_;
94 
95  return std::move(a);
96 }
97 
98 namespace {
99 HTTPMessage getUpgradePostRequest(uint32_t bodyLen,
100  const std::string& upgradeHeader,
101  bool expect100 = false) {
102  HTTPMessage req = getPostRequest(bodyLen);
103  req.getHeaders().set(HTTP_HEADER_UPGRADE, upgradeHeader);
104  if (expect100) {
105  req.getHeaders().add(HTTP_HEADER_EXPECT, "100-continue");
106  }
107  return req;
108 }
109 
110 std::unique_ptr<folly::IOBuf>
111 getResponseBuf(CodecProtocol protocol, HTTPCodec::StreamID id,
112  uint32_t code, uint32_t bodyLen, bool include100 = false) {
113  auto egressCodec =
114  HTTPCodecFactory::getCodec(protocol, TransportDirection::DOWNSTREAM);
116  egressCodec->generateSettings(respBufQ);
117  if (include100) {
118  HTTPMessage msg;
119  msg.setStatusCode(100);
120  msg.setStatusMessage("continue");
121  egressCodec->generateHeader(respBufQ, id, msg);
122  }
123  HTTPMessage resp = getResponse(code, bodyLen);
124  egressCodec->generateHeader(respBufQ, id, resp);
125  if (bodyLen > 0) {
126  auto buf = makeBuf(bodyLen);
127  egressCodec->generateBody(respBufQ, id, std::move(buf),
128  HTTPCodec::NoPadding, true /* eom */);
129  }
130  return respBufQ.move();
131 }
132 
133 }
134 
135 template <class C>
138  public:
139  explicit HTTPUpstreamTest(std::vector<int64_t> flowControl = {-1, -1, -1})
140  : eventBase_(),
142  transactionTimeouts_(folly::HHWheelTimer::newTimer(
143  &eventBase_,
144  std::chrono::milliseconds(
147  std::chrono::milliseconds(500))),
148  flowControl_(flowControl) {}
149 
150  void resumeWrites() {
151  pauseWrites_ = false;
152  for (auto cb: cbs_) {
153  handleWrite(cb);
154  }
155  cbs_.clear();
156  }
157 
158  virtual void onWriteChain(
160  std::shared_ptr<IOBuf> iob,
161  WriteFlags) {
162  if (pauseWrites_) {
163  cbs_.push_back(callback);
164  return; // let write requests timeout
165  }
166  auto mybuf = iob->clone();
167  mybuf->unshare();
168  writes_.append(std::move(mybuf));
169  handleWrite(callback);
170  }
171 
173  if (failWrites_) {
175  callback->writeErr(0, ex);
176  } else {
177  if (writeInLoop_) {
178  eventBase_.runInLoop([&] {
179  callback->writeSuccess();
180  });
181  } else {
182  callback->writeSuccess();
183  }
184  }
185  }
186 
187  void SetUp() override {
188  commonSetUp(makeClientCodec<typename C::Codec>(C::version));
189  }
190 
191  void commonSetUp(unique_ptr<HTTPCodec> codec) {
192  HTTPSession::setDefaultReadBufferLimit(65536);
193  HTTPSession::setDefaultWriteBufferLimit(65536);
194  EXPECT_CALL(*transport_, writeChain(_, _, _))
195  .WillRepeatedly(Invoke(this, &HTTPUpstreamTest<C>::onWriteChain));
196  EXPECT_CALL(*transport_, setReadCB(_))
197  .WillRepeatedly(SaveArg<0>(&readCallback_));
198  EXPECT_CALL(*transport_, getReadCB())
199  .WillRepeatedly(Return(readCallback_));
201  .WillRepeatedly(ReturnPointee(&eventBasePtr_));
202  EXPECT_CALL(*transport_, good())
203  .WillRepeatedly(ReturnPointee(&transportGood_));
204  EXPECT_CALL(*transport_, closeNow())
205  .WillRepeatedly(Assign(&transportGood_, false));
206  EXPECT_CALL(*transport_, isReplaySafe())
207  .WillOnce(Return(false));
208  EXPECT_CALL(*transport_, setReplaySafetyCallback(_))
209  .WillRepeatedly(SaveArg<0>(&replaySafetyCallback_));
210  EXPECT_CALL(*transport_, attachEventBase(_))
211  .WillRepeatedly(SaveArg<0>(&eventBasePtr_));
212 
213  for (auto& param: flowControl_) {
214  if (param < 0) {
215  param = codec->getDefaultWindowSize();
216  }
217  }
218  httpSession_ = new HTTPUpstreamSession(
219  transactionTimeouts_.get(),
221  localAddr_, peerAddr_,
222  std::move(codec),
223  mockTransportInfo_, this);
224  httpSession_->setFlowControl(flowControl_[0], flowControl_[1],
225  flowControl_[2]);
226  httpSession_->setMaxConcurrentOutgoingStreams(10);
227  httpSession_->setEgressSettings({{SettingsId::ENABLE_EX_HEADERS, 1}});
228  httpSession_->startNow();
229  eventBase_.loop();
230  ASSERT_EQ(this->sessionDestroyed_, false);
231  }
232 
233  unique_ptr<typename C::Codec> makeServerCodec() {
234  return ::makeServerCodec<typename C::Codec>(C::version);
235  }
236 
237  void enableExHeader(typename C::Codec* serverCodec){
238  if (!serverCodec || serverCodec->getProtocol() != CodecProtocol::HTTP_2) {
239  return;
240  }
241 
242  auto clientCodec = makeClientCodec<HTTP2Codec>(2);
244  clientCodec->getEgressSettings()->setSetting(
245  SettingsId::ENABLE_EX_HEADERS, 1);
246  clientCodec->generateConnectionPreface(c2s);
247  clientCodec->generateSettings(c2s);
248 
249  // set ENABLE_EX_HEADERS to 1 in egressSettings
250  serverCodec->getEgressSettings()->setSetting(
251  SettingsId::ENABLE_EX_HEADERS, 1);
252  // set ENABLE_EX_HEADERS to 1 in ingressSettings
253  auto setup = c2s.move();
254  serverCodec->onIngress(*setup);
255  }
256 
257  void parseOutput(HTTPCodec& serverCodec) {
259  while (!writes_.empty() && consumed > 0) {
260  consumed = serverCodec.onIngress(*writes_.front());
261  writes_.split(consumed);
262  }
263  EXPECT_TRUE(writes_.empty());
264  }
265 
266  void readAndLoop(const std::string& input) {
267  readAndLoop((const uint8_t *)input.data(), input.length());
268  }
269 
270  void readAndLoop(IOBuf* buf) {
271  buf->coalesce();
272  readAndLoop(buf->data(), buf->length());
273  }
274 
275  void readAndLoop(const uint8_t* input, size_t length) {
276  CHECK_NOTNULL(readCallback_);
277  void* buf;
278  size_t bufSize;
279  while (length > 0) {
280  readCallback_->getReadBuffer(&buf, &bufSize);
281  // This is somewhat specific to our implementation, but currently we
282  // always return at least some space from getReadBuffer
283  CHECK_GT(bufSize, 0);
284  bufSize = std::min(bufSize, length);
285  memcpy(buf, input, bufSize);
286  readCallback_->readDataAvailable(bufSize);
287  eventBasePtr_->loop();
288  length -= bufSize;
289  input += bufSize;
290  }
291  }
292 
293  void testBasicRequest();
294  void testBasicRequestHttp10(bool keepalive);
295 
296  // HTTPSession::InfoCallback interface
297  void onCreate(const HTTPSessionBase&) override { sessionCreated_ = true; }
298  void onDestroy(const HTTPSessionBase&) override { sessionDestroyed_ = true; }
300  transactionsFull_ = true;
301  }
303  transactionsFull_ = false;
304  }
305 
306  void TearDown() override {
308  for (auto& cb : cbs_) {
309  cb->writeErr(0, ex);
310  }
311  }
312 
313  std::unique_ptr<StrictMock<MockHTTPHandler>> openTransaction(
314  bool expectStartPaused = false) {
315  // Returns a mock handler with txn_ field set in it
316  auto handler = std::make_unique<StrictMock<MockHTTPHandler>>();
317  handler->expectTransaction();
318  if (expectStartPaused) {
319  handler->expectEgressPaused();
320  }
321  auto txn = httpSession_->newTransaction(handler.get());
322  EXPECT_EQ(txn, handler->txn_);
323  return handler;
324  }
325 
326  std::unique_ptr<NiceMock<MockHTTPHandler>> openNiceTransaction(
327  bool expectStartPaused = false) {
328  // Returns a mock handler with txn_ field set in it
329  auto handler = std::make_unique<NiceMock<MockHTTPHandler>>();
330  handler->expectTransaction();
331  if (expectStartPaused) {
332  handler->expectEgressPaused();
333  }
334  auto txn = httpSession_->newTransaction(handler.get());
335  EXPECT_EQ(txn, handler->txn_);
336  return handler;
337  }
338 
339  void testSimpleUpgrade(const std::string& upgradeReqHeader,
340  const std::string& upgradeRespHeader,
341  CodecProtocol respCodecVersion);
342 
344  auto byteEventTracker = new MockByteEventTracker(nullptr);
345  httpSession_->setByteEventTracker(
346  std::unique_ptr<ByteEventTracker>(byteEventTracker));
347  EXPECT_CALL(*byteEventTracker, preSend(_, _, _))
348  .WillRepeatedly(Return(0));
349  EXPECT_CALL(*byteEventTracker, drainByteEvents())
350  .WillRepeatedly(Return(0));
351  EXPECT_CALL(*byteEventTracker, processByteEvents(_, _))
352  .WillRepeatedly(Invoke([]
353  (std::shared_ptr<ByteEventTracker> self,
354  uint64_t bytesWritten) {
355  return self->ByteEventTracker::processByteEvents(
356  self,
357  bytesWritten);
358  }));
359 
360  return byteEventTracker;
361  }
362 
363  protected:
364  bool sessionCreated_{false};
365  bool sessionDestroyed_{false};
366 
367  bool transactionsFull_{false};
368  bool transportGood_{true};
369 
371  EventBase* eventBasePtr_{&eventBase_};
372  MockAsyncTransport* transport_; // invalid once httpSession_ is destroyed
374  folly::AsyncTransport::ReplaySafetyCallback* replaySafetyCallback_{nullptr};
376  std::vector<int64_t> flowControl_;
378  SocketAddress localAddr_{"127.0.0.1", 80};
379  SocketAddress peerAddr_{"127.0.0.1", 12345};
380  HTTPUpstreamSession* httpSession_{nullptr};
382  std::vector<folly::AsyncTransportWrapper::WriteCallback*> cbs_;
383  bool failWrites_{false};
384  bool pauseWrites_{false};
385  bool writeInLoop_{false};
386 };
388 
389 template <class C>
391  public:
393  // make it non-internal for this test class
397  std::chrono::milliseconds(folly::HHWheelTimer::DEFAULT_TICK_INTERVAL),
399  std::chrono::milliseconds(500));
400  }
401 };
402 
406 
408  SPDYCodec egressCodec(TransportDirection::DOWNSTREAM,
409  SPDYVersion::SPDY3);
411 
412  HTTPMessage push;
413  push.getHeaders().set("HOST", "www.foo.com");
414  push.setURL("https://www.foo.com/");
415  egressCodec.generatePushPromise(output, 2, push, 1, false, nullptr);
416  auto buf = makeBuf(100);
417  egressCodec.generateBody(output, 2, std::move(buf), HTTPCodec::NoPadding,
418  true /* eom */);
419 
420  HTTPMessage resp;
421  resp.setStatusCode(200);
422  resp.setStatusMessage("Ohai");
423  egressCodec.generateHeader(output, 1, resp, false, nullptr);
424  buf = makeBuf(100);
425  egressCodec.generateBody(output, 1, std::move(buf), HTTPCodec::NoPadding,
426  true /* eom */);
427 
428  std::unique_ptr<folly::IOBuf> input = output.move();
429  input->coalesce();
430 
431  MockHTTPHandler pushHandler;
432 
433  InSequence enforceOrder;
434 
435  auto handler = openTransaction();
436  EXPECT_CALL(*handler, onPushedTransaction(_))
437  .WillOnce(Invoke([&pushHandler] (HTTPTransaction* pushTxn) {
438  pushTxn->setHandler(&pushHandler);
439  }));
440  EXPECT_CALL(pushHandler, setTransaction(_));
441  EXPECT_CALL(pushHandler, onHeadersComplete(_))
442  .WillOnce(Invoke([&] (std::shared_ptr<HTTPMessage> msg) {
443  EXPECT_EQ(httpSession_->getNumIncomingStreams(), 1);
444  EXPECT_TRUE(msg->getIsChunked());
445  EXPECT_FALSE(msg->getIsUpgraded());
446  EXPECT_EQ(msg->getPath(), "/");
447  EXPECT_EQ(msg->getHeaders().getSingleOrEmpty(HTTP_HEADER_HOST),
448  "www.foo.com");
449  }));
450  EXPECT_CALL(pushHandler, onBody(_));
451  EXPECT_CALL(pushHandler, onEOM());
452  EXPECT_CALL(pushHandler, detachTransaction());
453 
454  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
455  EXPECT_FALSE(msg->getIsUpgraded());
456  EXPECT_EQ(200, msg->getStatusCode());
457  });
458  EXPECT_CALL(*handler, onBody(_));
459  handler->expectEOM();
460  handler->expectDetachTransaction();
461 
462  handler->sendRequest();
463  readAndLoop(input->data(), input->length());
464 
465  EXPECT_EQ(httpSession_->getNumIncomingStreams(), 0);
466  httpSession_->destroy();
467 }
468 
469 TEST_F(SPDY3UpstreamSessionTest, IngressGoawayAbortUncreatedStreams) {
470  // Tests whether the session aborts the streams which are not created
471  // at the remote end.
472 
473  // Create SPDY buf for GOAWAY with last good stream as 0 (no streams created)
474  SPDYCodec egressCodec(TransportDirection::DOWNSTREAM,
475  SPDYVersion::SPDY3);
477  egressCodec.generateGoaway(respBuf, 0, ErrorCode::NO_ERROR);
478  std::unique_ptr<folly::IOBuf> goawayFrame = respBuf.move();
479  goawayFrame->coalesce();
480 
481  InSequence enforceOrder;
482 
483  auto handler = openTransaction();
484  handler->expectGoaway();
485  handler->expectError([&] (const HTTPException& err) {
488  ASSERT_EQ(
489  folly::to<std::string>("StreamUnacknowledged on transaction id: ",
490  handler->txn_->getID()),
491  std::string(err.what()));
492  });
493  handler->expectDetachTransaction([this] {
494  // Make sure the session can't create any more transactions.
495  MockHTTPHandler handler2;
496  EXPECT_EQ(httpSession_->newTransaction(&handler2), nullptr);
497  });
498 
499  // Send the GET request
500  handler->sendRequest();
501 
502  // Receive GOAWAY frame while waiting for SYN_REPLY
503  readAndLoop(goawayFrame->data(), goawayFrame->length());
504 
505  // Session will delete itself after the abort
506 }
507 
508 TEST_F(SPDY3UpstreamSessionTest, IngressGoawaySessionError) {
509  // Tests whether the session aborts the streams which are not created
510  // at the remote end which have error codes.
511 
512  // Create SPDY buf for GOAWAY with last good stream as 0 (no streams created)
513  SPDYCodec egressCodec(TransportDirection::DOWNSTREAM,
514  SPDYVersion::SPDY3);
516  egressCodec.generateGoaway(respBuf, 0, ErrorCode::PROTOCOL_ERROR);
517  std::unique_ptr<folly::IOBuf> goawayFrame = respBuf.move();
518  goawayFrame->coalesce();
519 
520  InSequence enforceOrder;
521 
522  auto handler = openTransaction();
523  handler->expectGoaway();
524  handler->expectError([&] (const HTTPException& err) {
527  ASSERT_EQ(
528  folly::to<std::string>("StreamUnacknowledged on transaction id: ",
529  handler->txn_->getID(),
530  " with codec error: PROTOCOL_ERROR"),
531  std::string(err.what()));
532  });
533  handler->expectDetachTransaction([this] {
534  // Make sure the session can't create any more transactions.
535  MockHTTPHandler handler2;
536  EXPECT_EQ(httpSession_->newTransaction(&handler2), nullptr);
537  });
538 
539  // Send the GET request
540  handler->sendRequest();
541 
542  // Receive GOAWAY frame while waiting for SYN_REPLY
543  readAndLoop(goawayFrame->data(), goawayFrame->length());
544 
545  // Session will delete itself after the abort
546 }
547 
548 TEST_F(SPDY3UpstreamSessionTest, TestUnderLimitOnWriteError) {
549  InSequence enforceOrder;
550  auto handler = openTransaction();
551 
552  auto req = getPostRequest();
553  handler->txn_->sendHeaders(req);
554  // pause writes
555  pauseWrites_ = true;
556  handler->expectEgressPaused();
557 
558  // send body
559  handler->txn_->sendBody(makeBuf(70000));
560  eventBase_.loopOnce();
561 
562  // but no expectEgressResumed
563  handler->expectError();
564  handler->expectDetachTransaction();
565  failWrites_ = true;
566  resumeWrites();
567 
568  this->eventBase_.loop();
569  EXPECT_EQ(this->sessionDestroyed_, true);
570 }
571 
572 TEST_F(SPDY3UpstreamSessionTest, TestOverlimitResume) {
573  InSequence enforceOrder;
574  auto handler1 = openTransaction();
575  auto handler2 = openTransaction();
576 
577  // Disable stream flow control for this test
578  handler1->txn_->onIngressWindowUpdate(80000);
579  handler2->txn_->onIngressWindowUpdate(80000);
580 
581  auto req = getPostRequest();
582  handler1->txn_->sendHeaders(req);
583  handler2->txn_->sendHeaders(req);
584  // pause writes
585  pauseWrites_ = true;
586  handler1->expectEgressPaused();
587  handler2->expectEgressPaused();
588 
589  // send body
590  handler1->txn_->sendBody(makeBuf(70000));
591  handler2->txn_->sendBody(makeBuf(70000));
592  eventBase_.loopOnce();
593 
594  // when this handler is resumed, re-pause the pipe
595  handler1->expectEgressResumed([&] {
596  handler1->txn_->sendBody(makeBuf(70000));
597  });
598  // handler2 will get a shot
599  handler2->expectEgressResumed();
600 
601  // both handlers will be paused
602  handler1->expectEgressPaused();
603  handler2->expectEgressPaused();
604  resumeWrites();
605 
606  // They both get resumed
607  handler1->expectEgressResumed([&] { handler1->txn_->sendEOM(); });
608  handler2->expectEgressResumed([&] { handler2->txn_->sendEOM(); });
609 
610  this->eventBase_.loop();
611 
612  // less than graceful shutdown
613  handler1->expectError();
614  handler1->expectDetachTransaction();
615  handler2->expectError();
616  handler2->expectDetachTransaction();
617 
618  httpSession_->dropConnection();
619  EXPECT_EQ(this->sessionDestroyed_, true);
620 }
621 
623  InSequence enforceOrder;
624  // virtual priority node with pri=8
625  auto priGroupID = httpSession_->sendPriority({0, false, 7});
626  auto handler1 = openTransaction();
627  auto handler2 = openTransaction();
628 
629  auto req = getGetRequest();
630  // send request with maximal weight
631  req.setHTTP2Priority(HTTPMessage::HTTPPriority(0, false, 255));
632  handler1->sendRequest(req);
633  handler2->sendRequest(req);
634 
635  auto id = handler1->txn_->getID();
636  auto id2 = handler2->txn_->getID();
637 
638  // Insert depth is 1, only root node has depth 0
639  EXPECT_EQ(std::get<0>(handler1->txn_->getPrioritySummary()), 1);
640  EXPECT_EQ(handler1->txn_->getPriorityFallback(), false);
641 
642  // update handler to be in the pri-group
643  handler1->txn_->updateAndSendPriority(
644  http2::PriorityUpdate{(uint32_t)priGroupID, false, 15});
645  handler2->txn_->updateAndSendPriority(
646  http2::PriorityUpdate{(uint32_t)priGroupID + 254, false, 15});
647 
648  // Change pri-group weight to max
649  httpSession_->sendPriority(priGroupID, http2::PriorityUpdate{0, false, 255});
650  eventBase_.loop();
651 
652  auto serverCodec = makeServerCodec();
654  serverCodec->setCallback(&callbacks);
655  EXPECT_CALL(callbacks, onPriority(priGroupID,
656  HTTPMessage::HTTPPriority(0, false, 7)));
657  EXPECT_CALL(callbacks, onHeadersComplete(id, _))
658  .WillOnce(Invoke([&] (HTTPCodec::StreamID,
659  std::shared_ptr<HTTPMessage> msg) {
660  EXPECT_EQ(*(msg->getHTTP2Priority()),
661  HTTPMessage::HTTPPriority(0, false, 255));
662  }));
663  EXPECT_CALL(callbacks, onHeadersComplete(id2, _))
664  .WillOnce(Invoke([&] (HTTPCodec::StreamID,
665  std::shared_ptr<HTTPMessage> msg) {
666  EXPECT_EQ(*(msg->getHTTP2Priority()),
667  HTTPMessage::HTTPPriority(0, false, 255));
668  }));
669  EXPECT_CALL(callbacks,
670  onPriority(
671  id, HTTPMessage::HTTPPriority(priGroupID, false, 15)));
672  EXPECT_CALL(callbacks,
673  onPriority(
674  id2, HTTPMessage::HTTPPriority(priGroupID + 254, false, 15)));
675  EXPECT_EQ(handler1->txn_->getPriorityFallback(), false);
676  EXPECT_EQ(handler2->txn_->getPriorityFallback(), false);
677 
678  EXPECT_EQ(std::get<1>(handler1->txn_->getPrioritySummary()), 2);
679  // created virtual parent node
680  EXPECT_EQ(std::get<1>(handler2->txn_->getPrioritySummary()), 2);
681  EXPECT_CALL(callbacks,
682  onPriority(priGroupID, HTTPMessage::HTTPPriority(0, false, 255)));
683  parseOutput(*serverCodec);
684  eventBase_.loop();
685 
686  handler1->expectError();
687  handler1->expectDetachTransaction();
688  handler2->expectError();
689  handler2->expectDetachTransaction();
690  httpSession_->dropConnection();
691  eventBase_.loop();
692  EXPECT_EQ(sessionDestroyed_, true);
693 }
694 
695 TEST_F(HTTP2UpstreamSessionTest, TestSettingsAck) {
696  auto serverCodec = makeServerCodec();
698  serverCodec->generateSettings(buf);
699  auto settingsFrame = buf.move();
700  settingsFrame->coalesce();
701 
702  InSequence enforceOrder;
703 
705  serverCodec->setCallback(&callbacks);
706  EXPECT_CALL(callbacks, onSettings(_));
707  EXPECT_CALL(callbacks, onSettingsAck());
708 
709  readAndLoop(settingsFrame.get());
710  parseOutput(*serverCodec);
711  httpSession_->dropConnection();
712  EXPECT_EQ(sessionDestroyed_, true);
713 }
714 
715 TEST_F(HTTP2UpstreamSessionTest, TestSettingsInfoCallbacks) {
716  auto serverCodec = makeServerCodec();
717 
719  serverCodec->generateSettings(settingsBuf);
720  auto settingsFrame = settingsBuf.move();
721 
723  serverCodec->generateSettingsAck(settingsAckBuf);
724  auto settingsAckFrame = settingsAckBuf.move();
725 
727  httpSession_->setInfoCallback(&infoCb);
728 
729  EXPECT_CALL(infoCb, onRead(_, _)).Times(2);
730  EXPECT_CALL(infoCb, onWrite(_, _)).Times(1);
731  EXPECT_CALL(infoCb, onDestroy(_)).Times(1);
732 
733  EXPECT_CALL(infoCb, onSettings(_, _)).Times(1);
734  EXPECT_CALL(infoCb, onSettingsAck(_)).Times(1);
735 
736  InSequence enforceOrder;
737 
738  readAndLoop(settingsFrame.get());
739  readAndLoop(settingsAckFrame.get());
740 
741  httpSession_->destroy();
742 }
743 
744 TEST_F(HTTP2UpstreamSessionTest, TestSetControllerInitHeaderIndexingStrat) {
745  StrictMock<MockUpstreamController> mockController;
746  HeaderIndexingStrategy testH2IndexingStrat;
747  EXPECT_CALL(mockController, getHeaderIndexingStrategy())
748  .WillOnce(
749  Return(&testH2IndexingStrat)
750  );
751 
752  httpSession_->setController(&mockController);
753 
754  auto handler = openTransaction();
755  handler->expectDetachTransaction();
756 
757  const HTTP2Codec* h2Codec = static_cast<const HTTP2Codec*>(
758  &handler->txn_->getTransport().getCodec());
759  EXPECT_EQ(h2Codec->getHeaderIndexingStrategy(), &testH2IndexingStrat);
760 
761  handler->txn_->sendAbort();
762  eventBase_.loop();
763 
764  EXPECT_CALL(mockController, detachSession(_));
765  httpSession_->destroy();
766 }
767 
768 /*
769  * The sequence of streams are generated in the following order:
770  * - [client --> server] setup the control stream (getGetRequest())
771  * - [server --> client] respond to 1st stream (OK, without EOM)
772  * - [server --> client] request 2nd stream (pub, EOM)
773  * - [client --> server] abort the 2nd stream
774  * - [server --> client] respond to 1st stream (EOM)
775  */
776 
777 TEST_F(HTTP2UpstreamSessionTest, ExheaderFromServer) {
779 
780  // generate enable_ex_headers setting
781  auto serverCodec = makeServerCodec();
782  enableExHeader(serverCodec.get());
783  serverCodec->generateSettings(queue);
784  // generate the response for control stream, but EOM
785  auto cStreamId = HTTPCodec::StreamID(1);
786  serverCodec->generateHeader(queue, cStreamId, getResponse(200, 0),
787  false, nullptr);
788  // generate a request from server, encapsulated in EX_HEADERS frame
789  serverCodec->generateExHeader(queue, 2, getGetRequest("/messaging"),
790  HTTPCodec::ExAttributes(cStreamId, false),
791  true, nullptr);
792  serverCodec->generateEOM(queue, 1);
793 
794  auto cHandler = openTransaction();
795  cHandler->sendRequest(getGetRequest("/cc"));
796 
797  NiceMock<MockHTTPHandler> pubHandler;
798  InSequence handlerSequence;
799  cHandler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
800  EXPECT_EQ(200, msg->getStatusCode());
801  });
802 
803  EXPECT_CALL(*cHandler, onExTransaction(_))
804  .WillOnce(Invoke([&pubHandler] (HTTPTransaction* pubTxn) {
805  pubTxn->setHandler(&pubHandler);
806  pubHandler.txn_ = pubTxn;
807  }));
808  pubHandler.expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
809  EXPECT_EQ(msg->getPath(), "/messaging");
810  });
811  pubHandler.expectEOM([&] () {
812  pubHandler.txn_->sendAbort();
813  });
814  pubHandler.expectDetachTransaction();
815 
816  cHandler->expectEOM();
817  cHandler->expectDetachTransaction();
818 
819  auto buf = queue.move();
820  buf->coalesce();
821  readAndLoop(buf.get());
822 
823  httpSession_->destroy();
824 }
825 
826 TEST_F(HTTP2UpstreamSessionTest, InvalidControlStream) {
828 
829  // generate enable_ex_headers setting
830  auto serverCodec = makeServerCodec();
831  enableExHeader(serverCodec.get());
832  serverCodec->generateSettings(queue);
833  // generate the response for control stream, but EOM
834  auto cStreamId = HTTPCodec::StreamID(1);
835  serverCodec->generateHeader(queue, cStreamId, getResponse(200, 0),
836  false, nullptr);
837  // generate a EX_HEADERS frame with non-existing control stream
838  serverCodec->generateExHeader(queue, 2, getGetRequest("/messaging"),
839  HTTPCodec::ExAttributes(cStreamId + 2, false),
840  true, nullptr);
841  serverCodec->generateEOM(queue, 1);
842 
843  auto cHandler = openTransaction();
844  cHandler->sendRequest(getGetRequest("/cc"));
845 
846  InSequence handlerSequence;
847  cHandler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
848  EXPECT_EQ(200, msg->getStatusCode());
849  });
850  EXPECT_CALL(*cHandler, onExTransaction(_)).Times(0);
851  cHandler->expectEOM();
852  cHandler->expectDetachTransaction();
853 
854  auto buf = queue.move();
855  buf->coalesce();
856  readAndLoop(buf.get());
857 
858  httpSession_->destroy();
859 }
860 
862  public HTTPUpstreamTest<MockHTTPCodecPair> {
863  public:
864  void SetUp() override {
865  auto codec = std::make_unique<NiceMock<MockHTTPCodec>>();
866  codecPtr_ = codec.get();
867  EXPECT_CALL(*codec, supportsParallelRequests())
868  .WillRepeatedly(Return(true));
869  EXPECT_CALL(*codec, getTransportDirection())
870  .WillRepeatedly(Return(TransportDirection::UPSTREAM));
871  EXPECT_CALL(*codec, getProtocol())
872  .WillRepeatedly(Return(CodecProtocol::HTTP_2));
873  EXPECT_CALL(*codec, setCallback(_))
874  .WillRepeatedly(SaveArg<0>(&codecCb_));
875  EXPECT_CALL(*codec, createStream())
876  .WillRepeatedly(Invoke([&] {
877  auto ret = nextOutgoingTxn_;
878  nextOutgoingTxn_ += 2;
879  return ret;
880  }));
881  commonSetUp(std::move(codec));
882  }
883 
884  void commonSetUp(unique_ptr<HTTPCodec> codec) {
885  HTTPSession::setDefaultReadBufferLimit(65536);
886  HTTPSession::setDefaultWriteBufferLimit(65536);
887  EXPECT_CALL(*transport_, writeChain(_, _, _))
888  .WillRepeatedly(Invoke(
889  this,
891  EXPECT_CALL(*transport_, setReadCB(_))
892  .WillRepeatedly(SaveArg<0>(&readCallback_));
893  EXPECT_CALL(*transport_, getReadCB())
894  .WillRepeatedly(Return(readCallback_));
896  .WillRepeatedly(Return(&eventBase_));
897  EXPECT_CALL(*transport_, good())
898  .WillRepeatedly(ReturnPointee(&transportGood_));
899  EXPECT_CALL(*transport_, closeNow())
900  .WillRepeatedly(Assign(&transportGood_, false));
902  httpSession_ = new HTTPUpstreamSession(
903  transactionTimeouts_.get(),
904  std::move(transportPtr),
905  localAddr_, peerAddr_,
906  std::move(codec),
907  mockTransportInfo_,
908  this,
909  level_,
910  builder_);
911  eventBase_.loop();
912  ASSERT_EQ(this->sessionDestroyed_, false);
913  }
914 
915  void TearDown() override {
916  EXPECT_TRUE(sessionDestroyed_);
917  }
918 
919  protected:
920  MockHTTPCodec* codecPtr_{nullptr};
921  HTTPCodec::Callback* codecCb_{nullptr};
922  uint32_t nextOutgoingTxn_{1};
923  std::vector<HTTPCodec::StreamID> dependencies;
924  uint8_t level_{3};
925  std::shared_ptr<TestPriorityMapBuilder> builder_;
926 };
927 
929  InSequence enforceOrder;
930 
931  HTTPCodec::StreamID deps[] = {11, 13, 15};
932  EXPECT_CALL(*codecPtr_, addPriorityNodes(_, _, _))
933  .Times(1)
934  .WillOnce(Invoke([&] (
937  uint8_t maxLevel) {
938  for (size_t i = 0; i < maxLevel; i++) {
939  dependencies.push_back(deps[i]);
940  }
941  return 123;
942  }));
943  httpSession_->startNow();
944 
945  EXPECT_EQ(level_, dependencies.size());
947  handler.expectTransaction();
948  auto txn = httpSession_->newTransaction(&handler);
949 
950  EXPECT_CALL(*codecPtr_, mapPriorityToDependency(_))
951  .Times(1)
952  .WillOnce(Invoke([&] (uint8_t priority) {
953  return dependencies[priority];
954  }));
955  txn->updateAndSendPriority(0);
956 
957  handler.expectError();
958  handler.expectDetachTransaction();
959  httpSession_->dropConnection();
960 
961  eventBase_.loop();
962 }
963 
966 public:
968  builder_ = std::make_shared<TestPriorityMapBuilder>();
969  }
970 };
971 
973  InSequence enforceOrder;
974 
975  std::array<HTTPCodec::StreamID, 3> deps = { {11, 13, 15} };
976  EXPECT_CALL(*codecPtr_, addPriorityNodes(_, _, _))
977  .Times(0)
978  .WillOnce(Invoke([&] (
981  uint8_t maxLevel) {
982  for (size_t i = 0; i < maxLevel; i++) {
983  dependencies.push_back(deps[i]);
984  }
985  return 123;
986  }));
987  httpSession_->startNow();
988 
989  // It should have built the virtual streams from the tree but not the old
990  // priority levels.
991  EXPECT_EQ(dependencies.size(), 0);
993  *httpSession_->getHTTPPriority(builder_->hiPriLevel_);
994  EXPECT_EQ(std::get<2>(hiPri), builder_->hiPriWeight_);
996  *httpSession_->getHTTPPriority(builder_->loPriLevel_);
997  EXPECT_EQ(std::get<2>(loPri), builder_->loPriWeight_);
998 
999  for (size_t level = 0; level < 256; ++level) {
1000  if (level == builder_->hiPriLevel_) {
1001  continue;
1002  }
1003  HTTPMessage::HTTPPriority pri = *httpSession_->getHTTPPriority(level);
1004  EXPECT_EQ(pri, loPri);
1005  }
1006 
1008  handler.expectTransaction();
1009  auto txn = httpSession_->newTransaction(&handler);
1010 
1011  txn->updateAndSendPriority(0);
1012 
1013  handler.expectError();
1014  handler.expectDetachTransaction();
1015  httpSession_->dropConnection();
1016 
1017  eventBase_.loop();
1018 }
1019 
1021  // Receive an EOF without any request data
1022  this->readCallback_->readEOF();
1023  this->eventBase_.loop();
1024  EXPECT_EQ(this->sessionDestroyed_, true);
1025 }
1026 
1027 template <class CodecPair>
1029  InSequence enforceOrder;
1030 
1031  auto handler = openTransaction();
1032  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1033  EXPECT_TRUE(msg->getIsChunked());
1034  EXPECT_FALSE(msg->getIsUpgraded());
1035  EXPECT_EQ(200, msg->getStatusCode());
1036  });
1037  handler->expectEOM();
1038  handler->expectDetachTransaction();
1039 
1040  handler->sendRequest();
1041  readAndLoop("HTTP/1.1 200 OK\r\n"
1042  "Transfer-Encoding: chunked\r\n\r\n"
1043  "0\r\n\r\n");
1044 
1045  CHECK(httpSession_->supportsMoreTransactions());
1046  CHECK_EQ(httpSession_->getNumOutgoingStreams(), 0);
1047 }
1048 
1050  testBasicRequest();
1051  httpSession_->destroy();
1052 }
1053 
1055  testBasicRequest();
1056  testBasicRequest();
1057  httpSession_->destroy();
1058 }
1059 
1061  for (uint16_t i = 0; i < 10; i++) {
1062  testBasicRequest();
1063  }
1064  httpSession_->destroy();
1065 }
1066 
1067 TEST_F(HTTPUpstreamSessionTest, TestFirstHeaderByteEventTracker) {
1068  auto byteEventTracker = setMockByteEventTracker();
1069 
1070  EXPECT_CALL(*byteEventTracker, addFirstHeaderByteEvent(_, _))
1071  .WillOnce(Invoke([] (uint64_t /*byteNo*/,
1072  HTTPTransaction* txn) {
1074  }));
1075 
1076  InSequence enforceOrder;
1077 
1078  auto handler = openTransaction();
1079  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1080  EXPECT_TRUE(msg->getIsChunked());
1081  EXPECT_FALSE(msg->getIsUpgraded());
1082  EXPECT_EQ(200, msg->getStatusCode());
1083  });
1084  handler->expectEOM();
1085  handler->expectDetachTransaction();
1086 
1087  handler->sendRequest();
1088  readAndLoop("HTTP/1.1 200 OK\r\n"
1089  "Transfer-Encoding: chunked\r\n\r\n"
1090  "0\r\n\r\n");
1091 
1092  CHECK(httpSession_->supportsMoreTransactions());
1093  CHECK_EQ(httpSession_->getNumOutgoingStreams(), 0);
1094  handler->txn_->decrementPendingByteEvents();
1095  httpSession_->destroy();
1096 }
1097 
1098 template <class CodecPair>
1100  HTTPMessage req = getGetRequest();
1101  req.setHTTPVersion(1, 0);
1102  if (keepalive) {
1103  req.getHeaders().set(HTTP_HEADER_CONNECTION, "Keep-Alive");
1104  }
1105 
1106  InSequence enforceOrder;
1107 
1108  auto handler = openTransaction();
1109  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1110  EXPECT_EQ(200, msg->getStatusCode());
1111  EXPECT_EQ(keepalive ? "keep-alive" : "close",
1112  msg->getHeaders().getSingleOrEmpty(HTTP_HEADER_CONNECTION));
1113  });
1114  EXPECT_CALL(*handler, onBody(_));
1115  handler->expectEOM();
1116  handler->expectDetachTransaction();
1117 
1118  handler->sendRequest();
1119  if (keepalive) {
1120  readAndLoop("HTTP/1.0 200 OK\r\n"
1121  "Connection: keep-alive\r\n"
1122  "Content-length: 7\r\n\r\n"
1123  "content");
1124  } else {
1125  readAndLoop("HTTP/1.0 200 OK\r\n"
1126  "Connection: close\r\n"
1127  "Content-length: 7\r\n\r\n"
1128  "content");
1129  }
1130 }
1131 
1132 TEST_F(HTTPUpstreamSessionTest, Http10Keepalive) {
1133  testBasicRequestHttp10(true);
1134  testBasicRequestHttp10(false);
1135 }
1136 
1138  InSequence enforceOrder;
1139 
1140  auto handler = openTransaction();
1141  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1142  EXPECT_TRUE(msg->getIsChunked());
1143  EXPECT_FALSE(msg->getIsUpgraded());
1144  EXPECT_EQ(200, msg->getStatusCode());
1145  });
1146  EXPECT_CALL(*handler, onTrailers(_));
1147  handler->expectEOM();
1148  handler->expectDetachTransaction();
1149 
1150  handler->sendRequest();
1151  readAndLoop("HTTP/1.1 200 OK\r\n"
1152  "Transfer-Encoding: chunked\r\n\r\n"
1153  "0\r\n"
1154  "X-Trailer1: foo\r\n"
1155  "\r\n");
1156 
1157  CHECK(httpSession_->supportsMoreTransactions());
1158  CHECK_EQ(httpSession_->getNumOutgoingStreams(), 0);
1159  httpSession_->destroy();
1160 }
1161 
1163  auto egressCodec = makeServerCodec();
1165 
1166  egressCodec->generateSettings(output);
1167 
1168  HTTPMessage resp;
1169  resp.setStatusCode(200);
1170  resp.getHeaders().set("header1", "value1");
1171  egressCodec->generateHeader(output, 1, resp);
1172  auto buf = makeBuf(100);
1173  egressCodec->generateBody(
1174  output, 1, std::move(buf), HTTPCodec::NoPadding, false /* eom */);
1175  HTTPHeaders trailers;
1176  trailers.set("trailer2", "value2");
1177  egressCodec->generateTrailers(output, 1, trailers);
1178 
1179  std::unique_ptr<folly::IOBuf> input = output.move();
1180  input->coalesce();
1181 
1182  auto handler = openTransaction();
1183 
1184  handler->expectHeaders([&](std::shared_ptr<HTTPMessage> msg) {
1185  EXPECT_EQ(200, msg->getStatusCode());
1186  EXPECT_EQ(msg->getHeaders().getSingleOrEmpty("header1"), "value1");
1187  });
1188  handler->expectBody();
1189  handler->expectTrailers([&](std::shared_ptr<HTTPHeaders> trailers) {
1190  EXPECT_EQ(trailers->getSingleOrEmpty("trailer2"), "value2");
1191  });
1192  handler->expectEOM();
1193  handler->expectDetachTransaction();
1194 
1195  handler->sendRequest();
1196  readAndLoop(input->data(), input->length());
1197 
1198  httpSession_->destroy();
1199 }
1200 
1201 TEST_F(HTTP2UpstreamSessionTest, HeadersThenBodyThenHeaders) {
1202  auto egressCodec = makeServerCodec();
1204 
1205  egressCodec->generateSettings(output);
1206 
1207  HTTPMessage resp;
1208  resp.setStatusCode(200);
1209  resp.getHeaders().set("header1", "value1");
1210  egressCodec->generateHeader(output, 1, resp);
1211  auto buf = makeBuf(100);
1212  egressCodec->generateBody(
1213  output, 1, std::move(buf), HTTPCodec::NoPadding, false /* eom */);
1214  // generate same headers again on the same stream
1215  egressCodec->generateHeader(output, 1, resp);
1216 
1217  std::unique_ptr<folly::IOBuf> input = output.move();
1218  input->coalesce();
1219 
1220  auto handler = openTransaction();
1221 
1222  handler->expectHeaders([&](std::shared_ptr<HTTPMessage> msg) {
1223  EXPECT_EQ(200, msg->getStatusCode());
1224  EXPECT_EQ(msg->getHeaders().getSingleOrEmpty("header1"), "value1");
1225  });
1226  handler->expectBody();
1227  handler->expectError([&](const HTTPException& err) {
1230  ASSERT_EQ(
1231  "Invalid ingress state transition, state=RegularBodyReceived, "
1232  "event=onHeaders, streamID=1",
1233  std::string(err.what()));
1234  });
1235  handler->expectDetachTransaction();
1236 
1237  handler->sendRequest();
1238  readAndLoop(input->data(), input->length());
1239 
1240  httpSession_->destroy();
1241 }
1242 
1243 TEST_F(HTTPUpstreamSessionTest, TwoRequestsWithPause) {
1244  InSequence enforceOrder;
1245 
1246  auto handler = openTransaction();
1247  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1248  EXPECT_TRUE(msg->getIsChunked());
1249  EXPECT_FALSE(msg->getIsUpgraded());
1250  EXPECT_EQ(200, msg->getStatusCode());
1251  });
1252 
1253  handler->expectEOM([&] () { handler->txn_->pauseIngress(); });
1254  handler->expectDetachTransaction();
1255 
1256  handler->sendRequest();
1257  readAndLoop("HTTP/1.1 200 OK\r\n"
1258  "Transfer-Encoding: chunked\r\n\r\n"
1259  "0\r\n\r\n");
1260 
1261  // Even though the previous transaction paused ingress just before it
1262  // finished up, reads resume automatically when the number of
1263  // transactions goes to zero. This way, the second request can read
1264  // without having to call resumeIngress()
1265  testBasicRequest();
1266  httpSession_->destroy();
1267 }
1268 
1270 TEST_F(HTTPUpstreamTimeoutTest, WriteTimeoutAfterResponse) {
1271  // Test where the upstream session times out while writing the request
1272  // to the server, but after the server has already sent back a full
1273  // response.
1274  pauseWrites_ = true;
1275  HTTPMessage req = getPostRequest();
1276 
1277  InSequence enforceOrder;
1278  auto handler = openTransaction();
1279  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1280  EXPECT_TRUE(msg->getIsChunked());
1281  EXPECT_FALSE(msg->getIsUpgraded());
1282  EXPECT_EQ(200, msg->getStatusCode());
1283  });
1284  handler->expectEOM();
1285  handler->expectError([&] (const HTTPException& err) {
1287  ASSERT_EQ(err.getDirection(),
1288  HTTPException::Direction::INGRESS_AND_EGRESS);
1290  ASSERT_EQ(
1291  folly::to<std::string>("WriteTimeout on transaction id: ",
1292  handler->txn_->getID()),
1293  std::string(err.what()));
1294  });
1295  handler->expectDetachTransaction();
1296 
1297  handler->txn_->sendHeaders(req);
1298  // Don't send the body, but get a response immediately
1299  readAndLoop("HTTP/1.1 200 OK\r\n"
1300  "Transfer-Encoding: chunked\r\n\r\n"
1301  "0\r\n\r\n");
1302 }
1303 
1304 TEST_F(HTTPUpstreamSessionTest, SetTransactionTimeout) {
1305  // Test that setting a new timeout on the transaction will cancel
1306  // the old one.
1307  auto handler = openTransaction();
1308  handler->expectDetachTransaction();
1309 
1310  EXPECT_TRUE(handler->txn_->hasIdleTimeout());
1311  handler->txn_->setIdleTimeout(std::chrono::milliseconds(747));
1312  EXPECT_TRUE(handler->txn_->hasIdleTimeout());
1313  EXPECT_TRUE(handler->txn_->isScheduled());
1314  EXPECT_EQ(transactionTimeouts_->count(), 1);
1315  handler->txn_->sendAbort();
1316  eventBase_.loop();
1317 }
1318 
1321  httpSession_->setController(&controller);
1323  &eventBase_, std::chrono::milliseconds(50));
1324  cm->addConnection(httpSession_, true);
1325  eventBase_.loop();
1326 }
1327 
1328 TEST_F(HTTPUpstreamSessionTest, 100ContinueKeepalive) {
1329  // Test a request with 100 continue on a keepalive connection. Then make
1330  // another request.
1331  HTTPMessage req = getGetRequest();
1332  req.getHeaders().set(HTTP_HEADER_EXPECT, "100-continue");
1333 
1334  InSequence enforceOrder;
1335 
1336  auto handler = openTransaction();
1337  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1338  EXPECT_FALSE(msg->getIsChunked());
1339  EXPECT_FALSE(msg->getIsUpgraded());
1340  EXPECT_EQ(100, msg->getStatusCode());
1341  });
1342  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1343  EXPECT_TRUE(msg->getIsChunked());
1344  EXPECT_FALSE(msg->getIsUpgraded());
1345  EXPECT_EQ(200, msg->getStatusCode());
1346  });
1347  handler->expectEOM();
1348  handler->expectDetachTransaction();
1349 
1350  handler->sendRequest(req);
1351  readAndLoop("HTTP/1.1 100 Continue\r\n\r\n"
1352  "HTTP/1.1 200 OK\r\n"
1353  "Transfer-Encoding: chunked\r\n\r\n"
1354  "0\r\n\r\n");
1355 
1356  // Now make sure everything still works
1357  testBasicRequest();
1358  httpSession_->destroy();
1359 }
1360 
1362  // Test a request with 100 continue on a keepalive connection. Then make
1363  // another request after the expectation fails.
1364  HTTPMessage req = getGetRequest();
1365  req.getHeaders().set(HTTP_HEADER_EXPECT, "100-continue");
1366 
1367  InSequence enforceOrder;
1368 
1369  auto handler = openTransaction();
1370  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1371  EXPECT_FALSE(msg->getIsChunked());
1372  EXPECT_FALSE(msg->getIsUpgraded());
1373  EXPECT_EQ(417, msg->getStatusCode());
1374  });
1375  handler->expectEOM();
1376  handler->expectDetachTransaction();
1377 
1378  handler->sendRequest(req);
1379  readAndLoop("HTTP/1.1 417 Expectation Failed\r\n"
1380  "Content-Length: 0\r\n\r\n");
1381 
1382  // Now make sure everything still works
1383  testBasicRequest();
1384  EXPECT_FALSE(sessionDestroyed_);
1385  httpSession_->destroy();
1386 }
1387 
1389  // Test an upgrade request with sending 101 response. Then send
1390  // some data and check the onBody callback contents
1391  HTTPMessage req = getGetRequest();
1392  req.getHeaders().set(HTTP_HEADER_UPGRADE, "http/2.0");
1393 
1394  InSequence enforceOrder;
1395 
1396  auto handler = openTransaction();
1397  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1398  EXPECT_FALSE(msg->getIsChunked());
1399  EXPECT_EQ(101, msg->getStatusCode());
1400  });
1401  EXPECT_CALL(*handler, onUpgrade(_));
1402  EXPECT_CALL(*handler, onBody(_))
1403  .WillOnce(ExpectString("Test Body\r\n"));
1404  handler->expectEOM();
1405  handler->expectDetachTransaction();
1406 
1407  handler->sendRequest(req);
1408  eventBase_.loop();
1409  readAndLoop("HTTP/1.1 101 Switching Protocols\r\n"
1410  "Upgrade: http/2.0\r\n\r\n"
1411  "Test Body\r\n");
1412  readCallback_->readEOF();
1413  eventBase_.loop();
1414 
1415  CHECK_EQ(httpSession_->getNumOutgoingStreams(), 0);
1416  httpSession_->destroy();
1417 }
1418 
1419 // ===== Upgrade Tests ====
1420 
1421 template <class CodecPair>
1423  const std::string& upgradeReqHeader,
1424  const std::string& upgradeRespHeader,
1425  CodecProtocol respCodecVersion) {
1426  InSequence dummy;
1427  auto handler = openTransaction();
1429 
1430  httpSession_->setController(&controller);
1431  EXPECT_CALL(controller, onSessionCodecChange(httpSession_));
1432 
1433  EXPECT_EQ(httpSession_->getMaxConcurrentOutgoingStreams(), 1);
1434 
1435  HeaderIndexingStrategy testH2IndexingStrat;
1436  if (respCodecVersion == CodecProtocol::HTTP_2) {
1437  EXPECT_CALL(controller, getHeaderIndexingStrategy())
1438  .WillOnce(
1439  Return(&testH2IndexingStrat)
1440  );
1441  }
1442 
1443  handler->expectHeaders([] (std::shared_ptr<HTTPMessage> msg) {
1444  EXPECT_EQ(200, msg->getStatusCode());
1445  });
1446  handler->expectBody();
1447  handler->expectEOM();
1448  handler->expectDetachTransaction();
1449 
1450  auto txn = handler->txn_;
1451  HTTPMessage req = getUpgradeRequest(upgradeReqHeader);
1452  txn->sendHeaders(req);
1453  txn->sendEOM();
1454  eventBase_.loopOnce(); // force HTTP/1.1 writes
1455  writes_.move(); // clear them out
1456  readAndLoop(folly::to<string>("HTTP/1.1 101 Switching Protocols\r\n"
1457  "Upgrade: ", upgradeRespHeader, "\r\n"
1458  "\r\n"));
1459 
1460  if (respCodecVersion == CodecProtocol::HTTP_2) {
1461  const HTTP2Codec* codec = dynamic_cast<const HTTP2Codec*>(
1462  &txn->getTransport().getCodec());
1463  ASSERT_NE(codec, nullptr);
1464  EXPECT_EQ(codec->getHeaderIndexingStrategy(), &testH2IndexingStrat);
1465  }
1466 
1467  readAndLoop(getResponseBuf(respCodecVersion, txn->getID(), 200, 100).get());
1468 
1469  EXPECT_EQ(httpSession_->getMaxConcurrentOutgoingStreams(), 10);
1470  httpSession_->destroy();
1471 }
1472 
1473 TEST_F(HTTPUpstreamSessionTest, HttpUpgradeNativeH2) {
1474  testSimpleUpgrade("h2c", "h2c", CodecProtocol::HTTP_2);
1475 }
1476 
1477 // Upgrade to SPDY/3.1 with a non-native proto in the list
1478 TEST_F(HTTPUpstreamSessionTest, HttpUpgradeNativeUnknown) {
1479  testSimpleUpgrade("blarf, h2c", "h2c", CodecProtocol::HTTP_2);
1480 }
1481 
1482 // Upgrade header with extra whitespace
1483 TEST_F(HTTPUpstreamSessionTest, HttpUpgradeNativeWhitespace) {
1484  testSimpleUpgrade("blarf, \th2c\t, xyz", "h2c",
1485  CodecProtocol::HTTP_2);
1486 }
1487 
1488 // Upgrade header with random junk
1489 TEST_F(HTTPUpstreamSessionTest, HttpUpgradeNativeJunk) {
1490  testSimpleUpgrade(",,,, ,,\t~^%$(*&@(@$^^*(,h2c", "h2c",
1491  CodecProtocol::HTTP_2);
1492 }
1493 
1494 TEST_F(HTTPUpstreamSessionTest, HttpUpgrade101Unexpected) {
1495  InSequence dummy;
1496  auto handler = openTransaction();
1497 
1498  EXPECT_CALL(*handler, onError(_));
1499  handler->expectDetachTransaction();
1500 
1501  handler->sendRequest();
1502  eventBase_.loop();
1503  readAndLoop(folly::to<string>("HTTP/1.1 101 Switching Protocols\r\n"
1504  "Upgrade: spdy/3\r\n"
1505  "\r\n"));
1506  EXPECT_EQ(readCallback_, nullptr);
1507  EXPECT_TRUE(sessionDestroyed_);
1508 }
1509 
1510 TEST_F(HTTPUpstreamSessionTest, HttpUpgrade101MissingUpgrade) {
1511  InSequence dummy;
1512  auto handler = openTransaction();
1513 
1514  EXPECT_CALL(*handler, onError(_));
1515  handler->expectDetachTransaction();
1516 
1517  handler->sendRequest(getUpgradeRequest("spdy/3"));
1518  readAndLoop(folly::to<string>("HTTP/1.1 101 Switching Protocols\r\n"
1519  "\r\n"));
1520  EXPECT_EQ(readCallback_, nullptr);
1521  EXPECT_TRUE(sessionDestroyed_);
1522 }
1523 
1524 TEST_F(HTTPUpstreamSessionTest, HttpUpgrade101BogusHeader) {
1525  InSequence dummy;
1526  auto handler = openTransaction();
1527 
1528  EXPECT_CALL(*handler, onError(_));
1529  handler->expectDetachTransaction();
1530 
1531  handler->sendRequest(getUpgradeRequest("spdy/3"));
1532  eventBase_.loop();
1533  readAndLoop(folly::to<string>("HTTP/1.1 101 Switching Protocols\r\n"
1534  "Upgrade: blarf\r\n"
1535  "\r\n"));
1536  EXPECT_EQ(readCallback_, nullptr);
1537  EXPECT_TRUE(sessionDestroyed_);
1538 }
1539 
1540 TEST_F(HTTPUpstreamSessionTest, HttpUpgradePost100) {
1541  InSequence dummy;
1542  auto handler = openTransaction();
1543 
1544  handler->expectHeaders([] (std::shared_ptr<HTTPMessage> msg) {
1545  EXPECT_EQ(100, msg->getStatusCode());
1546  });
1547  handler->expectHeaders([] (std::shared_ptr<HTTPMessage> msg) {
1548  EXPECT_EQ(200, msg->getStatusCode());
1549  });
1550  handler->expectBody();
1551  handler->expectEOM();
1552  handler->expectDetachTransaction();
1553 
1554  auto txn = handler->txn_;
1555  HTTPMessage req = getUpgradePostRequest(100, "h2c", true /* 100 */);
1556  txn->sendHeaders(req);
1557  auto buf = makeBuf(100);
1558  txn->sendBody(std::move(buf));
1559  txn->sendEOM();
1560  eventBase_.loop();
1561  readAndLoop(folly::to<string>("HTTP/1.1 100 Continue\r\n"
1562  "\r\n"
1563  "HTTP/1.1 101 Switching Protocols\r\n"
1564  "Upgrade: h2c\r\n"
1565  "\r\n"));
1566  readAndLoop(
1567  getResponseBuf(CodecProtocol::HTTP_2, txn->getID(), 200, 100).get());
1568  httpSession_->destroy();
1569 }
1570 
1571 TEST_F(HTTPUpstreamSessionTest, HttpUpgradePost100Http2) {
1572  InSequence dummy;
1573  auto handler = openTransaction();
1574 
1575  handler->expectHeaders([] (std::shared_ptr<HTTPMessage> msg) {
1576  EXPECT_EQ(100, msg->getStatusCode());
1577  });
1578  handler->expectHeaders([] (std::shared_ptr<HTTPMessage> msg) {
1579  EXPECT_EQ(200, msg->getStatusCode());
1580  });
1581  handler->expectBody();
1582  handler->expectEOM();
1583  handler->expectDetachTransaction();
1584 
1585  auto txn = handler->txn_;
1586  HTTPMessage req = getUpgradePostRequest(100, "h2c");
1587  txn->sendHeaders(req);
1588  auto buf = makeBuf(100);
1589  txn->sendBody(std::move(buf));
1590  txn->sendEOM();
1591  eventBase_.loop();
1592  readAndLoop(folly::to<string>("HTTP/1.1 101 Switching Protocols\r\n"
1593  "Upgrade: h2c\r\n"
1594  "\r\n"));
1595  readAndLoop(getResponseBuf(CodecProtocol::HTTP_2,
1596  txn->getID(), 200, 100, true).get());
1597  httpSession_->destroy();
1598 }
1599 
1600 TEST_F(HTTPUpstreamSessionTest, HttpUpgradeOnTxn2) {
1601  InSequence dummy;
1602  auto handler1 = openTransaction();
1603 
1604  handler1->expectHeaders([] (std::shared_ptr<HTTPMessage> msg) {
1605  EXPECT_EQ(200, msg->getStatusCode());
1606  });
1607  handler1->expectBody();
1608  handler1->expectEOM();
1609  handler1->expectDetachTransaction();
1610 
1611  auto txn = handler1->txn_;
1612  HTTPMessage req = getUpgradeRequest("spdy/3");
1613  txn->sendHeaders(req);
1614  txn->sendEOM();
1615  readAndLoop("HTTP/1.1 200 Ok\r\n"
1616  "Content-Length: 10\r\n"
1617  "\r\n"
1618  "abcdefghij");
1619  eventBase_.loop();
1620 
1621  auto handler2 = openTransaction();
1622 
1623  txn = handler2->txn_;
1624  txn->sendHeaders(req);
1625  txn->sendEOM();
1626 
1627  handler2->expectHeaders();
1628  handler2->expectEOM();
1629  handler2->expectDetachTransaction();
1630  readAndLoop("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1631  httpSession_->destroy();
1632 }
1633 
1634 
1636  public:
1638  : HTTPUpstreamTest({100000, 105000, 110000}) {}
1639 };
1640 
1641 TEST_F(HTTPUpstreamRecvStreamTest, UpgradeFlowControl) {
1642  InSequence dummy;
1643  testSimpleUpgrade("h2c", "h2c", CodecProtocol::HTTP_2);
1644 
1645  HTTP2Codec serverCodec(TransportDirection::DOWNSTREAM);
1647  serverCodec.setCallback(&callbacks);
1648  EXPECT_CALL(callbacks, onSettings(_))
1649  .WillOnce(Invoke([this] (const SettingsList& settings) {
1650  if (flowControl_[0] > 0) {
1651  for (const auto& setting: settings) {
1652  if (setting.id == SettingsId::INITIAL_WINDOW_SIZE) {
1653  EXPECT_EQ(flowControl_[0], setting.value);
1654  }
1655  }
1656  }
1657  }));
1658  EXPECT_CALL(callbacks, onWindowUpdate(0, flowControl_[2] -
1659  serverCodec.getDefaultWindowSize()));
1660  size_t initWindow = flowControl_[0] > 0 ?
1661  flowControl_[0] : serverCodec.getDefaultWindowSize();
1662  EXPECT_CALL(callbacks, onWindowUpdate(1, flowControl_[1] - initWindow));
1663  parseOutput(serverCodec);
1664 }
1665 
1666 class NoFlushUpstreamSessionTest: public HTTPUpstreamTest<SPDY3CodecPair> {
1667  public:
1669  std::shared_ptr<IOBuf>,
1670  WriteFlags) override {
1671  if (!timesCalled_++) {
1672  callback->writeSuccess();
1673  } else {
1674  cbs_.push_back(callback);
1675  }
1676  // do nothing -- let unacked egress build up
1677  }
1678 
1681  for (auto& cb : cbs_) {
1682  cb->writeErr(0, ex);
1683  }
1684  }
1685  private:
1686  uint32_t timesCalled_{0};
1687  std::vector<folly::AsyncTransportWrapper::WriteCallback*> cbs_;
1688 };
1689 
1690 TEST_F(NoFlushUpstreamSessionTest, SessionPausedStartPaused) {
1691  // If the session is paused, new upstream transactions should start
1692  // paused too.
1693  HTTPMessage req = getGetRequest();
1694 
1695  InSequence enforceOrder;
1696 
1697  auto handler1 = openNiceTransaction();
1698  handler1->txn_->sendHeaders(req);
1699  Mock::VerifyAndClearExpectations(handler1.get());
1700  // The session pauses all txns since no writeSuccess for too many bytes
1701  handler1->expectEgressPaused();
1702  // Send a body big enough to pause egress
1703  handler1->txn_->sendBody(makeBuf(httpSession_->getWriteBufferLimit()));
1704  eventBase_.loop();
1705  Mock::VerifyAndClearExpectations(handler1.get());
1706 
1707  auto handler2 = openNiceTransaction(true /* expect start paused */);
1708  eventBase_.loop();
1709  Mock::VerifyAndClearExpectations(handler2.get());
1710 
1711  httpSession_->dropConnection();
1712 }
1713 
1714 TEST_F(NoFlushUpstreamSessionTest, DeleteTxnOnUnpause) {
1715  // Test where the handler gets onEgressPaused() and triggers another
1716  // HTTPSession call to iterate over all transactions (to ensure nested
1717  // iteration works).
1718 
1719  HTTPMessage req = getGetRequest();
1720 
1721  InSequence enforceOrder;
1722 
1723  auto handler1 = openNiceTransaction();
1724  auto handler2 = openNiceTransaction();
1725  auto handler3 = openNiceTransaction();
1726  handler2->expectEgressPaused([this] {
1727  // This time it is invoked by the session on all transactions
1728  httpSession_->dropConnection();
1729  });
1730  handler2->txn_->sendHeaders(req);
1731  // This happens when the body write fills the txn egress queue
1732  // Send a body big enough to pause egress
1733  handler2->txn_->onIngressWindowUpdate(100);
1734  handler2->txn_->sendBody(makeBuf(httpSession_->getWriteBufferLimit() + 1));
1735  eventBase_.loop();
1736 }
1737 
1738 class MockHTTPUpstreamTest: public HTTPUpstreamTest<MockHTTPCodecPair> {
1739  public:
1740  void SetUp() override {
1741  auto codec = std::make_unique<NiceMock<MockHTTPCodec>>();
1742  codecPtr_ = codec.get();
1743  EXPECT_CALL(*codec, supportsParallelRequests())
1744  .WillRepeatedly(Return(true));
1745  EXPECT_CALL(*codec, getTransportDirection())
1746  .WillRepeatedly(Return(TransportDirection::UPSTREAM));
1747  EXPECT_CALL(*codec, setCallback(_))
1748  .WillRepeatedly(SaveArg<0>(&codecCb_));
1749  EXPECT_CALL(*codec, isReusable())
1750  .WillRepeatedly(ReturnPointee(&reusable_));
1751  EXPECT_CALL(*codec, isWaitingToDrain())
1752  .WillRepeatedly(ReturnPointee(&reusable_));
1753  EXPECT_CALL(*codec, getDefaultWindowSize())
1754  .WillRepeatedly(Return(65536));
1755  EXPECT_CALL(*codec, getProtocol())
1756  .WillRepeatedly(Return(CodecProtocol::SPDY_3_1));
1757  EXPECT_CALL(*codec, generateGoaway(_, _, _, _))
1758  .WillRepeatedly(Invoke([&] (IOBufQueue& writeBuf,
1759  HTTPCodec::StreamID lastStream,
1760  ErrorCode,
1761  std::shared_ptr<folly::IOBuf>) {
1763  if (reusable_) {
1764  writeBuf.append("GOAWAY", 6);
1765  reusable_ = false;
1766  }
1767  return 6;
1768  }));
1769  EXPECT_CALL(*codec, createStream())
1770  .WillRepeatedly(Invoke([&] {
1771  auto ret = nextOutgoingTxn_;
1772  nextOutgoingTxn_ += 2;
1773  return ret;
1774  }));
1775 
1776  commonSetUp(std::move(codec));
1777  }
1778 
1779  void TearDown() override {
1780  EXPECT_TRUE(sessionDestroyed_);
1781  }
1782 
1783  std::unique_ptr<StrictMock<MockHTTPHandler>> openTransaction() {
1784  // Returns a mock handler with txn_ field set in it
1785  auto handler = std::make_unique<StrictMock<MockHTTPHandler>>();
1786  handler->expectTransaction();
1787  auto txn = httpSession_->newTransaction(handler.get());
1788  EXPECT_EQ(txn, handler->txn_);
1789  return handler;
1790  }
1791 
1792  MockHTTPCodec* codecPtr_{nullptr};
1793  HTTPCodec::Callback* codecCb_{nullptr};
1794  bool reusable_{true};
1795  uint32_t nextOutgoingTxn_{1};
1796 };
1797 
1799  httpSession_->setEgressSettings({{SettingsId::ENABLE_PUSH, 1}});
1800 
1801  auto egressCodec = makeServerCodec();
1803 
1804  HTTPMessage push;
1805  push.getHeaders().set("HOST", "www.foo.com");
1806  push.setURL("https://www.foo.com/");
1807  egressCodec->generateSettings(output);
1808  // PUSH_PROMISE
1809  egressCodec->generatePushPromise(output, 2, push, 1);
1810 
1811  // Pushed resource
1812  HTTPMessage resp;
1813  resp.setStatusCode(200);
1814  resp.getHeaders().set("ohai", "push");
1815  egressCodec->generateHeader(output, 2, resp);
1816  auto buf = makeBuf(100);
1817  egressCodec->generateBody(output, 2, std::move(buf), HTTPCodec::NoPadding,
1818  true /* eom */);
1819 
1820  // Original resource
1821  resp.getHeaders().set("ohai", "orig");
1822  egressCodec->generateHeader(output, 1, resp);
1823  buf = makeBuf(100);
1824  egressCodec->generateBody(output, 1, std::move(buf), HTTPCodec::NoPadding,
1825  true /* eom */);
1826 
1827  std::unique_ptr<folly::IOBuf> input = output.move();
1828  input->coalesce();
1829 
1830  MockHTTPHandler pushHandler;
1831 
1832  InSequence enforceOrder;
1833 
1834  auto handler = openTransaction();
1835  EXPECT_CALL(*handler, onPushedTransaction(_))
1836  .WillOnce(Invoke([&pushHandler] (HTTPTransaction* pushTxn) {
1837  pushTxn->setHandler(&pushHandler);
1838  }));
1839  EXPECT_CALL(pushHandler, setTransaction(_));
1840  pushHandler.expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1841  EXPECT_EQ(httpSession_->getNumIncomingStreams(), 1);
1842  EXPECT_TRUE(msg->getIsChunked());
1843  EXPECT_FALSE(msg->getIsUpgraded());
1844  EXPECT_EQ(msg->getPath(), "/");
1845  EXPECT_EQ(msg->getHeaders().getSingleOrEmpty(HTTP_HEADER_HOST),
1846  "www.foo.com");
1847  });
1848  pushHandler.expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1849  EXPECT_EQ(msg->getStatusCode(), 200);
1850  EXPECT_EQ(msg->getHeaders().getSingleOrEmpty("ohai"), "push");
1851  });
1852  pushHandler.expectBody();
1853  pushHandler.expectEOM();
1854  pushHandler.expectDetachTransaction();
1855 
1856  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1857  EXPECT_FALSE(msg->getIsUpgraded());
1858  EXPECT_EQ(200, msg->getStatusCode());
1859  EXPECT_EQ(msg->getHeaders().getSingleOrEmpty("ohai"), "orig");
1860  });
1861  handler->expectBody();
1862  handler->expectEOM();
1863  handler->expectDetachTransaction();
1864 
1865  handler->sendRequest();
1866  readAndLoop(input->data(), input->length());
1867 
1868  EXPECT_EQ(httpSession_->getNumIncomingStreams(), 0);
1869  httpSession_->destroy();
1870 }
1871 
1873  public:
1874  void SetUp() override {
1876 
1877  // This class assumes we are doing a test for SPDY or HTTP/2+ where
1878  // this function is *not* a no-op. Indicate this via a positive number
1879  // of bytes being generated for writing RST_STREAM.
1880 
1881  ON_CALL(*codecPtr_, generateRstStream(_, _, _))
1882  .WillByDefault(Return(1));
1883  }
1884 };
1885 
1886 
1887 TEST_F(MockHTTP2UpstreamTest, ParseErrorNoTxn) {
1888  // 1) Create streamID == 1
1889  // 2) Send request
1890  // 3) Detach handler
1891  // 4) Get an ingress parse error on reply
1892  // Expect that the codec should be asked to generate an abort on streamID==1
1893 
1894  // Setup the codec expectations.
1895  EXPECT_CALL(*codecPtr_, generateHeader(_, _, _, _, _))
1897  const HTTPMessage&, bool, HTTPHeaderSize*) {
1898  writeBuf.append("1", 1);
1899  }));
1900  EXPECT_CALL(*codecPtr_, generateEOM(_, _))
1901  .WillOnce(Return(20));
1902  EXPECT_CALL(*codecPtr_, generateRstStream(_, 1, _));
1903 
1904  // 1)
1905  auto handler = openTransaction();
1906 
1907  // 2)
1908  handler->sendRequest(getPostRequest());
1909 
1910  // 3) Note this sendAbort() doesn't destroy the txn since byte events are
1911  // enqueued
1912  handler->txn_->sendAbort();
1913 
1914  // 4)
1915  HTTPException ex(HTTPException::Direction::INGRESS_AND_EGRESS, "foo");
1917  ex.setCodecStatusCode(ErrorCode::REFUSED_STREAM);
1918  codecCb_->onError(1, ex, true);
1919 
1920  // cleanup
1921  handler->expectDetachTransaction();
1922  httpSession_->dropConnection();
1923  eventBase_.loop();
1924 }
1925 
1926 TEST_F(MockHTTPUpstreamTest, 0MaxOutgoingTxns) {
1927  // Test where an upstream session gets a SETTINGS frame with 0 max
1928  // outgoing transactions. In our implementation, we jsut send a GOAWAY
1929  // and close the connection.
1930 
1931  codecCb_->onSettings({{SettingsId::MAX_CONCURRENT_STREAMS, 0}});
1932  EXPECT_TRUE(transactionsFull_);
1933  httpSession_->dropConnection();
1934 }
1935 
1936 TEST_F(MockHTTPUpstreamTest, OutgoingTxnSettings) {
1937  // Create 2 transactions, then receive a settings frame from
1938  // the server indicating 1 parallel transaction at a time is allowed.
1939  // Then get another SETTINGS frame indicating 100 max parallel
1940  // transactions. Expect that HTTPSession invokes both info callbacks.
1941 
1942  NiceMock<MockHTTPHandler> handler1;
1943  NiceMock<MockHTTPHandler> handler2;
1944  httpSession_->newTransaction(&handler1);
1945  httpSession_->newTransaction(&handler2);
1946 
1947  codecCb_->onSettings({{SettingsId::MAX_CONCURRENT_STREAMS, 1}});
1948  EXPECT_TRUE(transactionsFull_);
1949  codecCb_->onSettings({{SettingsId::MAX_CONCURRENT_STREAMS, 100}});
1950  EXPECT_FALSE(transactionsFull_);
1951  httpSession_->dropConnection();
1952 }
1953 
1954 TEST_F(MockHTTPUpstreamTest, IngressGoawayDrain) {
1955  // Tests whether the session drains existing transactions and
1956  // deletes itself after receiving a GOAWAY.
1957 
1958  InSequence enforceOrder;
1959 
1960  auto handler = openTransaction();
1961  EXPECT_CALL(*handler, onGoaway(ErrorCode::NO_ERROR));
1962  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
1963  EXPECT_FALSE(msg->getIsUpgraded());
1964  EXPECT_EQ(200, msg->getStatusCode());
1965  });
1966  handler->expectEOM();
1967  handler->expectDetachTransaction();
1968 
1969  // Send the GET request
1970  handler->sendRequest();
1971 
1972  // Receive GOAWAY frame with last good stream as 1
1973  codecCb_->onGoaway(1, ErrorCode::NO_ERROR);
1974 
1975  // New transactions cannot be created afrer goaway
1976  EXPECT_FALSE(httpSession_->isReusable());
1977  EXPECT_EQ(httpSession_->newTransaction(handler.get()), nullptr);
1978 
1979  // Receive 200 OK
1980  auto resp = makeResponse(200);
1981  codecCb_->onMessageBegin(1, resp.get());
1982  codecCb_->onHeadersComplete(1, std::move(resp));
1983  codecCb_->onMessageComplete(1, false);
1984  eventBase_.loop();
1985 
1986  // Session will delete itself after getting the response
1987 }
1988 
1990  // Make sure existing txns complete successfully even if we drain the
1991  // upstream session
1992  const unsigned numTxns = 10;
1993  MockHTTPHandler handler[numTxns];
1994 
1995  InSequence enforceOrder;
1996 
1997  for (unsigned i = 0; i < numTxns; ++i) {
1998  handler[i].expectTransaction();
1999  handler[i].expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
2000  EXPECT_FALSE(msg->getIsUpgraded());
2001  EXPECT_EQ(200, msg->getStatusCode());
2002  });
2003  httpSession_->newTransaction(&handler[i]);
2004 
2005  // Send the GET request
2006  handler[i].sendRequest();
2007 
2008  // Receive 200 OK
2009  auto resp = makeResponse(200);
2010  codecCb_->onMessageBegin(handler[i].txn_->getID(), resp.get());
2011  codecCb_->onHeadersComplete(handler[i].txn_->getID(), std::move(resp));
2012  }
2013 
2014  codecCb_->onGoaway(numTxns * 2 + 1, ErrorCode::NO_ERROR);
2015  for (unsigned i = 0; i < numTxns; ++i) {
2016  handler[i].expectEOM();
2017  handler[i].expectDetachTransaction();
2018  codecCb_->onMessageComplete(i*2 + 1, false);
2019  }
2020  eventBase_.loop();
2021 
2022  // Session will delete itself after drain completes
2023 }
2024 
2025 TEST_F(MockHTTPUpstreamTest, GoawayPreHeaders) {
2026  // Make sure existing txns complete successfully even if we drain the
2027  // upstream session
2029 
2030  InSequence enforceOrder;
2031 
2032  handler.expectTransaction();
2033  EXPECT_CALL(*codecPtr_, generateHeader(_, _, _, _, _))
2034  .WillOnce(Invoke(
2035  [&](IOBufQueue& writeBuf,
2036  HTTPCodec::StreamID /*stream*/,
2037  const HTTPMessage& /*msg*/,
2038  bool /*eom*/,
2039  HTTPHeaderSize* /*size*/) { writeBuf.append("HEADERS", 7); }));
2040  handler.expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
2041  EXPECT_FALSE(msg->getIsUpgraded());
2042  EXPECT_EQ(200, msg->getStatusCode());
2043  });
2044  httpSession_->newTransaction(&handler);
2045  httpSession_->drain();
2046 
2047  // Send the GET request
2048  handler.sendRequest();
2049 
2050  // Receive 200 OK
2051  auto resp = makeResponse(200);
2052  codecCb_->onMessageBegin(handler.txn_->getID(), resp.get());
2053  codecCb_->onHeadersComplete(handler.txn_->getID(), std::move(resp));
2054 
2055  codecCb_->onGoaway(1, ErrorCode::NO_ERROR);
2056  handler.expectEOM();
2057  handler.expectDetachTransaction();
2058  codecCb_->onMessageComplete(1, false);
2059  eventBase_.loop();
2060 
2061  auto buf = writes_.move();
2062  ASSERT_TRUE(buf != nullptr);
2063  EXPECT_EQ(buf->moveToFbString().data(), string("HEADERSGOAWAY"));
2064  // Session will delete itself after drain completes
2065 }
2066 
2067 TEST_F(MockHTTPUpstreamTest, NoWindowUpdateOnDrain) {
2068  EXPECT_CALL(*codecPtr_, supportsStreamFlowControl())
2069  .WillRepeatedly(Return(true));
2070 
2071  auto handler = openTransaction();
2072 
2073  handler->sendRequest();
2074  httpSession_->drain();
2075  auto streamID = handler->txn_->getID();
2076 
2077  EXPECT_CALL(*handler, onGoaway(ErrorCode::NO_ERROR));
2078  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
2079  EXPECT_FALSE(msg->getIsUpgraded());
2080  EXPECT_EQ(200, msg->getStatusCode());
2081  });
2082  EXPECT_CALL(*handler, onBody(_))
2083  .Times(3);
2084  handler->expectEOM();
2085 
2086  handler->expectDetachTransaction();
2087 
2088  uint32_t outstanding = 0;
2089  uint32_t sendWindow = 65536;
2090  uint32_t toSend = sendWindow * 1.55;
2091 
2092  // We'll get exactly one window update because we are draining
2093  EXPECT_CALL(*codecPtr_, generateWindowUpdate(_, _, _))
2094  .WillOnce(Invoke([&](folly::IOBufQueue& writeBuf,
2095  HTTPCodec::StreamID /*stream*/,
2096  uint32_t delta) {
2097  EXPECT_EQ(delta, sendWindow);
2098  outstanding -= delta;
2099  uint32_t len = std::min(toSend, sendWindow - outstanding);
2100  EXPECT_LT(len, sendWindow);
2101  toSend -= len;
2102  EXPECT_EQ(toSend, 0);
2103  eventBase_.tryRunAfterDelay(
2104  [this, streamID, len] {
2105  failWrites_ = true;
2106  auto respBody = makeBuf(len);
2107  codecCb_->onBody(streamID, std::move(respBody), 0);
2108  codecCb_->onMessageComplete(streamID, false);
2109  },
2110  50);
2111 
2112  const std::string dummy("window");
2113  writeBuf.append(dummy);
2114  return 6;
2115  }));
2116 
2117  codecCb_->onGoaway(streamID, ErrorCode::NO_ERROR);
2118  auto resp = makeResponse(200);
2119  codecCb_->onMessageBegin(streamID, resp.get());
2120  codecCb_->onHeadersComplete(streamID, std::move(resp));
2121 
2122  // While there is room and the window and body to send
2123  while (sendWindow - outstanding > 0 && toSend > 0) {
2124  // Send up to a 36k chunk
2125  uint32_t len = std::min(toSend, uint32_t(36000));
2126  // limited by the available window
2127  len = std::min(len, sendWindow - outstanding);
2128  auto respBody = makeBuf(len);
2129  toSend -= len;
2130  outstanding += len;
2131  codecCb_->onBody(streamID, std::move(respBody), 0);
2132  }
2133 
2134  eventBase_.loop();
2135 }
2136 
2138  // Should be allowed to send a GET request with body.
2140  HTTPMessage req = getGetRequest();
2142 
2143  InSequence enforceOrder;
2144 
2145  EXPECT_CALL(*codecPtr_, generateHeader(_, _, _, _, _));
2146  EXPECT_CALL(*codecPtr_, generateBody(_, _, _, _, true));
2147 
2148  auto txn = httpSession_->newTransaction(&handler);
2149  txn->sendHeaders(req);
2150  txn->sendBody(makeBuf(10));
2151  txn->sendEOM();
2152 
2153  eventBase_.loop();
2154  httpSession_->dropConnection();
2155 }
2156 
2157 TEST_F(MockHTTPUpstreamTest, HeaderWithEom) {
2159  HTTPMessage req = getGetRequest();
2160  EXPECT_CALL(*codecPtr_, generateHeader(_, _, _, true, _));
2161 
2162  auto txn = httpSession_->newTransaction(&handler);
2163  txn->sendHeadersWithEOM(req);
2164  eventBase_.loop();
2165  EXPECT_TRUE(txn->isEgressComplete());
2166  httpSession_->dropConnection();
2167 }
2168 
2169 template <int stage>
2171  public:
2172  void doAbortTest() {
2173  // Send an abort at various points while receiving the response to a GET
2174  // The test is broken into "stages"
2175  // Stage 0) headers received
2176  // Stage 1) chunk header received
2177  // Stage 2) body received
2178  // Stage 3) chunk complete received
2179  // Stage 4) trailers received
2180  // Stage 5) eom received
2181  // This test makes sure expected callbacks are received if an abort is
2182  // sent before any of these stages.
2183  InSequence enforceOrder;
2185  HTTPMessage req = getPostRequest(10);
2186 
2187  std::unique_ptr<HTTPMessage> resp;
2188  std::unique_ptr<folly::IOBuf> respBody;
2189  std::tie(resp, respBody) = makeResponse(200, 50);
2190 
2191  handler.expectTransaction();
2192  EXPECT_CALL(*codecPtr_, generateHeader(_, _, _, _, _));
2193 
2194  if (stage > 0) {
2195  handler.expectHeaders();
2196  }
2197  if (stage > 1) {
2198  EXPECT_CALL(handler, onChunkHeader(_));
2199  }
2200  if (stage > 2) {
2201  EXPECT_CALL(handler, onBody(_));
2202  }
2203  if (stage > 3) {
2204  EXPECT_CALL(handler, onChunkComplete());
2205  }
2206  if (stage > 4) {
2207  EXPECT_CALL(handler, onTrailers(_));
2208  }
2209  if (stage > 5) {
2210  handler.expectEOM();
2211  }
2212 
2213  auto txn = httpSession_->newTransaction(&handler);
2214  auto streamID = txn->getID();
2215  txn->sendHeaders(req);
2216  txn->sendBody(makeBuf(5)); // only send half the body
2217 
2218  auto doAbort = [&] {
2219  EXPECT_CALL(*codecPtr_, generateRstStream(_, txn->getID(), _));
2220  handler.expectDetachTransaction();
2221  const auto id = txn->getID();
2222  txn->sendAbort();
2223  EXPECT_CALL(*codecPtr_,
2224  generateRstStream(_, id, ErrorCode::_SPDY_INVALID_STREAM))
2225  .Times(AtLeast(0));
2226  };
2227 
2228  if (stage == 0) {
2229  doAbort();
2230  }
2231  codecCb_->onHeadersComplete(streamID, std::move(resp));
2232  if (stage == 1) {
2233  doAbort();
2234  }
2235  codecCb_->onChunkHeader(streamID, respBody->computeChainDataLength());
2236  if (stage == 2) {
2237  doAbort();
2238  }
2239  codecCb_->onBody(streamID, std::move(respBody), 0);
2240  if (stage == 3) {
2241  doAbort();
2242  }
2243  codecCb_->onChunkComplete(streamID);
2244  if (stage == 4) {
2245  doAbort();
2246  }
2247  codecCb_->onTrailersComplete(streamID,
2248  std::make_unique<HTTPHeaders>());
2249  if (stage == 5) {
2250  doAbort();
2251  }
2252  codecCb_->onMessageComplete(streamID, false);
2253 
2254  eventBase_.loop();
2255  }
2256 };
2257 
2264 
2265 TEST_F(TestAbortPost1, Test) { doAbortTest(); }
2266 TEST_F(TestAbortPost2, Test) { doAbortTest(); }
2267 TEST_F(TestAbortPost3, Test) { doAbortTest(); }
2268 TEST_F(TestAbortPost4, Test) { doAbortTest(); }
2269 TEST_F(TestAbortPost5, Test) { doAbortTest(); }
2270 
2272  // This is basically the same test as above, just for the upgrade path
2273  InSequence enforceOrder;
2275  HTTPMessage req = getPostRequest(10);
2276 
2277  std::unique_ptr<HTTPMessage> resp = makeResponse(200);
2278 
2279  handler.expectTransaction();
2280  EXPECT_CALL(*codecPtr_, generateHeader(_, _, _, _, _));
2281 
2282  auto txn = httpSession_->newTransaction(&handler);
2283  const auto streamID = txn->getID();
2284  txn->sendHeaders(req);
2285  txn->sendBody(makeBuf(5)); // only send half the body
2286 
2287  handler.expectHeaders();
2288  codecCb_->onHeadersComplete(streamID, std::move(resp));
2289 
2290  EXPECT_CALL(*codecPtr_, generateRstStream(_, streamID, _));
2291  handler.expectDetachTransaction();
2292  EXPECT_CALL(*codecPtr_, generateRstStream(_, streamID,
2293  ErrorCode::_SPDY_INVALID_STREAM));
2294  txn->sendAbort();
2295  codecCb_->onMessageComplete(streamID, true); // upgrade
2296  EXPECT_CALL(*codecPtr_, generateRstStream(_, streamID,
2297  ErrorCode::_SPDY_INVALID_STREAM));
2298  codecCb_->onMessageComplete(streamID, false); // eom
2299 
2300  eventBase_.loop();
2301 }
2302 
2303 TEST_F(MockHTTPUpstreamTest, DrainBeforeSendHeaders) {
2304  // Test that drain on session before sendHeaders() is called on open txn
2305 
2306  InSequence enforceOrder;
2307  MockHTTPHandler pushHandler;
2308 
2309  auto handler = openTransaction();
2310  EXPECT_CALL(*codecPtr_, generateHeader(_, _, _, _, _));
2311 
2312  handler->expectHeaders();
2313  handler->expectEOM();
2314  handler->expectDetachTransaction();
2315 
2316  httpSession_->drain();
2317  handler->sendRequest();
2318  codecCb_->onHeadersComplete(handler->txn_->getID(), makeResponse(200));
2319  codecCb_->onMessageComplete(handler->txn_->getID(), false); // eom
2320 
2321  eventBase_.loop();
2322 }
2323 
2324 TEST_F(MockHTTP2UpstreamTest, ReceiveDoubleGoaway) {
2325  // Test that we handle receiving two goaways correctly
2326 
2327  InSequence enforceOrder;
2328  auto req = getGetRequest();
2329 
2330  // Open 2 txns but doesn't send headers yet
2331  auto handler1 = openTransaction();
2332  auto handler2 = openTransaction();
2333 
2334  // Get first goaway acking many un-started txns
2335  handler1->expectGoaway();
2336  handler2->expectGoaway();
2337  codecCb_->onGoaway(101, ErrorCode::NO_ERROR);
2338 
2339  // This txn should be alive since it was ack'd by the above goaway
2340  handler1->txn_->sendHeaders(req);
2341 
2342  // Second goaway acks the only the current outstanding transaction
2343  handler1->expectGoaway();
2344  handler2->expectGoaway();
2345  handler2->expectError([&] (const HTTPException& err) {
2348  ASSERT_EQ(
2349  folly::to<std::string>("StreamUnacknowledged on transaction id: ",
2350  handler2->txn_->getID()),
2351  std::string(err.what()));
2352  });
2353  handler2->expectDetachTransaction();
2354  codecCb_->onGoaway(handler1->txn_->getID(), ErrorCode::NO_ERROR);
2355 
2356  // Clean up
2357  httpSession_->drain();
2358  EXPECT_CALL(*codecPtr_, generateRstStream(_, handler1->txn_->getID(), _));
2359  handler1->expectDetachTransaction();
2360  handler1->txn_->sendAbort();
2361  eventBase_.loop();
2362 }
2363 
2364 TEST_F(MockHTTP2UpstreamTest, ServerPushInvalidAssoc) {
2365  // Test that protocol error is generated on server push
2366  // with invalid assoc stream id
2367  InSequence enforceOrder;
2368  auto req = getGetRequest();
2369  auto handler = openTransaction();
2370 
2371  int streamID = handler->txn_->getID();
2372  int pushID = streamID + 1;
2373  int badAssocID = streamID + 2;
2374 
2375  EXPECT_CALL(*codecPtr_,
2376  generateRstStream(_, pushID, ErrorCode::PROTOCOL_ERROR));
2377  EXPECT_CALL(*codecPtr_,
2378  generateRstStream(_, pushID, ErrorCode::_SPDY_INVALID_STREAM))
2379  .Times(2);
2380 
2381  auto resp = makeResponse(200);
2382  codecCb_->onPushMessageBegin(pushID, badAssocID, resp.get());
2383  codecCb_->onHeadersComplete(pushID, std::move(resp));
2384  codecCb_->onMessageComplete(pushID, false);
2385 
2386  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
2387  EXPECT_FALSE(msg->getIsUpgraded());
2388  EXPECT_EQ(200, msg->getStatusCode());
2389  });
2390  handler->expectEOM();
2391 
2392  resp = makeResponse(200);
2393  codecCb_->onMessageBegin(streamID, resp.get());
2394  codecCb_->onHeadersComplete(streamID, std::move(resp));
2395  codecCb_->onMessageComplete(streamID, false);
2396 
2397  // Cleanup
2398  EXPECT_CALL(*codecPtr_, generateRstStream(_, streamID, _));
2399  EXPECT_CALL(*handler, detachTransaction());
2400  handler->terminate();
2401 
2402  EXPECT_TRUE(!httpSession_->hasActiveTransactions());
2403  httpSession_->destroy();
2404 }
2405 
2406 TEST_F(MockHTTP2UpstreamTest, ServerPushAfterFin) {
2407  // Test that protocol error is generated on server push
2408  // after FIN is received on regular response on the stream
2409  InSequence enforceOrder;
2410  auto req = getGetRequest();
2411  auto handler = openTransaction();
2412 
2413  int streamID = handler->txn_->getID();
2414  int pushID = streamID + 1;
2415 
2416  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
2417  EXPECT_FALSE(msg->getIsUpgraded());
2418  EXPECT_EQ(200, msg->getStatusCode());
2419  });
2420  handler->expectEOM();
2421 
2422  auto resp = makeResponse(200);
2423  codecCb_->onMessageBegin(streamID, resp.get());
2424  codecCb_->onHeadersComplete(streamID, std::move(resp));
2425  codecCb_->onMessageComplete(streamID, false);
2426 
2427  EXPECT_CALL(*codecPtr_,
2428  generateRstStream(_, pushID, ErrorCode::PROTOCOL_ERROR))
2429  .WillOnce(InvokeWithoutArgs([this] {
2430  // Verify that the assoc txn is still present
2431  EXPECT_TRUE(httpSession_->hasActiveTransactions());
2432  return 1;
2433  }));
2434  EXPECT_CALL(*codecPtr_,
2435  generateRstStream(_, pushID, ErrorCode::_SPDY_INVALID_STREAM))
2436  .Times(2);
2437 
2438  resp = makeResponse(200);
2439  codecCb_->onPushMessageBegin(pushID, streamID, resp.get());
2440  codecCb_->onHeadersComplete(pushID, std::move(resp));
2441  codecCb_->onMessageComplete(pushID, false);
2442 
2443  // Cleanup
2444  EXPECT_CALL(*codecPtr_, generateRstStream(_, streamID, _));
2445  EXPECT_CALL(*handler, detachTransaction());
2446  handler->terminate();
2447 
2448  EXPECT_TRUE(!httpSession_->hasActiveTransactions());
2449  httpSession_->destroy();
2450 }
2451 
2452 TEST_F(MockHTTP2UpstreamTest, ServerPushHandlerInstallFail) {
2453  // Test that REFUSED_STREAM error is generated when the session
2454  // fails to install the server push handler
2455  InSequence enforceOrder;
2456  auto req = getGetRequest();
2457  auto handler = openTransaction();
2458 
2459  int streamID = handler->txn_->getID();
2460  int pushID = streamID + 1;
2461 
2462  EXPECT_CALL(*handler, onPushedTransaction(_))
2463  .WillOnce(Invoke([] (HTTPTransaction* txn) {
2464  // Intentionally unset the handler on the upstream push txn
2465  txn->setHandler(nullptr);
2466  }));
2467  EXPECT_CALL(*codecPtr_,
2468  generateRstStream(_, pushID, ErrorCode::REFUSED_STREAM));
2469  EXPECT_CALL(*codecPtr_,
2470  generateRstStream(_, pushID, ErrorCode::_SPDY_INVALID_STREAM))
2471  .Times(2);
2472 
2473  auto resp = std::make_unique<HTTPMessage>();
2474  resp->setStatusCode(200);
2475  resp->setStatusMessage("OK");
2476  codecCb_->onPushMessageBegin(pushID, streamID, resp.get());
2477  codecCb_->onHeadersComplete(pushID, std::move(resp));
2478  codecCb_->onMessageComplete(pushID, false);
2479 
2480  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
2481  EXPECT_FALSE(msg->getIsUpgraded());
2482  EXPECT_EQ(200, msg->getStatusCode());
2483  });
2484  handler->expectEOM();
2485 
2486  resp = std::make_unique<HTTPMessage>();
2487  resp->setStatusCode(200);
2488  resp->setStatusMessage("OK");
2489  codecCb_->onMessageBegin(streamID, resp.get());
2490  codecCb_->onHeadersComplete(streamID, std::move(resp));
2491  codecCb_->onMessageComplete(streamID, false);
2492 
2493  // Cleanup
2494  EXPECT_CALL(*codecPtr_, generateRstStream(_, streamID, _));
2495  EXPECT_CALL(*handler, detachTransaction());
2496  handler->terminate();
2497 
2498  EXPECT_TRUE(!httpSession_->hasActiveTransactions());
2499  httpSession_->destroy();
2500 }
2501 
2502 TEST_F(MockHTTP2UpstreamTest, ServerPushUnhandledAssoc) {
2503  // Test that REFUSED_STREAM error is generated when the assoc txn
2504  // is unhandled
2505  InSequence enforceOrder;
2506  auto req = getGetRequest();
2507  auto handler = openTransaction();
2508 
2509  int streamID = handler->txn_->getID();
2510  int pushID = streamID + 1;
2511 
2512  // Forcefully unset the handler on the assoc txn
2513  handler->txn_->setHandler(nullptr);
2514 
2515  EXPECT_CALL(*codecPtr_,
2516  generateRstStream(_, pushID, ErrorCode::REFUSED_STREAM));
2517  EXPECT_CALL(*codecPtr_,
2518  generateRstStream(_, pushID, ErrorCode::_SPDY_INVALID_STREAM))
2519  .Times(2);
2520 
2521  auto resp = std::make_unique<HTTPMessage>();
2522  resp->setStatusCode(200);
2523  resp->setStatusMessage("OK");
2524  codecCb_->onPushMessageBegin(pushID, streamID, resp.get());
2525  codecCb_->onHeadersComplete(pushID, std::move(resp));
2526  codecCb_->onMessageComplete(pushID, false);
2527 
2528  // Cleanup
2529  EXPECT_CALL(*codecPtr_, generateRstStream(_, streamID, _));
2530  handler->terminate();
2531 
2532  EXPECT_TRUE(!httpSession_->hasActiveTransactions());
2533  httpSession_->destroy();
2534 }
2535 
2536 TEST_F(MockHTTPUpstreamTest, HeadersThenBodyThenHeaders) {
2537  HTTPMessage req = getGetRequest();
2538  auto handler = openTransaction();
2539  handler->txn_->sendHeaders(req);
2540 
2541  handler->expectHeaders();
2542  EXPECT_CALL(*handler, onBody(_));
2543  // After getting the second headers, transaction will detach the handler
2544  handler->expectError([&] (const HTTPException& err) {
2547  ASSERT_EQ("Invalid ingress state transition, state=RegularBodyReceived, "
2548  "event=onHeaders, streamID=1",
2549  std::string(err.what()));
2550  });
2551  handler->expectDetachTransaction();
2552  auto resp = makeResponse(200);
2553  codecCb_->onMessageBegin(1, resp.get());
2554  codecCb_->onHeadersComplete(1, std::move(resp));
2555  codecCb_->onBody(1, makeBuf(20), 0);
2556  // Now receive headers again, on the same stream (illegal!)
2557  codecCb_->onHeadersComplete(1, makeResponse(200));
2558  eventBase_.loop();
2559 }
2560 
2561 TEST_F(MockHTTP2UpstreamTest, DelayUpstreamWindowUpdate) {
2562  EXPECT_CALL(*codecPtr_, supportsStreamFlowControl())
2563  .WillRepeatedly(Return(true));
2564 
2565  auto handler = openTransaction();
2566  handler->txn_->setReceiveWindow(1000000); // One miiiillion
2567 
2568  InSequence enforceOrder;
2569  EXPECT_CALL(*codecPtr_, generateHeader(_, _, _, _, _));
2570  EXPECT_CALL(*codecPtr_, generateWindowUpdate(_, _, _));
2571 
2572  HTTPMessage req = getGetRequest();
2573  handler->txn_->sendHeaders(req);
2574  handler->expectDetachTransaction();
2575  handler->txn_->sendAbort();
2576  httpSession_->destroy();
2577 }
2578 
2579 TEST_F(MockHTTPUpstreamTest, ForceShutdownInSetTransaction) {
2581  handler.expectTransaction([&] (HTTPTransaction* txn) {
2582  handler.txn_ = txn;
2583  httpSession_->dropConnection();
2584  });
2585  handler.expectError([&] (const HTTPException& err) {
2588  ASSERT_EQ(folly::to<std::string>("Dropped on transaction id: ",
2589  handler.txn_->getID()),
2590  std::string(err.what()));
2591  });
2592  handler.expectDetachTransaction();
2593  (void)httpSession_->newTransaction(&handler);
2594 }
2595 
2596 TEST_F(HTTP2UpstreamSessionTest, TestReplaySafetyCallback) {
2597  auto sock = dynamic_cast<HTTPTransaction::Transport*>(httpSession_);
2598 
2602 
2603  EXPECT_CALL(*transport_, isReplaySafe())
2604  .WillRepeatedly(Return(false));
2605  sock->addWaitingForReplaySafety(&cb1);
2606  sock->addWaitingForReplaySafety(&cb2);
2607  sock->addWaitingForReplaySafety(&cb3);
2608  sock->removeWaitingForReplaySafety(&cb2);
2609 
2610  ON_CALL(*transport_, isReplaySafe())
2611  .WillByDefault(Return(true));
2612  EXPECT_CALL(cb1, onReplaySafe_());
2613  EXPECT_CALL(cb3, onReplaySafe_());
2614  replaySafetyCallback_->onReplaySafe();
2615 
2616  httpSession_->destroy();
2617 }
2618 
2619 TEST_F(HTTP2UpstreamSessionTest, TestAlreadyReplaySafe) {
2620  auto sock = dynamic_cast<HTTPTransaction::Transport*>(httpSession_);
2621 
2623 
2624  EXPECT_CALL(*transport_, isReplaySafe())
2625  .WillRepeatedly(Return(true));
2626  EXPECT_CALL(cb, onReplaySafe_());
2627  sock->addWaitingForReplaySafety(&cb);
2628 
2629  httpSession_->destroy();
2630 }
2631 
2632 TEST_F(HTTP2UpstreamSessionTest ,TestChainedBufIngress) {
2633  auto buf = folly::IOBuf::copyBuffer("hi");
2634  buf->prependChain(folly::IOBuf::copyBuffer("hello"));
2635 
2637  this->httpSession_->setInfoCallback(&infoCb);
2638 
2639  EXPECT_CALL(infoCb, onRead(_, 7));
2640  readCallback_->readBufferAvailable(std::move(buf));
2641 
2642  httpSession_->destroy();
2643 }
2644 
2646  folly::EventBase base;
2647  auto timer =
2649  &base,
2650  std::chrono::milliseconds(folly::HHWheelTimer::DEFAULT_TICK_INTERVAL),
2651  TimeoutManager::InternalEnum::INTERNAL, std::chrono::milliseconds(500));
2652  WheelTimerInstance timerInstance(timer.get());
2653  uint64_t filterCount = 0;
2654  auto fn = [&filterCount](HTTPCodecFilter* /*filter*/) { filterCount++; };
2655 
2656  InSequence enforceOrder;
2657  auto egressCodec = makeServerCodec();
2659  egressCodec->generateConnectionPreface(output);
2660  egressCodec->generateSettings(output);
2661 
2662  for (auto i = 0; i < 2; i++) {
2663  auto handler = openTransaction();
2664  handler->expectHeaders([&] (std::shared_ptr<HTTPMessage> msg) {
2665  EXPECT_EQ(200, msg->getStatusCode());
2666  });
2667  handler->expectBody();
2668  handler->expectEOM();
2669  handler->expectDetachTransaction();
2670 
2671  HTTPMessage resp;
2672  resp.setStatusCode(200);
2673  egressCodec->generateHeader(output, handler->txn_->getID(), resp);
2674  egressCodec->generateBody(output, handler->txn_->getID(), makeBuf(20),
2675  HTTPCodec::NoPadding, true /* eom */);
2676 
2677  handler->sendRequest();
2678  auto buf = output.move();
2679  buf->coalesce();
2680  readAndLoop(buf.get());
2681 
2682  httpSession_->detachThreadLocals();
2683  httpSession_->attachThreadLocals(&base, nullptr, timerInstance, nullptr, fn,
2684  nullptr, nullptr);
2685  EXPECT_EQ(filterCount, 2);
2686  filterCount = 0;
2687  base.loopOnce();
2688  }
2689  httpSession_->destroy();
2690 }
2691 
2692 // Register and instantiate all our type-paramterized tests
2694  ImmediateEof);
2695 
2696 using AllTypes = ::testing::Types<HTTP1xCodecPair, SPDY3CodecPair>;
HTTPCodec::StreamID parentId_
TestAbortPost< 3 > TestAbortPost3
virtual void setHandler(Handler *handler)
virtual size_t onIngress(const folly::IOBuf &buf)=0
void setCallback(Callback *callback) override
::testing::Types< HTTP1xCodecPair, SPDY3CodecPair > AllTypes
void append(std::unique_ptr< folly::IOBuf > &&buf, bool pack=false)
Definition: IOBufQueue.cpp:143
GTEST_API_ Cardinality AtLeast(int n)
void onSettingsOutgoingStreamsFull(const HTTPSessionBase &) override
ProxygenError getProxygenError() const
Definition: Exception.h:50
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
HTTPUpstreamTest(std::vector< int64_t > flowControl={-1,-1,-1})
LogLevel max
Definition: LogLevel.cpp:31
TestAbortPost< 1 > TestAbortPost1
ByteRange coalesce()
Definition: IOBuf.h:1095
void setStatusMessage(T &&msg)
Definition: HTTPMessage.h:242
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
EventBase * getEventBase()
HTTPMessage::HTTPPriority hiPri_
CodecFactory codec
const uint8_t * data() const
Definition: IOBuf.h:499
void setProxygenError(ProxygenError proxygenError)
Definition: Exception.h:46
std::unique_ptr< folly::IOBuf > move()
Definition: IOBufQueue.h:459
static http_parser_settings settings
Definition: test.c:1529
MockByteEventTracker * setMockByteEventTracker()
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void setCodecStatusCode(ErrorCode statusCode)
Definition: HTTPException.h:98
static int DEFAULT_TICK_INTERVAL
Definition: HHWheelTimer.h:163
tuple make_tuple()
Definition: gtest-tuple.h:675
PolymorphicAction< internal::InvokeWithoutArgsAction< FunctionImpl > > InvokeWithoutArgs(FunctionImpl function_impl)
const HeaderIndexingStrategy * getHeaderIndexingStrategy() const
Definition: HTTP2Codec.h:174
HTTPMessage::HTTPPriority loPri_
void readAndLoop(const uint8_t *input, size_t length)
void onCreate(const HTTPSessionBase &) override
void parseOutput(HTTPCodec &serverCodec)
std::unique_ptr< StrictMock< MockHTTPHandler > > openTransaction(bool expectStartPaused=false)
void handler(int, siginfo_t *, void *)
ProtocolVersion version
std::unique_ptr< folly::IOBuf > makeBuf(uint32_t size)
Definition: ZlibTests.cpp:26
REGISTER_TYPED_TEST_CASE_P(HTTPUpstreamTest, ImmediateEof)
void set(folly::StringPiece name, const std::string &value)
Definition: HTTPHeaders.h:119
void testSimpleUpgrade(const std::string &upgradeReqHeader, const std::string &upgradeRespHeader, CodecProtocol respCodecVersion)
size_t generateBody(folly::IOBufQueue &writeBuf, StreamID stream, std::unique_ptr< folly::IOBuf > chain, folly::Optional< uint8_t > padding, bool eom) override
Definition: SPDYCodec.cpp:765
virtual void onWriteChain(folly::AsyncTransportWrapper::WriteCallback *callback, std::shared_ptr< IOBuf > iob, WriteFlags)
HTTPMessage::HTTPPriority minPriority_
std::unique_ptr< StrictMock< MockHTTPHandler > > openTransaction()
void writeBuf(const Buf &buf, folly::io::Appender &out)
static UniquePtr newTimer(Args &&...args)
Definition: HHWheelTimer.h:61
std::unique_ptr< AsyncTransportWrapper, Destructor > UniquePtr
ParseURL setURL(T &&url)
Definition: HTTPMessage.h:183
void readAndLoop(const std::string &input)
LogLevel min
Definition: LogLevel.cpp:30
static Options cacheChainLength()
Definition: IOBufQueue.h:83
Direction getDirection() const
Definition: HTTPException.h:67
bool loopOnce(int flags=0)
Definition: EventBase.cpp:271
PolymorphicAction< internal::InvokeAction< FunctionImpl > > Invoke(FunctionImpl function_impl)
unique_ptr< typename C::Codec > makeServerCodec()
static UniquePtr makeUnique(Args &&...args)
void setFlowControl(size_t initialReceiveWindow, size_t receiveStreamWindowSize, size_t receiveSessionWindowSize) override
std::size_t length() const
Definition: IOBuf.h:533
TestAbortPost< 0 > TestAbortPost0
void dummy()
virtual uint32_t getDefaultWindowSize() const
Definition: HTTPCodec.h:680
void expectEOM(std::function< void()> callback=std::function< void()>())
wangle::TransportInfo mockTransportInfo_
TestAbortPost< 4 > TestAbortPost4
char a
HTTPMessage getResponse(uint32_t code, uint32_t bodyLen)
Definition: TestUtils.cpp:137
MockAsyncTransport * transport_
void generatePushPromise(folly::IOBufQueue &writeBuf, StreamID stream, const HTTPMessage &msg, StreamID assocstream, bool eom=false, HTTPHeaderSize *size=nullptr) override
Definition: SPDYCodec.cpp:646
std::vector< folly::AsyncTransportWrapper::WriteCallback * > cbs_
#define C(name, bit)
Definition: CpuId.h:204
HTTPCodec::StreamID loPriId_
HTTPHeaders & getHeaders()
Definition: HTTPMessage.h:273
std::vector< HTTPCodec::StreamID > dependencies
void expectDetachTransaction(std::function< void()> callback=std::function< void()>())
std::unique_ptr< HHWheelTimer, Destructor > UniquePtr
Definition: HHWheelTimer.h:57
std::unique_ptr< HTTPMessage > makeResponse(uint16_t statusCode)
Definition: TestUtils.cpp:147
void onSettingsOutgoingStreamsNotFull(const HTTPSessionBase &) override
TYPED_TEST_CASE_P(HTTPUpstreamTest)
bool hasProxygenError() const
Definition: Exception.h:44
TEST_F(AsyncSSLSocketWriteTest, write_coalescing1)
void expectTransaction(std::function< void(HTTPTransaction *txn)> callback)
void expectHeaders(std::function< void()> callback=std::function< void()>())
std::size_t computeChainDataLength() const
Definition: IOBuf.cpp:501
void enableExHeader(typename C::Codec *serverCodec)
std::unique_ptr< NiceMock< MockHTTPHandler > > openNiceTransaction(bool expectStartPaused=false)
std::tuple< uint32_t, bool, uint8_t > HTTPPriority
Definition: HTTPMessage.h:592
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
std::shared_ptr< TestPriorityMapBuilder > builder_
void commonSetUp(unique_ptr< HTTPCodec > codec)
std::vector< HTTPSetting > SettingsList
Definition: HTTPSettings.h:81
#define ON_CALL(obj, call)
std::enable_if< std::is_enum< Version >::value, std::unique_ptr< MyCodec > >::type makeServerCodec(Version version)
virtual folly::Optional< const HTTPMessage::HTTPPriority > getHTTPPriority(uint8_t level) override
void onDestroy(const HTTPSessionBase &) override
HTTPMessage getGetRequest(const std::string &url)
Definition: TestUtils.cpp:76
const char * string
Definition: Conv.cpp:212
AsyncFizzClient::UniquePtr transport_
std::vector< int64_t > flowControl_
TestAbortPost< 2 > TestAbortPost2
HTTPMessage getPostRequest(uint32_t contentLength)
Definition: TestUtils.cpp:102
void setHTTPVersion(uint8_t major, uint8_t minor)
PolymorphicAction< internal::AssignAction< T1, T2 > > Assign(T1 *ptr, T2 val)
void onWriteChain(folly::AsyncTransportWrapper::WriteCallback *callback, std::shared_ptr< IOBuf >, WriteFlags) override
void commonSetUp(unique_ptr< HTTPCodec > codec)
void handleWrite(folly::AsyncTransportWrapper::WriteCallback *callback)
#define EXPECT_CALL(obj, call)
uint64_t StreamID
Definition: HTTPCodec.h:49
const internal::AnythingMatcher _
virtual void writeSuccess() noexcept=0
HTTPCodec::StreamID hiPriId_
void add(folly::StringPiece name, folly::StringPiece value)
Definition: HTTPHeaders.cpp:52
virtual void writeErr(size_t bytesWritten, const AsyncSocketException &ex) noexcept=0
TYPED_TEST_P(HTTPUpstreamTest, ImmediateEof)
#define ASSERT_NE(val1, val2)
Definition: gtest.h:1960
HTTPMessage getUpgradeRequest(const std::string &upgradeHeader, HTTPMethod method, uint32_t bodyLen)
Definition: TestUtils.cpp:161
void testBasicRequestHttp10(bool keepalive)
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
folly::HHWheelTimer::UniquePtr transactionTimeouts_
virtual HTTPCodec::StreamID sendPriority(http2::PriorityUpdate pri)=0
#define EXPECT_LT(val1, val2)
Definition: gtest.h:1930
virtual std::unique_ptr< HTTPUpstreamSession::PriorityAdapter > createVirtualStreams(HTTPPriorityMapFactoryProvider *session) const override
HTTPCodec::StreamID getID() const
INSTANTIATE_TYPED_TEST_CASE_P(AllTypesPrefix, HTTPUpstreamTest, AllTypes)
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
void generateHeader(folly::IOBufQueue &writeBuf, StreamID stream, const HTTPMessage &msg, bool eom=false, HTTPHeaderSize *size=nullptr) override
Definition: SPDYCodec.cpp:625
TestAbortPost< 5 > TestAbortPost5
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)
std::vector< folly::AsyncTransportWrapper::WriteCallback * > cbs_
void expectBody(std::function< void()> callback=std::function< void()>())
void readAndLoop(IOBuf *buf)
constexpr None none
Definition: Optional.h:87
internal::ReturnAction< R > Return(R value)
size_t generateGoaway(folly::IOBufQueue &writeBuf, StreamID lastStream, ErrorCode statusCode, std::unique_ptr< folly::IOBuf > debugData=nullptr) override
Definition: SPDYCodec.cpp:856
std::map< uint8_t, HTTPMessage::HTTPPriority > priorityMap_
uint32_t getDefaultWindowSize() const override
Definition: HTTP2Codec.h:117
void setStatusCode(uint16_t status)