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