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 "folly/Expected.h"
10 #include <proxygen/lib/http/session/HQDownstreamSession.h>
11 
12 #include <folly/io/async/EventBaseManager.h>
13 #include <proxygen/lib/http/codec/HQControlCodec.h>
14 #include <proxygen/lib/http/codec/HQStreamCodec.h>
15 #include <proxygen/lib/http/codec/HQUnidirectionalCodec.h>
16 #include <proxygen/lib/http/codec/HTTP1xCodec.h>
17 #include <proxygen/lib/http/session/test/HQDownstreamSessionTest.h>
18 #include <proxygen/lib/http/session/test/HQSessionMocks.h>
19 #include <proxygen/lib/http/session/test/HTTPSessionMocks.h>
20 #include <proxygen/lib/http/session/test/HTTPTransactionMocks.h>
21 #include <proxygen/lib/http/session/test/MockQuicSocketDriver.h>
22 #include <proxygen/lib/http/session/test/TestUtils.h>
23 #include <quic/api/test/MockQuicSocket.h>
24 #include <quic/dsr/Types.h>
25 #include <wangle/acceptor/ConnectionManager.h>
26 
27 #include <folly/futures/Future.h>
28 #include <folly/portability/GTest.h>
29 
30 using namespace proxygen;
31 using namespace proxygen::hq;
32 using namespace quic;
33 using namespace folly;
34 using namespace testing;
35 using namespace std::chrono;
36 
37 // Use this test class for h1q-fb only tests
38 using HQDownstreamSessionTestH1q = HQDownstreamSessionTest;
39 // Use this test class for h1q-fb-v1 only tests
40 using HQDownstreamSessionTestH1qv1 = HQDownstreamSessionTest;
41 // Use this test class for h1q-fb-v2/hq common tests (goaway)
42 using HQDownstreamSessionTestH1qv2HQ = HQDownstreamSessionTest;
43 
44 // Use this test class for hq only tests
45 using HQDownstreamSessionTestHQ = HQDownstreamSessionTest;
46 using HQDownstreamSessionTestHQDeliveryAck = HQDownstreamSessionTest;
47 
48 // Use this test class for h3 server push tests
49 using HQDownstreamSessionTestHQPush = HQDownstreamSessionTest;
50 
51 namespace {
getProgressiveGetRequest()52 HTTPMessage getProgressiveGetRequest() {
53   auto req = proxygen::getGetRequest();
54   req.getHeaders().add(HTTP_HEADER_PRIORITY, "u=1, i");
55   return req;
56 }
57 } // namespace
58 
sendRequest(const std::string & url,int8_t priority,bool eom)59 HTTPCodec::StreamID HQDownstreamSessionTest::sendRequest(const std::string& url,
60                                                          int8_t priority,
61                                                          bool eom) {
62   auto req = proxygen::getGetRequest();
63   req.setURL(url);
64   req.setPriority(priority);
65   return sendRequest(req, eom);
66 }
67 
nextStreamId()68 quic::StreamId HQDownstreamSessionTest::nextStreamId() {
69   auto id = nextStreamId_;
70   nextStreamId_ += 4;
71   return id;
72 }
73 
sendRequest(const proxygen::HTTPMessage & req,bool eom,quic::StreamId id)74 quic::StreamId HQDownstreamSessionTest::sendRequest(
75     const proxygen::HTTPMessage& req, bool eom, quic::StreamId id) {
76   if (id == quic::kEightByteLimit) {
77     id = nextStreamId();
78   }
79   auto res = requests_.emplace(std::piecewise_construct,
80                                std::forward_as_tuple(id),
81                                std::forward_as_tuple(makeCodec(id)));
82   auto& request = res.first->second;
83   request.id = request.codec->createStream();
84   request.readEOF = eom;
85   request.codec->generateHeader(request.buf, request.id, req, eom);
86   return id;
87 }
88 
sendHeader()89 quic::StreamId HQDownstreamSessionTest::sendHeader() {
90   return sendRequest("/", 0, false);
91 }
92 
sendRequestLater(proxygen::HTTPMessage req,bool eof)93 folly::Promise<folly::Unit> HQDownstreamSessionTest::sendRequestLater(
94     proxygen::HTTPMessage req, bool eof) {
95   folly::Promise<folly::Unit> reqp;
96   reqp.getSemiFuture().via(&eventBase_).thenValue([=](auto&&) {
97     auto id = sendRequest(req, eof);
98     socketDriver_->addReadEvent(
99         id, getStream(id).buf.move(), std::chrono::milliseconds(0));
100     socketDriver_->addReadEOF(id, std::chrono::milliseconds(0));
101     // note that eof=true used to terminate the connection and now it
102     // no longer does
103   });
104   return reqp;
105 }
106 
SetUp()107 void HQDownstreamSessionTest::SetUp() {
108   SetUpBase();
109   SetUpOnTransportReady();
110 }
111 
TearDown()112 void HQDownstreamSessionTest::TearDown() {
113   if (!IS_H1Q_FB_V1) {
114     // with these versions we need to wait for GOAWAY delivery on the control
115     // stream
116     eventBase_.loop();
117   }
118 }
119 
SetUpBase()120 void HQDownstreamSessionTest::SetUpBase() {
121   HQSessionTest::SetUp();
122   streamTransInfo_ = {.totalHeadOfLineBlockedTime =
123                           std::chrono::milliseconds(100),
124                       .holbCount = 2,
125                       .isHolb = true};
126 
127   EXPECT_CALL(*socketDriver_->getSocket(), getStreamTransportInfo(testing::_))
128       .WillRepeatedly(testing::Return(streamTransInfo_));
129 }
130 
SetUpOnTransportReady()131 void HQDownstreamSessionTest::SetUpOnTransportReady() {
132   hqSession_->onTransportReady();
133 
134   if (createControlStreams()) {
135     eventBase_.loopOnce();
136     if (IS_HQ) {
137       EXPECT_EQ(httpCallbacks_.settings, 1);
138     }
139   }
140 }
141 
142 template <class HandlerType>
143 std::unique_ptr<testing::StrictMock<HandlerType>>
addSimpleStrictHandlerBase()144 HQDownstreamSessionTest::addSimpleStrictHandlerBase() {
145   auto handler = std::make_unique<testing::StrictMock<HandlerType>>();
146 
147   // The ownership model here is suspect, but assume the callers won't destroy
148   // handler before it's requested
149   auto rawHandler = handler.get();
150   EXPECT_CALL(getMockController(), getRequestHandler(testing::_, testing::_))
151       .WillOnce(testing::Return(rawHandler))
152       .RetiresOnSaturation();
153 
154   EXPECT_CALL(*handler, setTransaction(testing::_))
155       .WillOnce(testing::SaveArg<0>(&handler->txn_));
156 
157   return handler;
158 }
159 
160 std::unique_ptr<testing::StrictMock<proxygen::MockHTTPHandler>>
addSimpleStrictHandler()161 HQDownstreamSessionTest::addSimpleStrictHandler() {
162   return addSimpleStrictHandlerBase<proxygen::MockHTTPHandler>();
163 }
164 
165 std::pair<quic::StreamId,
166           std::unique_ptr<testing::StrictMock<proxygen::MockHTTPHandler>>>
checkRequest(proxygen::HTTPMessage req)167 HQDownstreamSessionTest::checkRequest(proxygen::HTTPMessage req) {
168   auto id = sendRequest(req);
169   auto handler = addSimpleStrictHandler();
170   handler->expectHeaders();
171   handler->expectEOM(
172       [hdlr = handler.get()] { hdlr->sendReplyWithBody(200, 100); });
173   handler->expectDetachTransaction();
174   return {id, std::move(handler)};
175 }
176 
flushRequestsAndWaitForReads(bool eof,std::chrono::milliseconds eofDelay,std::chrono::milliseconds initialDelay,std::function<void ()> extraEventsFn)177 void HQDownstreamSessionTest::flushRequestsAndWaitForReads(
178     bool eof,
179     std::chrono::milliseconds eofDelay,
180     std::chrono::milliseconds initialDelay,
181     std::function<void()> extraEventsFn) {
182   while (!flushRequests(eof, eofDelay, initialDelay, extraEventsFn)) {
183     CHECK(eventBase_.loop());
184   }
185   CHECK(eventBase_.loop());
186 }
187 
flushRequestsAndLoop(bool eof,std::chrono::milliseconds eofDelay,std::chrono::milliseconds initialDelay,std::function<void ()> extraEventsFn)188 void HQDownstreamSessionTest::flushRequestsAndLoop(
189     bool eof,
190     std::chrono::milliseconds eofDelay,
191     std::chrono::milliseconds initialDelay,
192     std::function<void()> extraEventsFn) {
193   flushRequests(eof, eofDelay, initialDelay, extraEventsFn);
194   CHECK(eventBase_.loop());
195 }
196 
flushRequestsAndLoopN(uint64_t n,bool eof,std::chrono::milliseconds eofDelay,std::chrono::milliseconds initialDelay,std::function<void ()> extraEventsFn)197 void HQDownstreamSessionTest::flushRequestsAndLoopN(
198     uint64_t n,
199     bool eof,
200     std::chrono::milliseconds eofDelay,
201     std::chrono::milliseconds initialDelay,
202     std::function<void()> extraEventsFn) {
203   flushRequests(eof, eofDelay, initialDelay, extraEventsFn);
204   for (uint64_t i = 0; i < n; i++) {
205     eventBase_.loopOnce();
206   }
207 }
208 
flushRequests(bool eof,std::chrono::milliseconds eofDelay,std::chrono::milliseconds initialDelay,std::function<void ()> extraEventsFn)209 bool HQDownstreamSessionTest::flushRequests(
210     bool eof,
211     std::chrono::milliseconds eofDelay,
212     std::chrono::milliseconds initialDelay,
213     std::function<void()> extraEventsFn) {
214   bool done = true;
215 
216   if (!encoderWriteBuf_.empty()) {
217     socketDriver_->addReadEvent(
218         kQPACKEncoderIngressStreamId, encoderWriteBuf_.move(), initialDelay);
219     initialDelay = std::chrono::milliseconds(0);
220   }
221   for (auto& req : requests_) {
222     if (socketDriver_->isStreamIdle(req.first)) {
223       continue;
224     }
225     if (req.second.buf.chainLength() > 0) {
226       socketDriver_->addReadEvent(
227           req.first, req.second.buf.move(), initialDelay);
228       done = false;
229     }
230     // EOM -> stream EOF
231     if (req.second.readEOF) {
232       socketDriver_->addReadEOF(req.first, eofDelay);
233       done = false;
234     }
235   }
236   if (extraEventsFn) {
237     extraEventsFn();
238   }
239   if (eof || eofDelay.count() > 0) {
240     /*  wonkiness.  Should somehow close the connection?
241      * socketDriver_->addReadEOF(1, eofDelay);
242      */
243   }
244   return done;
245 }
246 
247 testing::StrictMock<proxygen::MockController>&
getMockController()248 HQDownstreamSessionTest::getMockController() {
249   return controllerContainer_.mockController;
250 }
251 
makeCodec(proxygen::HTTPCodec::StreamID id)252 std::unique_ptr<proxygen::HTTPCodec> HQDownstreamSessionTest::makeCodec(
253     proxygen::HTTPCodec::StreamID id) {
254   if (IS_HQ) {
255     return std::make_unique<proxygen::hq::HQStreamCodec>(
256         id,
257         proxygen::TransportDirection::UPSTREAM,
258         qpackCodec_,
259         encoderWriteBuf_,
260         decoderWriteBuf_,
261         [] { return std::numeric_limits<uint64_t>::max(); },
262         ingressSettings_);
263   } else {
264     return std::make_unique<proxygen::HTTP1xCodec>(
265         proxygen::TransportDirection::UPSTREAM, true);
266   }
267 }
268 
getStream(proxygen::HTTPCodec::StreamID id)269 HQDownstreamSessionTest::ClientStream& HQDownstreamSessionTest::getStream(
270     proxygen::HTTPCodec::StreamID id) {
271   auto it = requests_.find(id);
272   CHECK(it != requests_.end());
273   return it->second;
274 }
275 
expectTransactionTimeout(testing::StrictMock<proxygen::MockHTTPHandler> & handler,folly::Function<void ()> fn)276 void HQDownstreamSessionTest::expectTransactionTimeout(
277     testing::StrictMock<proxygen::MockHTTPHandler>& handler,
278     folly::Function<void()> fn) {
279   EXPECT_CALL(getMockController(),
280               getTransactionTimeoutHandler(testing::_, testing::_))
281       .WillOnce(testing::Return(&handler));
282   EXPECT_CALL(handler, setTransaction(testing::_))
283       .WillOnce(testing::SaveArg<0>(&handler.txn_));
284   handler.expectError(
285       [&handler, &fn](const proxygen::HTTPException& ex) mutable {
286         if (fn) {
287           fn();
288         }
289         EXPECT_FALSE(ex.hasHttpStatusCode());
290         handler.sendHeaders(408, 100);
291         handler.sendBody(100);
292         handler.sendEOM();
293       });
294   handler.expectDetachTransaction();
295 }
296 
TEST_P(HQDownstreamSessionTest,GetMaxPushIdOK)297 TEST_P(HQDownstreamSessionTest, GetMaxPushIdOK) {
298   folly::Optional<hq::PushId> expectedId = hqSession_->getMaxAllowedPushId();
299   EXPECT_EQ(expectedId, folly::none);
300   hqSession_->closeWhenIdle();
301 }
302 
TEST_P(HQDownstreamSessionTest,SimpleGet)303 TEST_P(HQDownstreamSessionTest, SimpleGet) {
304   auto idh = checkRequest();
305   flushRequestsAndLoop();
306   EXPECT_GT(socketDriver_->streams_[idh.first].writeBuf.chainLength(), 110);
307   EXPECT_TRUE(socketDriver_->streams_[idh.first].writeEOF);
308   if (IS_HQ) {
309     // Checks that the server response is sent using the QPACK dynamic table
310     CHECK_GE(qpackCodec_.getCompressionInfo().ingress.headerTableSize_, 0);
311   }
312   hqSession_->closeWhenIdle();
313 }
314 
TEST_P(HQDownstreamSessionTest,PriorityUpdateIntoTransport)315 TEST_P(HQDownstreamSessionTest, PriorityUpdateIntoTransport) {
316   if (!IS_HQ) { // H1Q tests do not support priority
317     hqSession_->closeWhenIdle();
318     return;
319   }
320   auto request = getProgressiveGetRequest();
321   sendRequest(request);
322   auto handler = addSimpleStrictHandler();
323   EXPECT_CALL(*socketDriver_->getSocket(), setStreamPriority(_, 1, true));
324   handler->expectHeaders();
325   handler->expectEOM([&]() {
326     auto resp = makeResponse(200, 0);
327     std::get<0>(resp)->getHeaders().add(HTTP_HEADER_PRIORITY, "u=2");
328     EXPECT_CALL(*socketDriver_->getSocket(), setStreamPriority(_, 2, false))
329         .Times(1);
330     handler->sendRequest(*std::get<0>(resp));
331   });
332   handler->expectDetachTransaction();
333   flushRequestsAndLoop();
334   hqSession_->closeWhenIdle();
335 }
336 
TEST_P(HQDownstreamSessionTest,ReplyResponsePriority)337 TEST_P(HQDownstreamSessionTest, ReplyResponsePriority) {
338   if (!IS_HQ) { // H1Q tests do not support priority
339     hqSession_->closeWhenIdle();
340     return;
341   }
342   auto request = getProgressiveGetRequest();
343   sendRequest(request);
344   auto handler = addSimpleStrictHandler();
345   EXPECT_CALL(*socketDriver_->getSocket(), setStreamPriority(_, 1, true))
346       .Times(1);
347   handler->expectHeaders();
348   handler->expectEOM([&]() {
349     auto resp = makeResponse(200, 0);
350     EXPECT_CALL(*socketDriver_->getSocket(), getStreamPriority(_))
351         .Times(1)
352         .WillOnce(Return(quic::Priority(1, true)));
353     handler->sendRequest(*std::get<0>(resp));
354   });
355   handler->expectDetachTransaction();
356   flushRequestsAndLoop();
357   hqSession_->closeWhenIdle();
358 }
359 
TEST_P(HQDownstreamSessionTestHQPush,PushPriority)360 TEST_P(HQDownstreamSessionTestHQPush, PushPriority) {
361   sendRequest("/", 1);
362   HTTPMessage promiseReq, parentResp;
363   promiseReq.getHeaders().set(HTTP_HEADER_HOST, "www.foo.com");
364   promiseReq.setURL("/");
365   promiseReq.setHTTPPriority(0, false);
366 
367   parentResp.setStatusCode(200);
368   parentResp.setStatusMessage("Ohai");
369 
370   HTTPMessage pushResp(parentResp);
371   pushResp.setHTTPPriority(1, false);
372 
373   auto handler = addSimpleStrictHandler();
374   StrictMock<MockHTTPPushHandler> pushHandler;
375   handler->expectHeaders();
376   HTTPCodec::StreamID pushStreamId = 0;
377   handler->expectEOM([&] {
378     EXPECT_CALL(*socketDriver_->getSocket(),
379                 setStreamPriority(handler->txn_->getID(), _, _))
380         .Times(0);
381     handler->txn_->sendHeaders(parentResp);
382     handler->txn_->sendBody(makeBuf(100));
383 
384     auto outgoingStreams = hqSession_->getNumOutgoingStreams();
385     auto* pushTxn = handler->txn_->newPushedTransaction(&pushHandler);
386     ASSERT_NE(pushTxn, nullptr);
387     EXPECT_EQ(hqSession_->getNumOutgoingStreams(), outgoingStreams + 1);
388     // PushPromise doesn't update parent streram's priority. It does update push
389     // stream priority
390     EXPECT_CALL(*socketDriver_->getSocket(),
391                 setStreamPriority(handler->txn_->getID(), _, _))
392         .Times(0);
393     EXPECT_CALL(*socketDriver_->getSocket(),
394                 setStreamPriority(pushTxn->getID(), 0, false))
395         .Times(1);
396     pushTxn->sendHeaders(promiseReq);
397     pushStreamId = pushTxn->getID();
398     EXPECT_CALL(*socketDriver_->getSocket(),
399                 setStreamPriority(pushStreamId, 1, false))
400         .Times(1);
401     pushTxn->sendHeaders(pushResp);
402     pushTxn->sendBody(makeBuf(200));
403     pushTxn->sendEOM();
404   });
405   EXPECT_CALL(pushHandler, setTransaction(_))
406       .WillOnce(Invoke([&](HTTPTransaction* txn) { pushHandler.txn_ = txn; }));
407   EXPECT_CALL(pushHandler, detachTransaction());
408 
409   flushRequestsAndLoopN(1);
410   handler->txn_->sendEOM();
411   handler->expectDetachTransaction();
412   flushRequestsAndLoop();
413   hqSession_->closeWhenIdle();
414 }
415 
TEST_P(HQDownstreamSessionTest,OnPriorityCallback)416 TEST_P(HQDownstreamSessionTest, OnPriorityCallback) {
417   if (!IS_HQ) { // H1Q tests do not support priority
418     hqSession_->closeWhenIdle();
419     return;
420   }
421   // Simulate priority arriving too early, connection still valid
422   // this is going to be stored and applied when receiving headers
423   hqSession_->onPriority(0, HTTPPriority(3, false));
424   EXPECT_CALL(*socketDriver_->getSocket(), setStreamPriority(0, 3, false));
425   auto id = sendRequest(getProgressiveGetRequest());
426   CHECK_EQ(id, 0);
427   auto handler = addSimpleStrictHandler();
428   handler->expectHeaders([&]() {
429     handler->sendHeaders(200, 1000);
430     // Priority update on the stream
431     EXPECT_CALL(*socketDriver_->getSocket(), setStreamPriority(0, 2, true));
432     hqSession_->onPriority(id, HTTPPriority(2, true));
433     handler->sendBody(1000);
434     handler->sendEOM();
435   });
436   handler->expectEOM();
437   handler->expectDetachTransaction();
438   flushRequestsAndLoop();
439   // Priority on a stream we can't find - no-op
440   hqSession_->onPriority(id, HTTPPriority(4, true));
441   hqSession_->closeWhenIdle();
442 }
443 
TEST_P(HQDownstreamSessionTest,GetStopSending)444 TEST_P(HQDownstreamSessionTest, GetStopSending) {
445   auto id = sendRequest(getGetRequest());
446   auto handler = addSimpleStrictHandler();
447   handler->expectHeaders();
448   handler->expectEOM([hdlr = handler.get()] { hdlr->sendHeaders(200, 100); });
449   handler->expectError([](const proxygen::HTTPException& ex) {
450     EXPECT_EQ(ex.getCodecStatusCode(), ErrorCode::CANCEL);
451     EXPECT_EQ(ex.getProxygenError(), kErrorStreamAbort);
452   });
453   handler->expectDetachTransaction();
454   flushRequestsAndLoopN(1);
455   socketDriver_->addStopSending(id, HTTP3::ErrorCode::HTTP_REQUEST_CANCELLED);
456   flushRequestsAndLoop();
457   hqSession_->closeWhenIdle();
458 }
459 
TEST_P(HQDownstreamSessionTest,HttpRateLimitNormal)460 TEST_P(HQDownstreamSessionTest, HttpRateLimitNormal) {
461   // The rate-limiting code grabs the event base from the EventBaseManager,
462   // so we need to set it.
463   folly::EventBaseManager::get()->setEventBase(&eventBase_, false);
464   uint32_t rspLengthBytes = 100000;
465 
466   // make sure we are not limited by connection flow control
467   socketDriver_->getSocket()->setConnectionFlowControlWindow(rspLengthBytes *
468                                                              2);
469   // Create a request
470   auto id = sendRequest();
471 
472   // Set a low rate-limit on the transaction
473   auto handler1 = addSimpleStrictHandler();
474   handler1->expectHeaders([&] {
475     uint32_t rateLimit_kbps = 640;
476     handler1->txn_->setEgressRateLimit(rateLimit_kbps * 1024);
477   });
478   // Send a somewhat big response that we know will get rate-limited
479   handler1->expectEOM([&] {
480     // At 640kbps, this should take slightly over 800ms
481     handler1->sendHeaders(200, rspLengthBytes);
482     handler1->sendBody(rspLengthBytes);
483   });
484   EXPECT_CALL(*handler1, onEgressPaused()).Times(AtLeast(1));
485   handler1->expectEgressResumed([&handler1] { handler1->txn_->sendEOM(); });
486   handler1->expectDetachTransaction();
487   flushRequestsAndLoop();
488 
489   // Check that the write side got blocked
490   socketDriver_->expectStreamWritesPaused(id);
491   // Open flow control again
492   socketDriver_->getSocket()->setStreamFlowControlWindow(id,
493                                                          rspLengthBytes * 2);
494   flushRequestsAndLoop();
495 
496   hqSession_->closeWhenIdle();
497 }
498 
TEST_P(HQDownstreamSessionTest,SimplePost)499 TEST_P(HQDownstreamSessionTest, SimplePost) {
500   auto id = sendRequest(getPostRequest(10), false);
501   auto& request = getStream(id);
502   request.codec->generateBody(
503       request.buf, request.id, makeBuf(10), HTTPCodec::NoPadding, true);
504   request.readEOF = true;
505   auto handler = addSimpleStrictHandler();
506   handler->expectHeaders();
507   handler->expectBody(); // should check length too but meh
508   handler->expectEOM([&handler] { handler->sendReplyWithBody(200, 100); });
509   handler->expectDetachTransaction();
510   flushRequestsAndLoop();
511   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
512   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
513   hqSession_->closeWhenIdle();
514 }
515 
516 // HQ doesn't have the notion of chunked
TEST_P(HQDownstreamSessionTestH1q,ChunkedPost)517 TEST_P(HQDownstreamSessionTestH1q, ChunkedPost) {
518   InSequence enforceOrder;
519 
520   auto id = sendRequest(getChunkedPostRequest(), false);
521   auto& request = getStream(id);
522   auto handler = addSimpleStrictHandler();
523   handler->expectHeaders();
524   for (int i = 1; i <= 3; i++) {
525     auto size = 10 * i;
526     request.codec->generateChunkHeader(request.buf, request.id, size);
527     handler->expectChunkHeader();
528     request.codec->generateBody(
529         request.buf, request.id, makeBuf(size), HTTPCodec::NoPadding, false);
530     handler->expectBody([size](uint64_t, std::shared_ptr<folly::IOBuf> buf) {
531       EXPECT_EQ(size, buf->length());
532     });
533     request.codec->generateChunkTerminator(request.buf, request.id);
534     handler->expectChunkComplete();
535   }
536   request.codec->generateEOM(request.buf, request.id);
537   request.readEOF = true;
538   handler->expectEOM([&handler] {
539     // Chunked Transfer Encoding for the response too
540     handler->sendChunkedReplyWithBody(200, 400, 100, false);
541   });
542   handler->expectDetachTransaction();
543   flushRequestsAndLoop();
544   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
545   hqSession_->closeWhenIdle();
546 }
547 
TEST_P(HQDownstreamSessionTest,SimpleGetEofDelay)548 TEST_P(HQDownstreamSessionTest, SimpleGetEofDelay) {
549   auto idh = checkRequest();
550   flushRequestsAndLoop(false, std::chrono::milliseconds(10));
551   EXPECT_GT(socketDriver_->streams_[idh.first].writeBuf.chainLength(), 110);
552   EXPECT_TRUE(socketDriver_->streams_[idh.first].writeEOF);
553   hqSession_->closeWhenIdle();
554 }
555 
TEST_P(HQDownstreamSessionTest,UnfinishedPost)556 TEST_P(HQDownstreamSessionTest, UnfinishedPost) {
557   auto id = sendRequest(getPostRequest(10), false);
558   auto& request = getStream(id);
559   request.codec->generateBody(
560       request.buf, request.id, makeBuf(9), HTTPCodec::NoPadding, true);
561   request.readEOF = true;
562   auto handler = addSimpleStrictHandler();
563   handler->expectHeaders();
564   handler->expectBody();
565   handler->expectError([this, &handler](const proxygen::HTTPException& ex) {
566     if (IS_HQ) {
567       // The HTTP/1.1 parser tracks content-length and 400's if it is short
568       // The HQStreamCodec does no such thing, and it's caught by
569       // HTTPTransaction, with a different error.
570       EXPECT_EQ(ex.getProxygenError(), kErrorParseBody);
571     } else {
572       EXPECT_TRUE(ex.hasHttpStatusCode());
573       EXPECT_EQ(ex.getHttpStatusCode(), 400);
574     }
575     handler->sendReplyWithBody(400, 100);
576     // afrind: this logic is in HTTPSession so should move to base or
577     // duplicate in HQSession (see also custom error handlers)
578   });
579   handler->expectDetachTransaction();
580   flushRequestsAndLoop();
581   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
582   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
583   hqSession_->dropConnection();
584 }
585 
586 // This is a bit weird.  Extra junk after an HTTP/1.1 message now gets ignored
587 // until more junk or an EOF arrives.  Had to split the test into two loops.
TEST_P(HQDownstreamSessionTestH1qv1,TwoMessages)588 TEST_P(HQDownstreamSessionTestH1qv1, TwoMessages) {
589   auto id = sendRequest(getGetRequest(), false);
590   auto handler = addSimpleStrictHandler();
591   handler->expectHeaders();
592   flushRequestsAndLoopN(1);
593 
594   // add a second request to the stream with Connection: close
595   auto& request = getStream(id);
596   auto req2 = getGetRequest();
597   req2.getHeaders().add(HTTP_HEADER_CONNECTION, "close");
598   request.codec->generateHeader(request.buf, request.id, req2, true);
599   request.readEOF = true;
600   hqSession_->notifyPendingShutdown();
601   handler->expectError(
602       [&handler](const HTTPException&) { handler->txn_->sendAbort(); });
603   handler->expectDetachTransaction();
604   flushRequestsAndLoop();
605   hqSession_->closeWhenIdle();
606 }
607 
TEST_P(HQDownstreamSessionTest,Multiplexing)608 TEST_P(HQDownstreamSessionTest, Multiplexing) {
609   std::vector<std::unique_ptr<StrictMock<MockHTTPHandler>>> handlers;
610   for (auto n = 0; n < 10; n++) {
611     auto idh = checkRequest();
612     handlers.emplace_back(std::move(idh.second));
613   }
614   flushRequestsAndWaitForReads();
615   for (auto& req : requests_) {
616     EXPECT_GT(socketDriver_->streams_[req.first].writeBuf.chainLength(), 110);
617     EXPECT_TRUE(socketDriver_->streams_[req.first].writeEOF);
618   }
619   hqSession_->closeWhenIdle();
620 }
621 
TEST_P(HQDownstreamSessionTest,Maxreadsperloop)622 TEST_P(HQDownstreamSessionTest, Maxreadsperloop) {
623   std::vector<std::unique_ptr<StrictMock<MockHTTPHandler>>> handlers;
624   for (auto n = 0; n < 20; n++) {
625     auto idh = checkRequest();
626     handlers.emplace_back(std::move(idh.second));
627   }
628 
629   flushRequestsAndLoopN(1);
630   // After one loop, reads on some streams will be idle
631   // while on some other they will not
632   int idleCount = 0;
633   int nonIdleCount = 0;
634   for (auto& req : requests_) {
635     if (socketDriver_->isStreamIdle(req.first)) {
636       idleCount++;
637     } else {
638       nonIdleCount++;
639     }
640   }
641   EXPECT_GT(idleCount, 0);
642   EXPECT_GT(nonIdleCount, 0);
643 
644   // Now finish all the reads
645   eventBase_.loop();
646   for (auto& req : requests_) {
647     EXPECT_GT(socketDriver_->streams_[req.first].writeBuf.chainLength(), 110);
648     EXPECT_TRUE(socketDriver_->streams_[req.first].writeEOF);
649   }
650   hqSession_->closeWhenIdle();
651 }
652 
TEST_P(HQDownstreamSessionTest,OnFlowControlUpdate)653 TEST_P(HQDownstreamSessionTest, OnFlowControlUpdate) {
654   auto id = sendRequest();
655   auto handler = addSimpleStrictHandler();
656   handler->expectHeaders();
657   handler->expectEOM([&handler] {
658     handler->sendHeaders(200, 100);
659     handler->txn_->sendBody(makeBuf(100));
660   });
661   handler->expectEgressPaused();
662   handler->expectEgressResumed([&handler] { handler->txn_->sendEOM(); });
663   handler->expectDetachTransaction();
664 
665   // Initialize the flow control window to less than the response body
666   socketDriver_->setStreamFlowControlWindow(id, 10);
667   flushRequestsAndLoop();
668   // Check that the write side got blocked
669   socketDriver_->expectStreamWritesPaused(id);
670   // Open the flow control window
671   socketDriver_->getSocket()->setStreamFlowControlWindow(id, 200);
672   CHECK(eventBase_.loop());
673   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
674   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
675   hqSession_->closeWhenIdle();
676 }
677 
TEST_P(HQDownstreamSessionTest,OnFlowControlUpdateOnUnknownStream)678 TEST_P(HQDownstreamSessionTest, OnFlowControlUpdateOnUnknownStream) {
679   auto id = sendRequest();
680   auto handler = addSimpleStrictHandler();
681   handler->expectHeaders();
682   handler->expectEOM([&handler] { handler->sendReplyWithBody(200, 100); });
683   handler->expectDetachTransaction();
684 
685   // Call flowControlUpdate on a stream the Application doesn't know
686   socketDriver_->sock_->connCb_->onFlowControlUpdate(id + 4);
687   flushRequestsAndLoop();
688   hqSession_->closeWhenIdle();
689 }
690 
691 // This test does not work with header compression
TEST_P(HQDownstreamSessionTest,OnConnectionWindowPartialHeaders)692 TEST_P(HQDownstreamSessionTest, OnConnectionWindowPartialHeaders) {
693   // Only enough conn window to send headers initially.
694   auto id = sendRequest();
695   auto handler = addSimpleStrictHandler();
696   handler->expectHeaders();
697   handler->expectEOM([&handler] { handler->sendReplyWithBody(200, 100); });
698   handler->expectDetachTransaction();
699 
700   // Initialize the flow control window to less than the response body
701   socketDriver_->setConnectionFlowControlWindow(10 + numCtrlStreams_);
702   flushRequestsAndLoop();
703   // Check that the write side got blocked
704   socketDriver_->expectConnWritesPaused();
705   if (!IS_HQ) {
706     // We should have 10 bytes pending to be written out.
707     EXPECT_GE(socketDriver_->streams_[id].writeBuf.chainLength(), 10);
708   } else {
709     // We should have some bytes pending to be written out in the QPACK Encoder
710     // stream
711     EXPECT_GT(socketDriver_->streams_[kQPACKEncoderEgressStreamId]
712                   .writeBuf.chainLength(),
713               0);
714   }
715   EXPECT_FALSE(socketDriver_->streams_[id].writeEOF);
716   // Open the flow control window
717   socketDriver_->getSocket()->setConnectionFlowControlWindow(200);
718   CHECK(eventBase_.loop());
719   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
720   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
721   hqSession_->closeWhenIdle();
722 }
723 
TEST_P(HQDownstreamSessionTest,OnConnectionWindowPartialBody)724 TEST_P(HQDownstreamSessionTest, OnConnectionWindowPartialBody) {
725   flushRequestsAndLoop(); // loop once for SETTINGS, etc
726   // Only enough conn window to send headers initially.
727   auto id = sendRequest();
728   auto handler = addSimpleStrictHandler();
729   handler->expectHeaders();
730   handler->expectEOM([&handler] { handler->sendReplyWithBody(200, 100); });
731   // TODO: we should probably pause egress on conn limited.
732   // handler->expectEgressPaused();
733   // handler->expectEgressResumed();
734   handler->expectDetachTransaction();
735 
736   // Initialize the flow control window to less than the response body
737   socketDriver_->setConnectionFlowControlWindow(110 + numCtrlStreams_);
738   flushRequestsAndLoop();
739   // Check that the write side got blocked
740   socketDriver_->expectConnWritesPaused();
741   if (!IS_HQ) {
742     // We should have 110 bytes pending to be written out.
743     EXPECT_GE(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
744   } else {
745     // We should have some bytes pending to be written out in the QPACK Encoder
746     // stream
747     EXPECT_GT(socketDriver_->streams_[kQPACKEncoderEgressStreamId]
748                   .writeBuf.chainLength(),
749               0);
750     EXPECT_GT(qpackCodec_.getCompressionInfo().egress.headerTableSize_, 0);
751   }
752   EXPECT_FALSE(socketDriver_->streams_[id].writeEOF);
753   // Open the flow control window
754   socketDriver_->getSocket()->setConnectionFlowControlWindow(200 +
755                                                              numCtrlStreams_);
756   CHECK(eventBase_.loop());
757   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
758   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
759   hqSession_->closeWhenIdle();
760 }
761 
TEST_P(HQDownstreamSessionTest,SeparateEom)762 TEST_P(HQDownstreamSessionTest, SeparateEom) {
763   // Only enough conn window to send headers initially.
764   auto id = sendRequest();
765   auto handler = addSimpleStrictHandler();
766   handler->expectHeaders();
767   handler->expectEOM([&handler] {
768     handler->sendHeaders(200, 100);
769     handler->sendBody(100);
770   });
771   handler->expectDetachTransaction();
772   flushRequestsAndLoop();
773   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
774   EXPECT_FALSE(socketDriver_->streams_[id].writeEOF);
775 
776   handler->sendEOM();
777   // Open the flow control window
778   CHECK(eventBase_.loop());
779   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
780   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
781   hqSession_->closeWhenIdle();
782 }
783 
getSimpleRequestData()784 std::unique_ptr<folly::IOBuf> getSimpleRequestData() {
785   std::string req("GET / HTTP/1.1\nHost: www.facebook.com\n\n");
786   return folly::IOBuf::copyBuffer(req);
787 }
788 
estimateResponseSize(bool isHq,HTTPMessage msg,size_t contentLength,size_t chunkSize)789 std::tuple<size_t, size_t, size_t> estimateResponseSize(bool isHq,
790                                                         HTTPMessage msg,
791                                                         size_t contentLength,
792                                                         size_t chunkSize) {
793   folly::IOBufQueue estimateSizeBuf{folly::IOBufQueue::cacheChainLength()};
794   std::unique_ptr<HTTPCodec> codec;
795   QPACKCodec qpackCodec;
796   folly::IOBufQueue encoderWriteBuf{folly::IOBufQueue::cacheChainLength()};
797   folly::IOBufQueue decoderWriteBuf{folly::IOBufQueue::cacheChainLength()};
798   HTTPSettings dummySettings;
799   qpackCodec.setEncoderHeaderTableSize(kQPACKTestDecoderMaxTableSize);
800   if (isHq) {
801     codec = std::make_unique<hq::HQStreamCodec>(
802         0,
803         TransportDirection::DOWNSTREAM,
804         qpackCodec,
805         encoderWriteBuf,
806         decoderWriteBuf,
807         [] { return std::numeric_limits<uint64_t>::max(); },
808         dummySettings);
809   } else {
810     codec = std::make_unique<HTTP1xCodec>(TransportDirection::DOWNSTREAM, true);
811   }
812 
813   MockHTTPCodecCallback callback;
814   codec->setCallback(&callback);
815   auto txn = codec->createStream();
816 
817   if (!isHq) {
818     EXPECT_CALL(callback, onHeadersComplete(_, _));
819     EXPECT_CALL(callback, onMessageBegin(_, _));
820     codec->onIngress(*getSimpleRequestData());
821   }
822 
823   codec->generateHeader(estimateSizeBuf, txn, msg);
824   size_t currentLength = contentLength;
825 
826   bool chunking = (chunkSize != 0);
827   if (!chunking) {
828     chunkSize = std::numeric_limits<size_t>::max();
829   }
830   auto currentSize = estimateSizeBuf.chainLength();
831   while (currentLength > 0) {
832     uint32_t toSend = std::min(currentLength, chunkSize);
833     std::vector<uint8_t> buf;
834     buf.resize(toSend, 'a');
835     if (chunking) {
836       codec->generateChunkHeader(estimateSizeBuf, txn, toSend);
837     }
838     codec->generateBody(estimateSizeBuf,
839                         txn,
840                         folly::IOBuf::copyBuffer(buf),
841                         HTTPCodec::NoPadding,
842                         false);
843     if (chunking) {
844       codec->generateChunkTerminator(estimateSizeBuf, txn);
845     }
846     currentLength -= toSend;
847   }
848   size_t framingOverhead =
849       estimateSizeBuf.chainLength() - currentSize - contentLength;
850   currentSize = estimateSizeBuf.chainLength();
851   codec->generateEOM(estimateSizeBuf, txn);
852 
853   size_t eomSize = estimateSizeBuf.chainLength() - currentSize;
854   size_t estimatedSize = estimateSizeBuf.chainLength();
855   return std::tuple<size_t, size_t, size_t>(
856       estimatedSize, framingOverhead, eomSize);
857 }
858 
TEST_P(HQDownstreamSessionTest,PendingEomBuffered)859 TEST_P(HQDownstreamSessionTest, PendingEomBuffered) {
860   size_t contentLength = 100;
861   size_t chunkSize = 5;
862 
863   auto reply = makeResponse(200);
864   reply->setIsChunked(true);
865   size_t estimatedSize = 0;
866   size_t framingOverhead = 0;
867   size_t eomSize = 0;
868   std::tie(estimatedSize, framingOverhead, eomSize) =
869       estimateResponseSize(IS_HQ, *reply, contentLength, chunkSize);
870   // EOMs are 0 bytes in H3, but there is framing overhead of at least two
871   // bytes.
872   auto bytesWithheld = (IS_HQ) ? 2 : eomSize;
873 
874   auto id = sendRequest();
875   auto handler = addSimpleStrictHandler();
876   handler->expectHeaders();
877   handler->expectEOM([&handler, contentLength, chunkSize] {
878     handler->sendChunkedReplyWithBody(
879         200, contentLength, chunkSize, false, true);
880   });
881 
882   // Set the flow control window to be less than the EOM overhead added by
883   // the codec
884   socketDriver_->setStreamFlowControlWindow(id, estimatedSize - bytesWithheld);
885   flushRequestsAndLoop();
886   CHECK(eventBase_.loop());
887   EXPECT_GE(socketDriver_->streams_[id].writeBuf.chainLength(),
888             estimatedSize - bytesWithheld);
889   EXPECT_FALSE(socketDriver_->streams_[id].writeEOF);
890 
891   handler->expectDetachTransaction();
892   socketDriver_->getSocket()->setStreamFlowControlWindow(id, estimatedSize);
893 
894   CHECK(eventBase_.loop());
895   EXPECT_GE(socketDriver_->streams_[id].writeBuf.chainLength(), estimatedSize);
896   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
897   hqSession_->closeWhenIdle();
898 }
899 
TEST_P(HQDownstreamSessionTest,PendingEomQueuedNotFlushed)900 TEST_P(HQDownstreamSessionTest, PendingEomQueuedNotFlushed) {
901   auto reply = makeResponse(200);
902   reply->setWantsKeepalive(true);
903   reply->getHeaders().add(HTTP_HEADER_CONTENT_LENGTH,
904                           folly::to<std::string>(1));
905   size_t estimatedSize = 0;
906   size_t framingOverhead = 0;
907   size_t eomSize = 0;
908   std::tie(estimatedSize, framingOverhead, eomSize) =
909       estimateResponseSize(IS_HQ, *reply, 1, 0);
910   CHECK_EQ(eomSize, 0);
911   // There's no EOM and no framing overhead for h1q, withhold the body byte
912   auto bytesWithheld = IS_HQ ? framingOverhead : 1;
913 
914   auto id = sendRequest(getGetRequest());
915   auto handler = addSimpleStrictHandler();
916   handler->expectHeaders();
917   handler->expectEOM([&handler, this, id, estimatedSize, bytesWithheld] {
918     // Initialize the flow control window to just less than the
919     // estimated size of the eom codec which the codec generates..
920     socketDriver_->setStreamFlowControlWindow(id,
921                                               estimatedSize - bytesWithheld);
922     handler->sendReplyWithBody(200, 1);
923   });
924 
925   flushRequestsAndLoop();
926   CHECK(eventBase_.loop());
927   EXPECT_GE(socketDriver_->streams_[id].writeBuf.chainLength(),
928             estimatedSize - bytesWithheld);
929   EXPECT_FALSE(socketDriver_->streams_[id].writeEOF);
930 
931   handler->expectDetachTransaction();
932   socketDriver_->getSocket()->setStreamFlowControlWindow(id, estimatedSize);
933 
934   CHECK(eventBase_.loop());
935   EXPECT_GE(socketDriver_->streams_[id].writeBuf.chainLength(), estimatedSize);
936   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
937   hqSession_->closeWhenIdle();
938 }
939 
TEST_P(HQDownstreamSessionTestHQ,PendingEomQueuedNotFlushedConn)940 TEST_P(HQDownstreamSessionTestHQ, PendingEomQueuedNotFlushedConn) {
941   // flush control streams first
942   flushRequestsAndLoop();
943   CHECK(eventBase_.loop());
944 
945   auto reply = makeResponse(200);
946   reply->setWantsKeepalive(true);
947   size_t estimatedSize = 0;
948   size_t framingOverhead = 0;
949   size_t eomSize = 0;
950   std::tie(estimatedSize, framingOverhead, eomSize) =
951       estimateResponseSize(IS_HQ, *reply, 1, 0);
952 
953   // No EOM yet
954   auto id = sendRequest(getGetRequest(), false);
955   auto handler = addSimpleStrictHandler();
956   handler->expectHeaders([&handler] { handler->sendHeaders(200, 1); });
957   flushRequestsAndLoopN(1);
958 
959   socketDriver_->addReadEOF(id, std::chrono::milliseconds(0));
960   handler->expectEOM([&handler, this] {
961     handler->txn_->sendBody(makeBuf(1));
962     handler->txn_->sendEOM();
963     socketDriver_->setConnectionFlowControlWindow(1);
964   });
965 
966   // Set the conn flow control to be enough for the body byte but not enough
967   // for the framing overhead
968   auto remaining = framingOverhead + eomSize;
969   flushRequestsAndLoop();
970   CHECK(eventBase_.loop());
971   EXPECT_GE(socketDriver_->streams_[id].writeBuf.chainLength(),
972             estimatedSize - remaining);
973   EXPECT_FALSE(socketDriver_->streams_[id].writeEOF);
974 
975   handler->expectDetachTransaction();
976   for (size_t i = 0; i < remaining; i++) {
977     socketDriver_->getSocket()->setConnectionFlowControlWindow(1);
978 
979     CHECK(eventBase_.loop());
980     EXPECT_GE(socketDriver_->streams_[id].writeBuf.chainLength(),
981               estimatedSize - remaining + i);
982 
983     EXPECT_TRUE(socketDriver_->streams_[id].writeEOF != (i < remaining - 1));
984   }
985 
986   // Need flow control for goaway
987   socketDriver_->getSocket()->setConnectionFlowControlWindow(100);
988   hqSession_->closeWhenIdle();
989 }
990 
TEST_P(HQDownstreamSessionTest,SendEomLaterChunked)991 TEST_P(HQDownstreamSessionTest, SendEomLaterChunked) {
992   size_t contentLength = 100;
993   size_t chunkSize = 10;
994 
995   auto id = sendRequest();
996   auto handler = addSimpleStrictHandler();
997   handler->expectHeaders([&handler, contentLength, chunkSize] {
998     handler->sendChunkedReplyWithBody(
999         200, contentLength, chunkSize, false, false);
1000   });
1001   handler->expectEOM([&handler] { handler->sendEOM(); });
1002   handler->expectDetachTransaction();
1003 
1004   flushRequestsAndLoop();
1005   CHECK(eventBase_.loop());
1006   EXPECT_GE(socketDriver_->streams_[id].writeBuf.chainLength(), contentLength);
1007   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
1008   hqSession_->closeWhenIdle();
1009 }
1010 
TEST_P(HQDownstreamSessionTest,SendEomLater)1011 TEST_P(HQDownstreamSessionTest, SendEomLater) {
1012   size_t contentLength = 100;
1013   auto id = sendRequest();
1014   auto handler = addSimpleStrictHandler();
1015   handler->expectHeaders([&handler, contentLength] {
1016     handler->sendHeaders(200, contentLength);
1017     handler->sendBody(contentLength);
1018   });
1019   handler->expectEOM([&handler] { handler->sendEOM(); });
1020   handler->expectDetachTransaction();
1021 
1022   flushRequestsAndLoop();
1023   CHECK(eventBase_.loop());
1024   EXPECT_GE(socketDriver_->streams_[id].writeBuf.chainLength(), contentLength);
1025   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
1026   hqSession_->closeWhenIdle();
1027 }
1028 
1029 // Invoke notifyPendingShutdown, which will include an outgoing
1030 // Connection: close header on the next outbound headers.  The next incoming
1031 // request containing a Connection: close header will complete the drain state
1032 // machine
1033 // NOTE: this behavior is only valid for basic h1q
TEST_P(HQDownstreamSessionTestH1qv1,ShutdownNotify)1034 TEST_P(HQDownstreamSessionTestH1qv1, ShutdownNotify) {
1035   hqSession_->notifyPendingShutdown();
1036   EXPECT_FALSE(hqSession_->isReusable());
1037   auto idh1 = checkRequest();
1038   flushRequestsAndLoop();
1039   // we should write Connection: close in the outgoing headers
1040   auto resp =
1041       socketDriver_->streams_[idh1.first].writeBuf.move()->moveToFbString();
1042   EXPECT_TRUE(resp.find("Connection: close"));
1043 
1044   // Add connection: close
1045   auto req = getGetRequest();
1046   req.getHeaders().set(HTTP_HEADER_CONNECTION, "close");
1047   auto idh2 = checkRequest(req);
1048   flushRequestsAndLoop();
1049 }
1050 
1051 // closeWhenIdle on an idle conn - immediate delete
TEST_P(HQDownstreamSessionTest,ShutdownCloseIdle)1052 TEST_P(HQDownstreamSessionTest, ShutdownCloseIdle) {
1053   EXPECT_TRUE(hqSession_->isReusable());
1054   hqSession_->closeWhenIdle();
1055 }
1056 
1057 // closeWhenIdle invoked when a request is open, delete happens when it finishes
TEST_P(HQDownstreamSessionTest,ShutdownCloseIdleReq)1058 TEST_P(HQDownstreamSessionTest, ShutdownCloseIdleReq) {
1059   sendRequest();
1060   auto handler = addSimpleStrictHandler();
1061   handler->expectHeaders([this] {
1062     hqSession_->closeWhenIdle();
1063     EXPECT_TRUE(hqSession_->isClosing());
1064   });
1065   handler->expectEOM([&handler] { handler->sendReplyWithBody(200, 100); });
1066   handler->expectDetachTransaction();
1067   flushRequestsAndLoop();
1068 }
1069 
1070 // Peer initiates shutdown by sending Connection: close
1071 // NOTE: this behavior is only valid for basic h1q
TEST_P(HQDownstreamSessionTestH1qv1,ShutdownFromPeer)1072 TEST_P(HQDownstreamSessionTestH1qv1, ShutdownFromPeer) {
1073   // client initiates shutdown by including Connection: close
1074   auto req = getGetRequest();
1075   req.getHeaders().set(HTTP_HEADER_CONNECTION, "close");
1076   auto idh = checkRequest(req);
1077   flushRequestsAndLoop();
1078 
1079   // session deleted when server emits connection: close
1080 }
1081 
1082 // dropConnection invoked while a request being processed, it receives an
1083 // error
TEST_P(HQDownstreamSessionTest,ShutdownDropWithReq)1084 TEST_P(HQDownstreamSessionTest, ShutdownDropWithReq) {
1085   sendRequest();
1086   auto handler = addSimpleStrictHandler();
1087   handler->expectHeaders();
1088   handler->expectEOM();
1089   handler->expectError();
1090   handler->expectDetachTransaction();
1091   flushRequestsAndLoopN(1);
1092   hqSession_->dropConnection();
1093 }
1094 
1095 // dropConnection invoked while a request is partial, it receives an
1096 // error from the transport
TEST_P(HQDownstreamSessionTest,ShutdownDropWithPartialReq)1097 TEST_P(HQDownstreamSessionTest, ShutdownDropWithPartialReq) {
1098   sendRequest(getPostRequest(10), false);
1099   auto handler = addSimpleStrictHandler();
1100   handler->expectHeaders();
1101   handler->expectError();
1102   handler->expectDetachTransaction();
1103   flushRequestsAndLoopN(1);
1104   hqSession_->dropConnection();
1105 }
1106 
1107 // Call drop connection while there are bytes pending to egress
TEST_P(HQDownstreamSessionTest,DropConnectionPendingEgress)1108 TEST_P(HQDownstreamSessionTest, DropConnectionPendingEgress) {
1109   // NOTE: this test assumes that dropConnection() gets called by the handler
1110   // before the session has the chance to write data.
1111   // This is not true anymore when there are control streams
1112   // So let's just loop a bit to give time to the Downstream Session to send the
1113   // control stream preface
1114   if (!IS_H1Q_FB_V1) {
1115     flushRequestsAndLoop();
1116   }
1117 
1118   sendRequest(getGetRequest());
1119   auto handler = addSimpleStrictHandler();
1120   handler->expectHeaders([&handler, this] {
1121     handler->sendReplyWithBody(200, 1);
1122     eventBase_.runInLoop([this] { hqSession_->dropConnection(); }, true);
1123   });
1124   handler->expectEOM();
1125   handler->expectError();
1126   handler->expectDetachTransaction();
1127   flushRequestsAndLoop();
1128 }
1129 
TEST_P(HQDownstreamSessionTest,TestInfoCallbacks)1130 TEST_P(HQDownstreamSessionTest, TestInfoCallbacks) {
1131   folly::Optional<HTTPCodec::StreamID> id = sendRequest();
1132   auto handler = addSimpleStrictHandler();
1133   handler->expectHeaders();
1134   handler->expectEOM([&handler] { handler->sendReplyWithBody(200, 100); });
1135   handler->expectDetachTransaction();
1136   EXPECT_CALL(infoCb_, onRequestBegin(_)).Times(1);
1137   EXPECT_CALL(infoCb_, onActivateConnection(_)).Times(1);
1138   EXPECT_CALL(infoCb_, onIngressMessage(_, _)).Times(1);
1139   EXPECT_CALL(infoCb_, onRead(_, _, id)).Times(AtLeast(2));
1140   EXPECT_CALL(infoCb_, onWrite(_, _)).Times(AtLeast(1));
1141   EXPECT_CALL(infoCb_, onDestroy(_)).Times(1);
1142   EXPECT_CALL(infoCb_, onRequestEnd(_, _)).Times(1);
1143   EXPECT_CALL(infoCb_, onDeactivateConnection(_)).Times(1);
1144   flushRequestsAndLoop();
1145   hqSession_->dropConnection();
1146 }
1147 
TEST_P(HQDownstreamSessionTest,NotifyDropNoStreams)1148 TEST_P(HQDownstreamSessionTest, NotifyDropNoStreams) {
1149   hqSession_->notifyPendingShutdown();
1150   eventBase_.loop();
1151   // no need to explicitly drop in H1Q-V2
1152   if (IS_H1Q_FB_V1) {
1153     hqSession_->dropConnection();
1154   }
1155 }
1156 
TEST_P(HQDownstreamSessionTest,ShutdownDropWithUnflushedResp)1157 TEST_P(HQDownstreamSessionTest, ShutdownDropWithUnflushedResp) {
1158   auto id = sendRequest();
1159   // should be enough to trick HQSession into serializing the EOM into
1160   // HQStreamTransport but without enough to send it.
1161   // HTTP/3 has an extra grease frame on the first transaction
1162   socketDriver_->setStreamFlowControlWindow(id, IS_HQ ? 209 : 206);
1163   auto handler = addSimpleStrictHandler();
1164   handler->expectHeaders();
1165   handler->expectEOM([&handler] {
1166     handler->sendChunkedReplyWithBody(200, 100, 100, false, true);
1167   });
1168   handler->expectDetachTransaction();
1169   flushRequestsAndLoopN(1);
1170   hqSession_->dropConnection();
1171 }
1172 
1173 // rst_stream while a request is partial, terminate cleanly
TEST_P(HQDownstreamSessionTest,Cancel)1174 TEST_P(HQDownstreamSessionTest, Cancel) {
1175   auto id = sendRequest(getPostRequest(10), false);
1176   auto handler = addSimpleStrictHandler();
1177   handler->expectHeaders([this, id] {
1178     socketDriver_->addReadError(id,
1179                                 HTTP3::ErrorCode::HTTP_INTERNAL_ERROR,
1180                                 std::chrono::milliseconds(0));
1181     hqSession_->closeWhenIdle();
1182   });
1183   handler->expectError();
1184   handler->expectDetachTransaction();
1185   flushRequestsAndLoop();
1186   EXPECT_EQ(*socketDriver_->streams_[id].error,
1187             HTTP3::ErrorCode::HTTP_REQUEST_CANCELLED);
1188 }
1189 
TEST_P(HQDownstreamSessionTestHQ,EndOfStreamWithPartialFrame)1190 TEST_P(HQDownstreamSessionTestHQ, EndOfStreamWithPartialFrame) {
1191   auto id = sendRequest(getPostRequest(10), false);
1192   auto& request = getStream(id);
1193   // generate body + EOM, but trim the last byte
1194   folly::IOBufQueue writeBuf{folly::IOBufQueue::cacheChainLength()};
1195   request.codec->generateBody(
1196       writeBuf, request.id, makeBuf(10), HTTPCodec::NoPadding, true);
1197   request.buf.append(writeBuf.split(writeBuf.chainLength() - 1));
1198   request.readEOF = true;
1199   auto handler = addSimpleStrictHandler();
1200   handler->expectHeaders();
1201   handler->expectBody();
1202   handler->expectError();
1203   handler->expectDetachTransaction();
1204   flushRequestsAndLoop();
1205   EXPECT_EQ(*socketDriver_->streams_[kConnectionStreamId].error,
1206             HTTP3::ErrorCode::HTTP_FRAME_ERROR);
1207 }
1208 
1209 // read() returns a LocalErrorCode
TEST_P(HQDownstreamSessionTest,ReadErrorSync)1210 TEST_P(HQDownstreamSessionTest, ReadErrorSync) {
1211   auto id = sendRequest(getPostRequest(10), false);
1212   auto handler = addSimpleStrictHandler();
1213   handler->expectHeaders([this, id] {
1214     // mark the stream in read error and trigger a readAvailable call
1215     socketDriver_->setReadError(id);
1216     // This is just to trigger readAvailable
1217     socketDriver_->addReadEvent(id, makeBuf(10), milliseconds(0));
1218     hqSession_->closeWhenIdle();
1219   });
1220   handler->expectError();
1221   handler->expectDetachTransaction();
1222   flushRequestsAndLoop();
1223 }
1224 
1225 // Connection dies in error with an open stream
TEST_P(HQDownstreamSessionTest,TransportErrorWithOpenStream)1226 TEST_P(HQDownstreamSessionTest, TransportErrorWithOpenStream) {
1227   sendRequest(getPostRequest(10), false);
1228   auto handler = addSimpleStrictHandler();
1229   handler->expectHeaders([this] {
1230     eventBase_.runInLoop([this] {
1231       // This should error out the stream first, then destroy the session
1232       socketDriver_->deliverConnectionError(
1233           std::make_pair(quic::TransportErrorCode::PROTOCOL_VIOLATION, ""));
1234     });
1235   });
1236   handler->expectError([](const HTTPException& ex) {
1237     EXPECT_EQ(ex.getProxygenError(), kErrorConnectionReset);
1238   });
1239   handler->expectDetachTransaction();
1240   EXPECT_CALL(infoCb_, onConnectionError(_)).Times(0);
1241   flushRequestsAndLoop();
1242 }
1243 
1244 // writeChain() returns a LocalErrorCode with a half-closed stream
TEST_P(HQDownstreamSessionTest,WriteError)1245 TEST_P(HQDownstreamSessionTest, WriteError) {
1246   auto id = sendRequest();
1247   auto handler = addSimpleStrictHandler();
1248   handler->expectHeaders();
1249   handler->expectEOM([&handler, this, id] {
1250     handler->sendHeaders(200, 100);
1251     socketDriver_->setWriteError(id);
1252     hqSession_->closeWhenIdle();
1253   });
1254   handler->expectError([](const HTTPException& ex) {
1255     EXPECT_EQ(ex.getProxygenError(), kErrorWrite);
1256   });
1257   handler->expectDetachTransaction();
1258   flushRequestsAndLoop();
1259 }
1260 
1261 // writeChain() returns a LocalErrorCode with stream open both ways
TEST_P(HQDownstreamSessionTest,WriteErrorPartialReq)1262 TEST_P(HQDownstreamSessionTest, WriteErrorPartialReq) {
1263   auto id = sendRequest(getPostRequest(10), false);
1264   auto handler = addSimpleStrictHandler();
1265   handler->expectHeaders([&handler, this, id] {
1266     handler->sendReplyWithBody(200, 100);
1267     socketDriver_->setWriteError(id);
1268     hqSession_->closeWhenIdle();
1269   });
1270   handler->expectError();
1271   handler->expectDetachTransaction();
1272   flushRequestsAndLoop();
1273 }
1274 
1275 // Test write on non writable stream
TEST_P(HQDownstreamSessionTest,WriteNonWritableStream)1276 TEST_P(HQDownstreamSessionTest, WriteNonWritableStream) {
1277   auto idh = checkRequest();
1278   // delay the eof event so that we won't have to loop
1279   flushRequestsAndLoop(false, milliseconds(0), milliseconds(50), [&] {
1280     // Force the read in the loop, so that this will trigger a write.
1281     eventBase_.loop();
1282     socketDriver_->flowControlAccess_.clear();
1283   });
1284   // Once the eof is written and no more bytes remain, we should never
1285   // call flow control methods.
1286   EXPECT_EQ(socketDriver_->flowControlAccess_.count(idh.first), 0);
1287   hqSession_->closeWhenIdle();
1288 }
1289 
TEST_P(HQDownstreamSessionTest,WriteErrorFlowControl)1290 TEST_P(HQDownstreamSessionTest, WriteErrorFlowControl) {
1291   auto id = sendRequest(getPostRequest(10), false);
1292   auto handler = addSimpleStrictHandler();
1293   handler->expectHeaders([&handler, this, id] {
1294     handler->sendReplyWithBody(200, 100);
1295     socketDriver_->forceStreamClose(id);
1296     hqSession_->closeWhenIdle();
1297   });
1298   handler->expectError();
1299   handler->expectDetachTransaction();
1300   flushRequestsAndLoop();
1301 }
1302 
1303 // Connection error on idle connection
TEST_P(HQDownstreamSessionTest,ConnectionErrorIdle)1304 TEST_P(HQDownstreamSessionTest, ConnectionErrorIdle) {
1305   socketDriver_->deliverConnectionError(
1306       std::make_pair(quic::TransportErrorCode::PROTOCOL_VIOLATION, ""));
1307   eventBase_.loopOnce();
1308 }
1309 
1310 // Connection End on an idle connection
TEST_P(HQDownstreamSessionTest,ConnectionEnd)1311 TEST_P(HQDownstreamSessionTest, ConnectionEnd) {
1312   nextStreamId();
1313   socketDriver_->addOnConnectionEndEvent(10);
1314   CHECK(eventBase_.loop());
1315 }
1316 
1317 // invalid HTTP on stream before headers
1318 // Might need an HQ test with unparseable junk?
TEST_P(HQDownstreamSessionTestH1q,BadHttp)1319 TEST_P(HQDownstreamSessionTestH1q, BadHttp) {
1320   auto id = nextStreamId();
1321   auto buf = IOBuf::create(10);
1322   memset(buf->writableData(), 'a', 10);
1323   buf->append(10);
1324   testing::StrictMock<MockHTTPHandler> handler;
1325   EXPECT_CALL(getMockController(), getParseErrorHandler(_, _, _))
1326       .WillOnce(Return(&handler));
1327   EXPECT_CALL(handler, setTransaction(testing::_))
1328       .WillOnce(testing::SaveArg<0>(&handler.txn_));
1329   handler.expectError([&handler](const HTTPException& ex) {
1330     EXPECT_TRUE(ex.hasHttpStatusCode());
1331     handler.sendReplyWithBody(ex.getHttpStatusCode(), 100);
1332   });
1333   handler.expectDetachTransaction();
1334   socketDriver_->addReadEvent(id, std::move(buf), milliseconds(0));
1335   socketDriver_->addReadEOF(id);
1336 
1337   flushRequestsAndLoop();
1338   hqSession_->closeWhenIdle();
1339 }
1340 
1341 // Invalid HTTP headers
TEST_P(HQDownstreamSessionTestH1q,BadHttpHeaders)1342 TEST_P(HQDownstreamSessionTestH1q, BadHttpHeaders) {
1343   auto id = nextStreamId();
1344   auto buf = IOBuf::copyBuffer("GET", 3);
1345   socketDriver_->addReadEvent(id, std::move(buf), milliseconds(0));
1346   socketDriver_->addReadEOF(id);
1347   testing::StrictMock<MockHTTPHandler> handler;
1348   EXPECT_CALL(getMockController(), getParseErrorHandler(_, _, _))
1349       .WillOnce(Return(&handler));
1350   EXPECT_CALL(handler, setTransaction(testing::_))
1351       .WillOnce(testing::SaveArg<0>(&handler.txn_));
1352   handler.expectError([&handler](const HTTPException& ex) {
1353     EXPECT_TRUE(ex.hasHttpStatusCode());
1354     handler.sendReplyWithBody(ex.getHttpStatusCode(), 100);
1355   });
1356   handler.expectDetachTransaction();
1357 
1358   flushRequestsAndLoop();
1359   hqSession_->closeWhenIdle();
1360 }
1361 
TEST_P(HQDownstreamSessionTestHQ,BadHttpHeaders)1362 TEST_P(HQDownstreamSessionTestHQ, BadHttpHeaders) {
1363   auto id = nextStreamId();
1364   std::array<uint8_t, 4> badHeaders{0x01, 0x02, 0x00, 0x81};
1365   auto buf = folly::IOBuf::copyBuffer(badHeaders.data(), badHeaders.size());
1366   socketDriver_->addReadEvent(id, std::move(buf), milliseconds(0));
1367   socketDriver_->addReadEOF(id);
1368   /* T35641532 -- Should QPACK errors be a session errors ?
1369   testing::StrictMock<MockHTTPHandler> handler;
1370   EXPECT_CALL(getMockController(), getParseErrorHandler(_, _, _))
1371       .WillOnce(Return(&handler));
1372   EXPECT_CALL(handler, setTransaction(testing::_))
1373       .WillOnce(testing::SaveArg<0>(&handler.txn_));
1374   handler.expectError();
1375   handler.expectDetachTransaction();
1376   */
1377   flushRequestsAndLoop();
1378   // The QPACK error will cause the connection to get dropped
1379 }
1380 
TEST_P(HQDownstreamSessionTest,BadHttpStrict)1381 TEST_P(HQDownstreamSessionTest, BadHttpStrict) {
1382   hqSession_->setStrictValidation(true);
1383   sendRequest(getGetRequest("/foo\xff"));
1384   testing::StrictMock<MockHTTPHandler> handler;
1385   EXPECT_CALL(getMockController(), getParseErrorHandler(_, _, _))
1386       .WillOnce(Return(&handler));
1387   EXPECT_CALL(handler, setTransaction(testing::_))
1388       .WillOnce(testing::SaveArg<0>(&handler.txn_));
1389   handler.expectError([&handler](const HTTPException& ex) {
1390     EXPECT_TRUE(ex.hasHttpStatusCode());
1391     handler.sendReplyWithBody(ex.getHttpStatusCode(), 100);
1392   });
1393   handler.expectDetachTransaction();
1394 
1395   flushRequestsAndLoop();
1396   hqSession_->closeWhenIdle();
1397 }
1398 
TEST_P(HQDownstreamSessionTest,BadHttpHeadersStrict)1399 TEST_P(HQDownstreamSessionTest, BadHttpHeadersStrict) {
1400   hqSession_->setStrictValidation(true);
1401   auto req = getGetRequest("/foo");
1402   req.getHeaders().set("Foo", "bad value\xff");
1403   sendRequest(req);
1404   testing::StrictMock<MockHTTPHandler> handler;
1405   EXPECT_CALL(getMockController(), getParseErrorHandler(_, _, _))
1406       .WillOnce(Return(&handler));
1407   EXPECT_CALL(handler, setTransaction(testing::_))
1408       .WillOnce(testing::SaveArg<0>(&handler.txn_));
1409   handler.expectError([&handler](const HTTPException& ex) {
1410     EXPECT_TRUE(ex.hasHttpStatusCode());
1411     handler.sendReplyWithBody(ex.getHttpStatusCode(), 100);
1412   });
1413   handler.expectDetachTransaction();
1414 
1415   flushRequestsAndLoop();
1416   hqSession_->closeWhenIdle();
1417 }
1418 
1419 // NOTE: this behavior is only valid for basic h1q
TEST_P(HQDownstreamSessionTestH1qv1,ShutdownWithTwoTxn)1420 TEST_P(HQDownstreamSessionTestH1qv1, ShutdownWithTwoTxn) {
1421   sendRequest();
1422   auto req = getGetRequest();
1423   req.getHeaders().set(HTTP_HEADER_CONNECTION, "close");
1424   sendRequest(req);
1425   auto handler1 = addSimpleStrictHandler();
1426   auto handler2 = addSimpleStrictHandler();
1427   handler1->expectHeaders();
1428   handler1->expectEOM([&handler1] { handler1->sendReplyWithBody(200, 100); });
1429   handler1->expectDetachTransaction();
1430   handler2->expectHeaders();
1431   handler2->expectEOM([&handler2] { handler2->sendReplyWithBody(200, 100); });
1432   handler2->expectDetachTransaction();
1433   flushRequestsAndLoop();
1434 }
1435 
TEST_P(HQDownstreamSessionTestH1q,SendEmptyResponseHeadersOnly)1436 TEST_P(HQDownstreamSessionTestH1q, SendEmptyResponseHeadersOnly) {
1437   HTTPMessage req;
1438   req.setMethod(HTTPMethod::GET);
1439   req.setHTTPVersion(0, 9);
1440   req.setURL("/");
1441   sendRequest(req);
1442   auto handler = addSimpleStrictHandler();
1443   handler->expectHeaders();
1444   handler->expectEOM([&] {
1445     HTTPMessage resp;
1446     resp.setStatusCode(200);
1447     resp.setHTTPVersion(0, 9);
1448     handler->txn_->sendHeaders(resp);
1449     eventBase_.runAfterDelay([&] { handler->txn_->sendEOM(); }, 10);
1450   });
1451   handler->expectDetachTransaction();
1452   flushRequestsAndLoop();
1453   hqSession_->closeWhenIdle();
1454 }
1455 
TEST_P(HQDownstreamSessionTest,SendFinOnly)1456 TEST_P(HQDownstreamSessionTest, SendFinOnly) {
1457   HTTPMessage req;
1458   req.setMethod(HTTPMethod::GET);
1459   req.setHTTPVersion(0, 9);
1460   req.setURL("/");
1461   sendRequest(req);
1462   auto handler = addSimpleStrictHandler();
1463   handler->expectHeaders();
1464   handler->expectEOM([&handler] {
1465     HTTPMessage resp;
1466     resp.setStatusCode(200);
1467     resp.setHTTPVersion(0, 9);
1468     handler->txn_->sendHeaders(resp);
1469     handler->txn_->sendEOM();
1470   });
1471   handler->expectDetachTransaction();
1472   flushRequestsAndLoop();
1473   hqSession_->closeWhenIdle();
1474 }
1475 
TEST_P(HQDownstreamSessionTest,PauseResume)1476 TEST_P(HQDownstreamSessionTest, PauseResume) {
1477   auto id = sendRequest(getPostRequest(65547), false);
1478   auto& request = getStream(id);
1479   auto handler = addSimpleStrictHandler();
1480   // Handler pauses as soon as it receives headers.  Nothing buffered so
1481   // transport continues reading
1482   handler->expectHeaders([&handler] { handler->txn_->pauseIngress(); });
1483   flushRequestsAndLoop();
1484   EXPECT_FALSE(socketDriver_->isStreamPaused(id));
1485 
1486   // Generate some body, but over the limit.  The session (currently) reads
1487   // everything from the transport, so it will exceed the limit and pause
1488   request.codec->generateBody(
1489       request.buf, request.id, makeBuf(65537), HTTPCodec::NoPadding, true);
1490   flushRequestsAndLoop();
1491   EXPECT_TRUE(socketDriver_->isStreamPaused(id));
1492   EXPECT_TRUE(socketDriver_->streams_[id].readBuf.empty());
1493 
1494   // Now send some more data, all buffered
1495   request.codec->generateBody(
1496       request.buf, request.id, makeBuf(10), HTTPCodec::NoPadding, true);
1497   request.readEOF = true;
1498   flushRequestsAndLoop();
1499   EXPECT_FALSE(socketDriver_->streams_[id].readBuf.empty());
1500 
1501   auto id2 = sendRequest();
1502   auto handler2 = addSimpleStrictHandler();
1503   // stream 2 will start paused at the transport, so even headers are parsed.
1504   flushRequestsAndLoopN(1);
1505   EXPECT_FALSE(socketDriver_->streams_[id2].readBuf.empty());
1506   EXPECT_TRUE(socketDriver_->isStreamPaused(id2));
1507   hqSession_->closeWhenIdle();
1508 
1509   // After resume, body (2 calls) and EOM delivered
1510   EXPECT_CALL(*handler, onBodyWithOffset(_, _)).Times(2);
1511   handler->expectEOM([&handler] { handler->sendReplyWithBody(200, 100); });
1512   handler->expectDetachTransaction();
1513   handler2->expectHeaders(
1514       [&handler2] { handler2->sendReplyWithBody(200, 100); });
1515   handler2->expectEOM();
1516   handler2->expectDetachTransaction();
1517   handler->txn_->resumeIngress();
1518   eventBase_.loop();
1519 }
1520 
TEST_P(HQDownstreamSessionTest,EnqueuedAbort)1521 TEST_P(HQDownstreamSessionTest, EnqueuedAbort) {
1522   sendRequest();
1523   auto handler = addSimpleStrictHandler();
1524   handler->expectHeaders();
1525   handler->expectEOM([&handler] {
1526     handler->sendHeaders(200, 100);
1527     handler->txn_->sendBody(makeBuf(100));
1528     handler->txn_->sendAbort();
1529   });
1530   handler->expectDetachTransaction();
1531   flushRequestsAndLoop();
1532   hqSession_->closeWhenIdle();
1533 }
1534 
TEST_P(HQDownstreamSessionTest,TransactionTimeout)1535 TEST_P(HQDownstreamSessionTest, TransactionTimeout) {
1536   sendRequest(getPostRequest(10), false);
1537   auto handler = addSimpleStrictHandler();
1538   handler->expectHeaders([&handler] {
1539     // fire the timeout as soon as receiving the headers
1540     handler->txn_->setIdleTimeout(std::chrono::milliseconds(0));
1541   });
1542   handler->expectError([&handler](const HTTPException& ex) {
1543     EXPECT_FALSE(ex.hasHttpStatusCode());
1544     handler->terminate();
1545   });
1546   handler->expectDetachTransaction();
1547   flushRequestsAndLoop();
1548   hqSession_->closeWhenIdle();
1549 }
1550 
TEST_P(HQDownstreamSessionTestH1q,ManagedTimeoutReadReset)1551 TEST_P(HQDownstreamSessionTestH1q, ManagedTimeoutReadReset) {
1552   std::chrono::milliseconds connIdleTimeout{200};
1553   auto connManager = wangle::ConnectionManager::makeUnique(
1554       &eventBase_, connIdleTimeout, nullptr);
1555   connManager->addConnection(hqSession_, true);
1556   HQSession::DestructorGuard dg(hqSession_);
1557   auto handler = addSimpleStrictHandler();
1558   auto id = sendRequest(getPostRequest(10), false);
1559   auto& request = getStream(id);
1560   request.codec->generateBody(
1561       request.buf, request.id, makeBuf(3), HTTPCodec::NoPadding, true);
1562   request.readEOF = false;
1563   eventBase_.runAfterDelay(
1564       [&] {
1565         request.codec->generateBody(
1566             request.buf, request.id, makeBuf(3), HTTPCodec::NoPadding, true);
1567         request.readEOF = false;
1568         flushRequests();
1569       },
1570       100);
1571   eventBase_.runAfterDelay(
1572       [&] {
1573         EXPECT_NE(hqSession_->getConnectionCloseReason(),
1574                   ConnectionCloseReason::TIMEOUT);
1575         request.codec->generateBody(
1576             request.buf, request.id, makeBuf(4), HTTPCodec::NoPadding, true);
1577         request.readEOF = true;
1578         flushRequests();
1579       },
1580       250);
1581   handler->expectEOM([&handler] { handler->sendReplyWithBody(200, 100); });
1582   handler->expectHeaders();
1583   EXPECT_CALL(*handler, onBodyWithOffset(testing::_, testing::_)).Times(3);
1584   handler->expectDetachTransaction();
1585   flushRequestsAndLoop();
1586 }
1587 
TEST_P(HQDownstreamSessionTestHQ,ManagedTimeoutUnidirectionalReadReset)1588 TEST_P(HQDownstreamSessionTestHQ, ManagedTimeoutUnidirectionalReadReset) {
1589   std::chrono::milliseconds connIdleTimeout{200};
1590   auto connManager = wangle::ConnectionManager::makeUnique(
1591       &eventBase_, connIdleTimeout, nullptr);
1592   connManager->addConnection(hqSession_, true);
1593   HQSession::DestructorGuard dg(hqSession_);
1594 
1595   // Just keep sending instructions to set the dynamic table capacity
1596   std::array<uint8_t, 1> data1{0b00100111};
1597   auto buf1 = folly::IOBuf::copyBuffer(data1.data(), data1.size());
1598   socketDriver_->addReadEvent(6, std::move(buf1), milliseconds(0));
1599   std::array<uint8_t, 1> data2{0b00100110};
1600   auto buf2 = folly::IOBuf::copyBuffer(data2.data(), data2.size());
1601   socketDriver_->addReadEvent(6, std::move(buf2), milliseconds(100));
1602   // Check that the session did not timeout, yet
1603   eventBase_.runAfterDelay(
1604       [&] {
1605         EXPECT_NE(hqSession_->getConnectionCloseReason(),
1606                   ConnectionCloseReason::TIMEOUT);
1607       },
1608       250);
1609 
1610   flushRequestsAndLoop();
1611 }
1612 
TEST_P(HQDownstreamSessionTest,ManagedTimeoutActiveStreams)1613 TEST_P(HQDownstreamSessionTest, ManagedTimeoutActiveStreams) {
1614   std::chrono::milliseconds connIdleTimeout{300};
1615   auto connManager = wangle::ConnectionManager::makeUnique(
1616       &eventBase_, connIdleTimeout, nullptr);
1617   HQSession::DestructorGuard dg(hqSession_);
1618   sendRequest(getPostRequest(10), false);
1619   auto handler = addSimpleStrictHandler();
1620   connManager->addConnection(hqSession_, true);
1621   // Txn idle timer is > connIdleTimeout
1622   auto lastErrorTime = std::chrono::steady_clock::now();
1623   handler->expectHeaders([&handler] {
1624     handler->txn_->setIdleTimeout(std::chrono::milliseconds(500));
1625   });
1626   handler->expectError(
1627       [&handler, this, &lastErrorTime](const HTTPException& ex) {
1628         // we should txn timeout
1629         EXPECT_FALSE(ex.hasHttpStatusCode());
1630         EXPECT_EQ(ex.getProxygenError(), kErrorTimeout);
1631         EXPECT_TRUE(hqSession_->isScheduled());
1632         hqSession_->cancelTimeout();
1633         handler->terminate();
1634         lastErrorTime = std::chrono::steady_clock::now();
1635       });
1636   handler->expectDetachTransaction();
1637   flushRequestsAndLoop();
1638   auto now = std::chrono::steady_clock::now();
1639   EXPECT_GE(
1640       std::chrono::duration_cast<std::chrono::milliseconds>(now - lastErrorTime)
1641           .count(),
1642       connIdleTimeout.count());
1643   // Connection timeouts in the loop and closes.
1644   EXPECT_EQ(hqSession_->getConnectionCloseReason(),
1645             ConnectionCloseReason::TIMEOUT);
1646 }
1647 
TEST_P(HQDownstreamSessionTest,ManagedTimeoutNoStreams)1648 TEST_P(HQDownstreamSessionTest, ManagedTimeoutNoStreams) {
1649   std::chrono::milliseconds connIdleTimeout{300};
1650   auto connManager = wangle::ConnectionManager::makeUnique(
1651       &eventBase_, connIdleTimeout, nullptr);
1652   HQSession::DestructorGuard dg(hqSession_);
1653   connManager->addConnection(hqSession_, true);
1654   eventBase_.loop();
1655   EXPECT_EQ(hqSession_->getConnectionCloseReason(),
1656             ConnectionCloseReason::TIMEOUT);
1657 }
1658 
1659 // HQ can't do this case, because onMessageBegin is only called with full
1660 // headers.
TEST_P(HQDownstreamSessionTestH1q,TransactionTimeoutNoHandler)1661 TEST_P(HQDownstreamSessionTestH1q, TransactionTimeoutNoHandler) {
1662   // test transaction timeout before receiving the full headers
1663   auto id = nextStreamId();
1664   auto res = requests_.emplace(std::piecewise_construct,
1665                                std::forward_as_tuple(id),
1666                                std::forward_as_tuple(makeCodec(id)));
1667   auto req = getGetRequest();
1668   auto& request = res.first->second;
1669   request.id = request.codec->createStream();
1670   request.codec->generateHeader(request.buf, request.id, req, false);
1671   // Send some bytes, but less than the whole headers, so that a stream gets
1672   // created but the handler does not get assigned
1673   request.buf.trimEnd(1);
1674 
1675   testing::StrictMock<MockHTTPHandler> handler;
1676   expectTransactionTimeout(handler);
1677 
1678   flushRequestsAndLoop();
1679   hqSession_->closeWhenIdle();
1680 }
1681 
TEST_P(HQDownstreamSessionTest,TransactionTimeoutNoCodecId)1682 TEST_P(HQDownstreamSessionTest, TransactionTimeoutNoCodecId) {
1683   auto id = nextStreamId();
1684   auto res = requests_.emplace(std::piecewise_construct,
1685                                std::forward_as_tuple(id),
1686                                std::forward_as_tuple(makeCodec(id)));
1687   auto req = getGetRequest();
1688   auto& request = res.first->second;
1689   request.id = request.codec->createStream();
1690   request.codec->generateHeader(request.buf, request.id, req, false);
1691   // Send only a new line, so that onMessageBegin does not get called
1692   request.buf.split(request.buf.chainLength() - 1);
1693   testing::StrictMock<MockHTTPHandler> handler;
1694   expectTransactionTimeout(handler);
1695   flushRequestsAndLoop();
1696   hqSession_->closeWhenIdle();
1697 }
1698 
TEST_P(HQDownstreamSessionTest,SendOnFlowControlPaused)1699 TEST_P(HQDownstreamSessionTest, SendOnFlowControlPaused) {
1700   // 106 bytes of resp headers, 1 byte of body but 5 bytes of chunk overhead
1701   auto id = sendRequest();
1702   // HTTP/3 has an extra grease frame on the first transaction
1703   socketDriver_->setStreamFlowControlWindow(id, IS_HQ ? 103 : 100);
1704 
1705   auto handler = addSimpleStrictHandler();
1706   handler->expectHeaders();
1707   handler->expectEOM([&handler] {
1708     handler->sendHeaders(200, 100);
1709     handler->txn_->sendBody(makeBuf(100));
1710   });
1711   handler->expectEgressPaused([&handler] { handler->txn_->sendEOM(); });
1712   flushRequestsAndLoop();
1713   socketDriver_->setStreamFlowControlWindow(id, 100);
1714   handler->expectDetachTransaction();
1715   eventBase_.loop();
1716   hqSession_->closeWhenIdle();
1717 }
1718 
TEST_P(HQDownstreamSessionTest,Http_100Continue)1719 TEST_P(HQDownstreamSessionTest, Http_100Continue) {
1720   auto req = getPostRequest(100);
1721   req.getHeaders().add(HTTP_HEADER_EXPECT, "100-continue");
1722   auto id = sendRequest(req, false);
1723   auto handler = addSimpleStrictHandler();
1724   handler->expectHeaders([&handler] {
1725     HTTPMessage continueResp;
1726     continueResp.setStatusCode(100);
1727     handler->txn_->sendHeaders(continueResp);
1728   });
1729   flushRequestsAndLoopN(1);
1730   auto& request = getStream(id);
1731   request.codec->generateBody(
1732       request.buf, request.id, makeBuf(100), HTTPCodec::NoPadding, true);
1733   request.readEOF = true;
1734 
1735   handler->expectBody();
1736   handler->expectEOM([&handler] { handler->sendReplyWithBody(200, 100); });
1737   handler->expectDetachTransaction();
1738   flushRequestsAndLoop();
1739   hqSession_->closeWhenIdle();
1740 }
1741 
TEST_P(HQDownstreamSessionTest,ByteEvents)1742 TEST_P(HQDownstreamSessionTest, ByteEvents) {
1743   sendRequest();
1744   auto handler = addSimpleStrictHandler();
1745   MockHTTPTransactionTransportCallback callback;
1746   handler->expectHeaders([&handler, &callback] {
1747     handler->txn_->setTransportCallback(&callback);
1748   });
1749   handler->expectEOM([&handler] { handler->sendReplyWithBody(200, 100); });
1750   handler->expectDetachTransaction();
1751   EXPECT_CALL(callback, headerBytesGenerated(_));
1752   EXPECT_CALL(callback, bodyBytesGenerated(_));
1753   EXPECT_CALL(callback, firstHeaderByteFlushed());
1754   EXPECT_CALL(callback, firstByteFlushed());
1755   EXPECT_CALL(callback, lastByteFlushed());
1756   EXPECT_CALL(callback, lastByteAcked(_));
1757   flushRequestsAndLoop();
1758   hqSession_->closeWhenIdle();
1759 }
1760 
TEST_P(HQDownstreamSessionTest,AppRateLimited)1761 TEST_P(HQDownstreamSessionTest, AppRateLimited) {
1762   sendRequest();
1763   auto handler = addSimpleStrictHandler();
1764   MockHTTPTransactionTransportCallback callback;
1765   handler->expectHeaders([&handler, &callback] {
1766     handler->txn_->setTransportCallback(&callback);
1767   });
1768   handler->expectEOM([this, &handler] {
1769     handler->sendHeaders(200, 150);
1770     handler->txn_->sendBody(makeBuf(100));
1771     // force trigger onAppRateLimited
1772     hqSession_->onAppRateLimited();
1773   });
1774   EXPECT_CALL(callback, headerBytesGenerated(_));
1775   EXPECT_CALL(callback, bodyBytesGenerated(Ge(100))); // For HQ it's 100
1776   EXPECT_CALL(callback, firstHeaderByteFlushed());
1777   EXPECT_CALL(callback, firstByteFlushed());
1778   EXPECT_CALL(callback, transportAppRateLimited());
1779   flushRequestsAndLoop();
1780 
1781   // send some more bytes and force trigger onAppRateLimited
1782   EXPECT_CALL(callback, bodyBytesGenerated(Ge(50))); // For HQ it's 52
1783   EXPECT_CALL(callback, transportAppRateLimited());
1784   handler->txn_->sendBody(makeBuf(50));
1785   hqSession_->onAppRateLimited();
1786   flushRequestsAndLoop();
1787 
1788   // Send the EOM, txn should not detach yet
1789   EXPECT_CALL(callback, bodyBytesGenerated(0));
1790   EXPECT_CALL(callback, lastByteFlushed());
1791   handler->txn_->sendEOM(); // 0 length EOM
1792   flushRequestsAndLoopN(1);
1793 
1794   // Let the delivery callback fire, now it can cleanup
1795   EXPECT_CALL(callback, lastByteAcked(_));
1796   handler->expectDetachTransaction();
1797   flushRequestsAndLoop();
1798   hqSession_->closeWhenIdle();
1799 }
1800 
TEST_P(HQDownstreamSessionTest,LastByteEventZeroSize)1801 TEST_P(HQDownstreamSessionTest, LastByteEventZeroSize) {
1802   sendRequest();
1803   auto handler = addSimpleStrictHandler();
1804   MockHTTPTransactionTransportCallback callback;
1805   handler->expectHeaders([&handler, &callback] {
1806     handler->txn_->setTransportCallback(&callback);
1807   });
1808   handler->expectEOM([&handler] {
1809     handler->sendHeaders(200, 100);
1810     handler->txn_->sendBody(makeBuf(100));
1811   });
1812   EXPECT_CALL(callback, headerBytesGenerated(_));
1813   EXPECT_CALL(callback, bodyBytesGenerated(Ge(100))); // For HQ it's 103
1814   EXPECT_CALL(callback, firstHeaderByteFlushed());
1815   EXPECT_CALL(callback, firstByteFlushed());
1816   flushRequestsAndLoop();
1817 
1818   // Send the EOM, txn should not detach yet
1819   EXPECT_CALL(callback, bodyBytesGenerated(0));
1820   EXPECT_CALL(callback, lastByteFlushed());
1821   handler->txn_->sendEOM(); // 0 length EOM
1822   flushRequestsAndLoopN(1);
1823 
1824   // Let the delivery callback fire, now it can cleanup
1825   EXPECT_CALL(callback, lastByteAcked(_));
1826   handler->expectDetachTransaction();
1827   flushRequestsAndLoop();
1828   hqSession_->closeWhenIdle();
1829 }
1830 
TEST_P(HQDownstreamSessionTest,DropWithByteEvents)1831 TEST_P(HQDownstreamSessionTest, DropWithByteEvents) {
1832   sendRequest();
1833   auto handler = addSimpleStrictHandler();
1834   MockHTTPTransactionTransportCallback callback;
1835   handler->expectHeaders([&handler, &callback] {
1836     handler->txn_->setTransportCallback(&callback);
1837   });
1838   handler->expectEOM([&handler] { handler->sendReplyWithBody(200, 100); });
1839   handler->expectDetachTransaction();
1840   EXPECT_CALL(callback, headerBytesGenerated(_));
1841   EXPECT_CALL(callback, bodyBytesGenerated(_));
1842   EXPECT_CALL(callback, firstHeaderByteFlushed());
1843   EXPECT_CALL(callback, firstByteFlushed());
1844   EXPECT_CALL(callback, lastByteFlushed());
1845   flushRequestsAndLoopN(1);
1846   hqSession_->dropConnection();
1847 }
1848 
TEST_P(HQDownstreamSessionTest,TransportInfo)1849 TEST_P(HQDownstreamSessionTest, TransportInfo) {
1850   wangle::TransportInfo transInfo;
1851   quic::QuicSocket::TransportInfo quicInfo;
1852   quicInfo.srtt = std::chrono::microseconds(135);
1853   quicInfo.rttvar = std::chrono::microseconds(246);
1854   quicInfo.writableBytes = 212;
1855   quicInfo.congestionWindow = 5 * quic::kDefaultUDPSendPacketLen;
1856   quicInfo.packetsRetransmitted = 513;
1857   quicInfo.timeoutBasedLoss = 90;
1858   quicInfo.pto = std::chrono::microseconds(34);
1859   quicInfo.bytesSent = 23;
1860   quicInfo.bytesRecvd = 123;
1861   quicInfo.ptoCount = 1;
1862   quicInfo.totalPTOCount = 2;
1863   EXPECT_CALL(*socketDriver_->getSocket(), getTransportInfo())
1864       .Times(3)
1865       .WillRepeatedly(Return(quicInfo));
1866   hqSession_->getCurrentTransportInfoWithoutUpdate(&transInfo);
1867   EXPECT_EQ(135, transInfo.rtt.count());
1868   EXPECT_EQ(246, transInfo.rtt_var);
1869   EXPECT_EQ(5, transInfo.cwnd);
1870   EXPECT_EQ(5 * quic::kDefaultUDPSendPacketLen, transInfo.cwndBytes);
1871   EXPECT_EQ(513, transInfo.rtx);
1872   EXPECT_EQ(90, transInfo.rtx_tm);
1873   EXPECT_EQ(34, transInfo.rto);
1874   EXPECT_EQ(23, transInfo.totalBytes);
1875   auto quicProtocolInfo =
1876       dynamic_cast<QuicProtocolInfo*>(transInfo.protocolInfo.get());
1877   EXPECT_EQ(0, quicProtocolInfo->ptoCount);
1878   EXPECT_EQ(0, quicProtocolInfo->totalPTOCount);
1879   EXPECT_EQ(0, quicProtocolInfo->totalTransportBytesSent);
1880   EXPECT_EQ(0, quicProtocolInfo->totalTransportBytesRecvd);
1881   hqSession_->getCurrentTransportInfo(&transInfo);
1882   EXPECT_EQ(1, quicProtocolInfo->ptoCount);
1883   EXPECT_EQ(2, quicProtocolInfo->totalPTOCount);
1884   EXPECT_EQ(23, quicProtocolInfo->totalTransportBytesSent);
1885   EXPECT_EQ(123, quicProtocolInfo->totalTransportBytesRecvd);
1886   hqSession_->dropConnection();
1887 }
1888 
1889 // Current Transport Info tests
TEST_P(HQDownstreamSessionTest,CurrentTransportInfo)1890 TEST_P(HQDownstreamSessionTest, CurrentTransportInfo) {
1891   sendRequest();
1892   auto handler = addSimpleStrictHandler();
1893   MockHTTPTransactionTransportCallback callback;
1894   handler->expectHeaders([&handler, &callback] {
1895     handler->txn_->setTransportCallback(&callback);
1896   });
1897 
1898   QuicStreamProtocolInfo resultProtocolInfo;
1899   handler->expectEOM([&handler, &resultProtocolInfo] {
1900     wangle::TransportInfo transInfo;
1901     handler->txn_->getCurrentTransportInfo(&transInfo);
1902     auto quicStreamProtocolInfo =
1903         dynamic_cast<QuicStreamProtocolInfo*>(transInfo.protocolInfo.get());
1904 
1905     if (quicStreamProtocolInfo) {
1906       resultProtocolInfo.streamTransportInfo =
1907           quicStreamProtocolInfo->streamTransportInfo;
1908     }
1909   });
1910 
1911   handler->expectDetachTransaction();
1912   handler->expectError([&](const HTTPException& ex) {
1913     EXPECT_EQ(ex.getProxygenError(), kErrorDropped);
1914   });
1915 
1916   flushRequestsAndLoop();
1917   hqSession_->dropConnection();
1918 
1919   // The stream transport info field should be equal to
1920   // the mock object
1921   EXPECT_EQ(resultProtocolInfo.streamTransportInfo.totalHeadOfLineBlockedTime,
1922             streamTransInfo_.totalHeadOfLineBlockedTime);
1923   EXPECT_EQ(resultProtocolInfo.streamTransportInfo.holbCount,
1924             streamTransInfo_.holbCount);
1925   EXPECT_EQ(resultProtocolInfo.streamTransportInfo.isHolb,
1926             streamTransInfo_.isHolb);
1927 }
1928 
TEST_P(HQDownstreamSessionTest,GetAddresses)1929 TEST_P(HQDownstreamSessionTest, GetAddresses) {
1930   EXPECT_EQ(socketDriver_->localAddress_, hqSession_->getLocalAddress());
1931   EXPECT_EQ(socketDriver_->peerAddress_, hqSession_->getPeerAddress());
1932   hqSession_->dropConnection();
1933 }
1934 
TEST_P(HQDownstreamSessionTest,GetAddressesFromBase)1935 TEST_P(HQDownstreamSessionTest, GetAddressesFromBase) {
1936   HTTPSessionBase* sessionBase = dynamic_cast<HTTPSessionBase*>(hqSession_);
1937   EXPECT_EQ(socketDriver_->localAddress_, sessionBase->getLocalAddress());
1938   EXPECT_EQ(socketDriver_->peerAddress_, sessionBase->getPeerAddress());
1939   hqSession_->dropConnection();
1940 }
1941 
TEST_P(HQDownstreamSessionTest,GetAddressesAfterDropConnection)1942 TEST_P(HQDownstreamSessionTest, GetAddressesAfterDropConnection) {
1943   HQSession::DestructorGuard dg(hqSession_);
1944   hqSession_->dropConnection();
1945   EXPECT_EQ(socketDriver_->localAddress_, hqSession_->getLocalAddress());
1946   EXPECT_EQ(socketDriver_->peerAddress_, hqSession_->getPeerAddress());
1947 }
1948 
TEST_P(HQDownstreamSessionTest,RstCancelled)1949 TEST_P(HQDownstreamSessionTest, RstCancelled) {
1950   auto id = nextStreamId();
1951   auto buf = IOBuf::create(3);
1952   memcpy(buf->writableData(), "GET", 3);
1953   buf->append(3);
1954   socketDriver_->addReadEvent(id, std::move(buf), milliseconds(0));
1955   flushRequestsAndLoopN(1);
1956   socketDriver_->addReadError(id,
1957                               HTTP3::ErrorCode::HTTP_REQUEST_CANCELLED,
1958                               std::chrono::milliseconds(0));
1959   hqSession_->closeWhenIdle();
1960   flushRequestsAndLoop();
1961   EXPECT_EQ(*socketDriver_->streams_[id].error,
1962             HTTP3::ErrorCode::HTTP_REQUEST_REJECTED);
1963 }
1964 
TEST_P(HQDownstreamSessionTest,LocalErrQueuedEgress)1965 TEST_P(HQDownstreamSessionTest, LocalErrQueuedEgress) {
1966   sendRequest(getPostRequest(10), false);
1967   auto handler = addSimpleStrictHandler();
1968   handler->expectHeaders([&handler, this] {
1969     socketDriver_->setStreamFlowControlWindow(0, 0);
1970     socketDriver_->setConnectionFlowControlWindow(0);
1971     handler->sendHeaders(200, 65536 * 2);
1972     handler->sendBody(65536 * 2);
1973   });
1974   handler->expectEgressPaused();
1975   flushRequestsAndLoopN(2);
1976   handler->expectError([](const HTTPException& ex) {
1977     EXPECT_EQ(ex.getProxygenError(), kErrorShutdown);
1978   });
1979   handler->expectDetachTransaction();
1980   socketDriver_->deliverConnectionError(
1981       std::make_pair(quic::LocalErrorCode::CONNECTION_RESET, ""));
1982   flushRequestsAndLoop();
1983 }
1984 
TEST_P(HQDownstreamSessionTest,NoErrorNoStreams)1985 TEST_P(HQDownstreamSessionTest, NoErrorNoStreams) {
1986   EXPECT_CALL(infoCb_, onIngressError(_, kErrorNone));
1987   socketDriver_->deliverConnectionError(
1988       std::make_pair(HTTP3::ErrorCode::HTTP_NO_ERROR, ""));
1989   flushRequestsAndLoop();
1990 }
1991 
TEST_P(HQDownstreamSessionTest,NoErrorOneStreams)1992 TEST_P(HQDownstreamSessionTest, NoErrorOneStreams) {
1993   sendRequest();
1994   auto handler = addSimpleStrictHandler();
1995   handler->expectHeaders();
1996   handler->expectEOM();
1997   flushRequestsAndLoopN(1);
1998   // stream gets an error
1999   handler->expectError([](const HTTPException& ex) {
2000     EXPECT_EQ(ex.getProxygenError(), kErrorEOF);
2001   });
2002   handler->expectDetachTransaction();
2003   // This is for connection level errors, maybe should be reported a
2004   EXPECT_CALL(infoCb_, onIngressError(_, kErrorEOF));
2005   socketDriver_->deliverConnectionError(
2006       std::make_pair(HTTP3::ErrorCode::HTTP_NO_ERROR, ""));
2007 }
2008 
TEST_P(HQDownstreamSessionTestHQ,Connect)2009 TEST_P(HQDownstreamSessionTestHQ, Connect) {
2010   auto handler = addSimpleStrictHandler();
2011   // Send HTTP 200 OK to accept the CONNECT request
2012   handler->expectHeaders([&handler] { handler->sendHeaders(200, 100); });
2013   handler->expectEOM([&] { handler->terminate(); });
2014 
2015   // Data should be received using onBody
2016   EXPECT_CALL(*handler, onBodyWithOffset(_, _))
2017       .WillOnce(ExpectString("12345"))
2018       .WillOnce(ExpectString("abcdefg"));
2019   handler->expectDetachTransaction();
2020 
2021   proxygen::HTTPMessage req;
2022   req.setURL("test.net/path");
2023   req.setMethod("CONNECT");
2024   req.getHeaders().add(proxygen::HTTP_HEADER_HOST, "https://test.net/path");
2025   auto id = sendRequest(req, /* eom */ false);
2026   auto& request = getStream(id);
2027 
2028   auto buf1 = IOBuf::copyBuffer("12345");
2029   request.codec->generateBody(
2030       request.buf, request.id, std::move(buf1), HTTPCodec::NoPadding, true);
2031   flushRequestsAndLoopN(1);
2032 
2033   auto buf2 = IOBuf::copyBuffer("abcdefg");
2034   request.codec->generateBody(
2035       request.buf, request.id, std::move(buf2), HTTPCodec::NoPadding, true);
2036   flushRequestsAndLoopN(1);
2037 
2038   request.readEOF = true;
2039   flushRequestsAndLoop();
2040   hqSession_->closeWhenIdle();
2041 }
2042 
TEST_P(HQDownstreamSessionTestHQ,ConnectUDP)2043 TEST_P(HQDownstreamSessionTestHQ, ConnectUDP) {
2044   auto handler = addSimpleStrictHandler();
2045   // Send HTTP 200 OK to accept the CONNECT request
2046   handler->expectHeaders([&handler] { handler->sendHeaders(200, 100); });
2047   handler->expectEOM([&] { handler->terminate(); });
2048 
2049   // Data should be received using onBody
2050   EXPECT_CALL(*handler, onBodyWithOffset(_, _))
2051       .WillOnce(ExpectString("12345"))
2052       .WillOnce(ExpectString("abcdefg"));
2053   handler->expectDetachTransaction();
2054 
2055   proxygen::HTTPMessage req;
2056   req.setURL("test.net/path");
2057   req.setMethod("CONNECT-UDP");
2058   req.getHeaders().add(proxygen::HTTP_HEADER_HOST, "https://test.net/path");
2059   auto id = sendRequest(req, /* eom */ false);
2060   auto& request = getStream(id);
2061 
2062   auto buf1 = IOBuf::copyBuffer("12345");
2063   request.codec->generateBody(
2064       request.buf, request.id, std::move(buf1), HTTPCodec::NoPadding, true);
2065   flushRequestsAndLoopN(1);
2066 
2067   auto buf2 = IOBuf::copyBuffer("abcdefg");
2068   request.codec->generateBody(
2069       request.buf, request.id, std::move(buf2), HTTPCodec::NoPadding, true);
2070   flushRequestsAndLoopN(1);
2071 
2072   request.readEOF = true;
2073   flushRequestsAndLoop();
2074   hqSession_->closeWhenIdle();
2075 }
2076 
2077 // Just open a stream and send nothing
TEST_P(HQDownstreamSessionTest,zeroBytes)2078 TEST_P(HQDownstreamSessionTest, zeroBytes) {
2079   auto id = nextStreamId();
2080   socketDriver_->addReadEvent(
2081       id, folly::IOBuf::copyBuffer("", 0), milliseconds(0));
2082   testing::StrictMock<MockHTTPHandler> handler;
2083   expectTransactionTimeout(handler);
2084   eventBase_.loop();
2085   hqSession_->closeWhenIdle();
2086 }
2087 
2088 // For HQ, send an incomplete frame header
TEST_P(HQDownstreamSessionTestHQ,oneByte)2089 TEST_P(HQDownstreamSessionTestHQ, oneByte) {
2090   auto id = nextStreamId();
2091   socketDriver_->addReadEvent(
2092       id, folly::IOBuf::copyBuffer("", 1), milliseconds(0));
2093   testing::StrictMock<MockHTTPHandler> handler;
2094   expectTransactionTimeout(handler);
2095   eventBase_.loop();
2096   hqSession_->closeWhenIdle();
2097 }
2098 
TEST_P(HQDownstreamSessionTestH1qv2HQ,TestGoawayID)2099 TEST_P(HQDownstreamSessionTestH1qv2HQ, TestGoawayID) {
2100   // This test check that unidirectional stream IDs are not accounted for
2101   // in the Goaway Max Stream ID
2102   auto req = getGetRequest();
2103   // Explicitly skip some stream IDs to simulate out of order delivery
2104   sendRequest(req, true, 4);
2105   auto handler = addSimpleStrictHandler();
2106   handler->expectHeaders();
2107   handler->expectEOM([hdlr = handler.get()] {
2108     // Delay sending EOM so the streams are active when draining
2109     hdlr->sendReplyWithBody(200, 100, true, false);
2110   });
2111   handler->expectDetachTransaction();
2112   flushRequestsAndLoopN(1);
2113   hqSession_->closeWhenIdle();
2114   // Give it some time to send the two goaways and receive the delivery callback
2115   flushRequestsAndLoopN(3);
2116   EXPECT_EQ(httpCallbacks_.goaways, 2);
2117   EXPECT_THAT(httpCallbacks_.goawayStreamIds,
2118               ElementsAre(kMaxClientBidiStreamId, 8));
2119   handler->sendEOM();
2120   flushRequestsAndLoop();
2121 }
2122 
TEST_P(HQDownstreamSessionTestHQ,TestReceiveGoaway)2123 TEST_P(HQDownstreamSessionTestHQ, TestReceiveGoaway) {
2124   folly::IOBufQueue writeBuf{folly::IOBufQueue::cacheChainLength()};
2125   egressControlCodec_->generateGoaway(
2126       writeBuf, HTTPCodec::MaxStreamID, ErrorCode::NO_ERROR, nullptr);
2127   socketDriver_->addReadEvent(
2128       connControlStreamId_, writeBuf.move(), std::chrono::milliseconds(0));
2129   flushRequestsAndLoopN(1);
2130   EXPECT_FALSE(hqSession_->isClosing());
2131   hqSession_->closeWhenIdle();
2132   eventBase_.loop();
2133 }
2134 
TEST_P(HQDownstreamSessionTestH1qv2HQ,TestGetGoaway)2135 TEST_P(HQDownstreamSessionTestH1qv2HQ, TestGetGoaway) {
2136   std::vector<std::unique_ptr<StrictMock<MockHTTPHandler>>> handlers;
2137   auto numStreams = 3;
2138   for (auto n = 1; n <= numStreams; n++) {
2139     auto req = getGetRequest();
2140     // Explicitly skip some stream IDs to simulate out of order delivery
2141     sendRequest(req, true, n * 8);
2142     handlers.emplace_back(addSimpleStrictHandler());
2143     auto handler = handlers.back().get();
2144     handler->expectHeaders();
2145     handler->expectEOM([hdlr = handler] {
2146       // Delay sending EOM so the streams are active when draining
2147       hdlr->sendReplyWithBody(200, 100, true, false);
2148     });
2149     handler->expectDetachTransaction();
2150   }
2151   flushRequestsAndLoopN(1);
2152   hqSession_->closeWhenIdle();
2153   // Give it some time to send the two goaways and receive the delivery callback
2154   flushRequestsAndLoopN(3);
2155   EXPECT_EQ(httpCallbacks_.goaways, 2);
2156   EXPECT_THAT(httpCallbacks_.goawayStreamIds,
2157               ElementsAre(kMaxClientBidiStreamId, numStreams * 8 + 4));
2158 
2159   // Check that a new stream with id >= lastStreamId gets rejected
2160   auto errReq = getGetRequest();
2161   quic::StreamId errStreamId = numStreams * 8 + 4;
2162   sendRequest(errReq, true, errStreamId);
2163   flushRequestsAndLoopN(1);
2164   auto& errStream = socketDriver_->streams_[errStreamId];
2165   EXPECT_EQ(errStream.writeState, MockQuicSocketDriver::StateEnum::ERROR);
2166   EXPECT_TRUE(errStream.error == HTTP3::ErrorCode::HTTP_REQUEST_REJECTED);
2167 
2168   // Check that a new stream with id <= lastStreamId is instead just fine
2169   auto okReq = getGetRequest();
2170   sendRequest(okReq, true, numStreams * 8 - 4);
2171   auto okHandler = addSimpleStrictHandler();
2172   okHandler->expectHeaders();
2173   okHandler->expectEOM([&] { okHandler->sendReplyWithBody(200, 100); });
2174   okHandler->expectDetachTransaction();
2175   flushRequestsAndLoopN(1);
2176 
2177   // now send response EOM on the pending transactions, to finish shutdown
2178   for (auto& handler : handlers) {
2179     handler->sendEOM();
2180   }
2181   flushRequestsAndLoop();
2182 }
2183 
TEST_P(HQDownstreamSessionTestHQ,DelayedQPACK)2184 TEST_P(HQDownstreamSessionTestHQ, DelayedQPACK) {
2185   auto req = getGetRequest();
2186   req.getHeaders().add("X-FB-Debug", "rfccffgvtvnenjkbtitkfdufddnvbecu");
2187   auto id = sendRequest(req);
2188   auto handler = addSimpleStrictHandler();
2189   handler->expectHeaders();
2190   handler->expectEOM(
2191       [hdlr = handler.get()] { hdlr->sendReplyWithBody(200, 100); });
2192   handler->expectDetachTransaction();
2193 
2194   auto controlStream = encoderWriteBuf_.move();
2195   flushRequestsAndLoopN(1);
2196   encoderWriteBuf_.append(std::move(controlStream));
2197   flushRequestsAndLoop();
2198   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
2199   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
2200   hqSession_->closeWhenIdle();
2201 }
2202 
TEST_P(HQDownstreamSessionTestHQ,cancelQPACK)2203 TEST_P(HQDownstreamSessionTestHQ, cancelQPACK) {
2204   auto req = getGetRequest();
2205   req.getHeaders().add("X-FB-Debug", "rfccffgvtvnenjkbtitkfdufddnvbecu");
2206   auto id = sendRequest(req);
2207   auto& request = getStream(id);
2208   // discard part of request, header won't get qpack-ack'd
2209   request.buf.trimEnd(request.buf.chainLength() - 3);
2210   request.readEOF = false;
2211   flushRequestsAndLoopN(1);
2212   socketDriver_->addReadError(id,
2213                               HTTP3::ErrorCode::HTTP_REQUEST_CANCELLED,
2214                               std::chrono::milliseconds(0));
2215   hqSession_->closeWhenIdle();
2216   flushRequestsAndLoop();
2217   // this will evict all headers, which is only legal if the cancellation is
2218   // emitted and processed.
2219   qpackCodec_.setEncoderHeaderTableSize(0);
2220   EXPECT_EQ(*socketDriver_->streams_[id].error,
2221             HTTP3::ErrorCode::HTTP_REQUEST_REJECTED);
2222   eventBase_.loopOnce();
2223 }
2224 
TEST_P(HQDownstreamSessionTestHQ,DelayedQPACKCanceled)2225 TEST_P(HQDownstreamSessionTestHQ, DelayedQPACKCanceled) {
2226   auto req = getGetRequest();
2227   req.getHeaders().add("X-FB-Debug", "rfccffgvtvnenjkbtitkfdufddnvbecu");
2228   auto id = sendRequest(req);
2229   // This request never gets a handler
2230 
2231   auto controlStream = encoderWriteBuf_.move();
2232   // receive header block with unsatisfied dep
2233   flushRequestsAndLoopN(1);
2234 
2235   // cancel this request
2236   socketDriver_->addReadError(id,
2237                               HTTP3::ErrorCode::HTTP_REQUEST_CANCELLED,
2238                               std::chrono::milliseconds(0));
2239   flushRequestsAndLoopN(1);
2240 
2241   // Now send the dependency
2242   encoderWriteBuf_.append(std::move(controlStream));
2243   flushRequestsAndLoop();
2244 
2245   // This used to crash
2246   hqSession_->closeWhenIdle();
2247 }
2248 
TEST_P(HQDownstreamSessionTestHQ,DelayedQPACKTimeout)2249 TEST_P(HQDownstreamSessionTestHQ, DelayedQPACKTimeout) {
2250   auto req = getPostRequest(10);
2251   req.getHeaders().add("X-FB-Debug", "rfccffgvtvnenjkbtitkfdufddnvbecu");
2252   auto id = sendRequest(req, false);
2253   auto& request = getStream(id);
2254   folly::IOBufQueue reqTail(folly::IOBufQueue::cacheChainLength());
2255   reqTail.append(request.buf.move());
2256   request.buf.append(reqTail.split(reqTail.chainLength() / 2));
2257   // reqTail now has the second half of request
2258 
2259   flushRequests();
2260   testing::StrictMock<MockHTTPHandler> handler;
2261   expectTransactionTimeout(handler, [&] {
2262     request.buf.append(reqTail.move());
2263     auto body = folly::IOBuf::wrapBuffer("\3\3\3\3\3\3\3\3\3\3", 10);
2264     request.codec->generateBody(
2265         request.buf, request.id, std::move(body), HTTPCodec::NoPadding, true);
2266     flushRequests();
2267   });
2268   eventBase_.loop();
2269   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
2270   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
2271   hqSession_->closeWhenIdle();
2272 }
2273 
TEST_P(HQDownstreamSessionTestHQ,QPACKEncoderLimited)2274 TEST_P(HQDownstreamSessionTestHQ, QPACKEncoderLimited) {
2275   auto req = getGetRequest();
2276   socketDriver_->getSocket()->setStreamFlowControlWindow(
2277       kQPACKEncoderEgressStreamId, 10);
2278   auto id = sendRequest(req);
2279   auto handler = addSimpleStrictHandler();
2280   handler->expectHeaders();
2281   handler->expectEOM([hdlr = handler.get()] {
2282     HTTPMessage resp;
2283     resp.setStatusCode(200);
2284     resp.getHeaders().add("X-FB-Debug", "rfccffgvtvnenjkbtitkfdufddnvbecu");
2285     hdlr->txn_->sendHeaders(resp);
2286     hdlr->txn_->sendEOM();
2287   });
2288   handler->expectDetachTransaction();
2289   flushRequestsAndLoop();
2290 
2291   // QPACK will attempt to index the header, but cannot reference it because
2292   // it runs out of stream flow control
2293   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 30);
2294   hqSession_->closeWhenIdle();
2295 }
2296 
TEST_P(HQDownstreamSessionTestHQ,DelayedQPACKStopSendingReset)2297 TEST_P(HQDownstreamSessionTestHQ, DelayedQPACKStopSendingReset) {
2298   auto req = getGetRequest();
2299   req.getHeaders().add("X-FB-Debug", "rfccffgvtvnenjkbtitkfdufddnvbecu");
2300   auto id = sendRequest(req);
2301   // This request never gets a handler
2302 
2303   auto controlStream = encoderWriteBuf_.move();
2304   // receive header block with unsatisfied dep
2305   flushRequestsAndLoopN(1);
2306 
2307   // cancel this request
2308   socketDriver_->addStopSending(id, HTTP3::ErrorCode::HTTP_REQUEST_CANCELLED);
2309   socketDriver_->addReadError(id,
2310                               HTTP3::ErrorCode::HTTP_REQUEST_CANCELLED,
2311                               std::chrono::milliseconds(0));
2312   flushRequestsAndLoopN(1);
2313 
2314   // Now send the dependency
2315   encoderWriteBuf_.append(std::move(controlStream));
2316   flushRequestsAndLoop();
2317 
2318   // This used to crash
2319   hqSession_->closeWhenIdle();
2320 }
2321 
TEST_P(HQDownstreamSessionTestHQ,QPACKHeadersTooLarge)2322 TEST_P(HQDownstreamSessionTestHQ, QPACKHeadersTooLarge) {
2323   hqSession_->setEgressSettings({{SettingsId::MAX_HEADER_LIST_SIZE, 60}});
2324   auto req = getGetRequest();
2325   req.getHeaders().add("X-FB-Debug", "rfccffgvtvnenjkbtitkfdufddnvbecu");
2326   auto id = sendRequest(req);
2327   testing::StrictMock<MockHTTPHandler> errHandler;
2328   EXPECT_CALL(getMockController(), getParseErrorHandler(_, _, _))
2329       .WillOnce(Return(&errHandler));
2330   EXPECT_CALL(errHandler, setTransaction(testing::_))
2331       .WillOnce(testing::SaveArg<0>(&errHandler.txn_));
2332   errHandler.expectError([&errHandler](const HTTPException& ex) {
2333     EXPECT_EQ(ex.getHttp3ErrorCode(),
2334               (uint32_t)HTTP3::ErrorCode::HTTP_QPACK_DECOMPRESSION_FAILED);
2335     errHandler.sendReplyWithBody(400, 100);
2336   });
2337   errHandler.expectDetachTransaction();
2338   flushRequestsAndLoopN(2);
2339   // Gets a response
2340   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 30);
2341   EXPECT_EQ(*socketDriver_->streams_[id].error,
2342             (uint32_t)HTTP3::ErrorCode::HTTP_QPACK_DECOMPRESSION_FAILED);
2343   auto decoderStream = socketDriver_->streams_[kQPACKDecoderEgressStreamId]
2344                            .writeBuf.front()
2345                            ->clone();
2346   decoderStream->coalesce();
2347   // preface, cancel, ici
2348   EXPECT_EQ(decoderStream->computeChainDataLength(), 3);
2349   EXPECT_EQ(decoderStream->data()[1], 0x40); // stream 0 cancelled
2350 
2351   // But the conn is still usable
2352   sendRequest();
2353   auto handler = addSimpleStrictHandler();
2354   handler->expectHeaders();
2355   handler->expectEOM([hdlr = handler.get(), this] {
2356     HTTPMessage resp;
2357     resp.setStatusCode(200);
2358     hdlr->txn_->sendHeaders(resp);
2359     hdlr->txn_->sendEOM();
2360     hqSession_->closeWhenIdle();
2361   });
2362   handler->expectDetachTransaction();
2363   flushRequestsAndLoop();
2364 }
2365 
TEST_P(HQDownstreamSessionBeforeTransportReadyTest,NotifyPendingShutdown)2366 TEST_P(HQDownstreamSessionBeforeTransportReadyTest, NotifyPendingShutdown) {
2367   hqSession_->notifyPendingShutdown();
2368   SetUpOnTransportReady();
2369   // Give it some time to send the two goaways and receive the delivery callback
2370   flushRequestsAndLoopN(3);
2371   if (IS_HQ) {
2372     // There is a check for this already for all the tests, but adding this to
2373     // make it explicit that SETTINGS should be sent before GOAWAY even in this
2374     // corner case, otherwise the peer will error out the session
2375     EXPECT_EQ(httpCallbacks_.settings, 1);
2376   }
2377   EXPECT_EQ(httpCallbacks_.goaways, 2);
2378   EXPECT_THAT(httpCallbacks_.goawayStreamIds,
2379               ElementsAre(kMaxClientBidiStreamId, 0));
2380 }
2381 
2382 // NOTE: a failure for this test may cause an infinite loop in processReadData
TEST_P(HQDownstreamSessionTest,ProcessReadDataOnDetachedStream)2383 TEST_P(HQDownstreamSessionTest, ProcessReadDataOnDetachedStream) {
2384   auto id = sendRequest("/", 0, false);
2385   auto handler = addSimpleStrictHandler();
2386   handler->expectHeaders([&] {
2387     eventBase_.runAfterDelay(
2388         [&] {
2389           // schedule a few events to run in the eventbase back-to-back
2390           // call readAvailable with just the EOF
2391           auto& stream = socketDriver_->streams_[id];
2392           CHECK(!stream.readEOF);
2393           stream.readEOF = true;
2394           CHECK(stream.readCB);
2395           stream.readCB->readAvailable(id);
2396           // now send an error so that the stream gets marked for detach
2397           stream.readCB->readError(
2398               id, std::make_pair(HTTP3::ErrorCode::HTTP_NO_ERROR, folly::none));
2399           // then closeWhenIdle (like during shutdown), this calls
2400           // checkForShutdown that calls checkForDetach and may detach a
2401           // transaction that was added to the pendingProcessReadSet in the same
2402           // loop
2403           hqSession_->closeWhenIdle();
2404         },
2405         10);
2406   });
2407   flushRequestsAndLoopN(1);
2408 
2409   handler->expectError();
2410   handler->expectDetachTransaction();
2411 
2412   flushRequestsAndLoop();
2413 }
2414 
2415 // Test Cases for which Settings are not sent in the test SetUp
2416 using HQDownstreamSessionTestHQNoSettings = HQDownstreamSessionTest;
2417 INSTANTIATE_TEST_CASE_P(HQDownstreamSessionTest,
2418                         HQDownstreamSessionTestHQNoSettings,
__anond237a0706902null2419                         Values([] {
2420                           TestParams tp;
2421                           tp.alpn_ = "h3";
2422                           tp.shouldSendSettings_ = false;
2423                           return tp;
2424                         }()),
2425                         paramsToTestName);
TEST_P(HQDownstreamSessionTestHQNoSettings,SimpleGet)2426 TEST_P(HQDownstreamSessionTestHQNoSettings, SimpleGet) {
2427   auto idh = checkRequest();
2428   flushRequestsAndLoop();
2429   EXPECT_GT(socketDriver_->streams_[idh.first].writeBuf.chainLength(), 110);
2430   EXPECT_TRUE(socketDriver_->streams_[idh.first].writeEOF);
2431   // Checks that the server response is sent without the QPACK dynamic table
2432   CHECK_EQ(qpackCodec_.getCompressionInfo().ingress.headerTableSize_, 0);
2433 
2434   // TODO: Check that QPACK does not use the dynamic table for the response
2435   hqSession_->closeWhenIdle();
2436 }
2437 
2438 // This test is checking two different scenarios for different protocol
2439 //   - in HQ we already have sent SETTINGS in SetUp, so tests that multiple
2440 //     setting frames are not allowed
2441 //   - in h1q-fb-v2 tests that receiving even a single SETTINGS frame errors
2442 //     out the connection
TEST_P(HQDownstreamSessionTestH1qv2HQ,ExtraSettings)2443 TEST_P(HQDownstreamSessionTestH1qv2HQ, ExtraSettings) {
2444   sendRequest();
2445   auto handler = addSimpleStrictHandler();
2446   handler->expectHeaders();
2447   handler->expectEOM();
2448   handler->expectError([&](const HTTPException& ex) {
2449     EXPECT_EQ(ex.getProxygenError(), kErrorConnection);
2450   });
2451   handler->expectDetachTransaction();
2452   flushRequestsAndLoopN(1);
2453 
2454   // Need to use a new codec. Since generating settings twice is
2455   // forbidden
2456   HQControlCodec auxControlCodec_{0x0003,
2457                                   TransportDirection::UPSTREAM,
2458                                   StreamDirection::EGRESS,
2459                                   egressSettings_};
2460   folly::IOBufQueue writeBuf{folly::IOBufQueue::cacheChainLength()};
2461   auxControlCodec_.generateSettings(writeBuf);
2462   socketDriver_->addReadEvent(
2463       connControlStreamId_, writeBuf.move(), milliseconds(0));
2464 
2465   flushRequestsAndLoop();
2466 
2467   EXPECT_EQ(*socketDriver_->streams_[kConnectionStreamId].error,
2468             HTTP3::ErrorCode::HTTP_FRAME_UNEXPECTED);
2469 }
2470 
2471 using HQDownstreamSessionFilterTestHQ = HQDownstreamSessionTestHQ;
TEST_P(HQDownstreamSessionFilterTestHQ,ControlStreamFilters)2472 TEST_P(HQDownstreamSessionFilterTestHQ, ControlStreamFilters) {
2473   uint64_t settingsReceived = 0;
2474 
2475   class TestFilter : public PassThroughHTTPCodecFilter {
2476    public:
2477     explicit TestFilter(uint64_t& settingsReceived)
2478         : settingsReceived_(settingsReceived) {
2479     }
2480 
2481     void onSettings(const SettingsList& settings) override {
2482       settingsReceived_++;
2483     }
2484     uint64_t& settingsReceived_;
2485   };
2486 
2487   hqSession_->addCodecFilter<TestFilter>(settingsReceived);
2488   sendSettings();
2489   flushRequestsAndLoop();
2490   EXPECT_EQ(settingsReceived, 1);
2491   hqSession_->closeWhenIdle();
2492 }
2493 
TEST_P(HQDownstreamSessionTestH1q,httpPausedBufferedDetach)2494 TEST_P(HQDownstreamSessionTestH1q, httpPausedBufferedDetach) {
2495   IOBufQueue rst{IOBufQueue::cacheChainLength()};
2496   auto id1 = sendRequest();
2497 
2498   InSequence handlerSequence;
2499   auto handler1 = addSimpleStrictHandler();
2500   handler1->expectHeaders();
2501   handler1->expectEOM([&handler1, this, id1] {
2502     // HTTP/3 has an extra grease frame on the first transaction
2503     socketDriver_->setStreamFlowControlWindow(id1, IS_HQ ? 202 : 199);
2504     handler1->sendHeaders(200, 100);
2505     handler1->sendBody(100);
2506     eventBase_.runInLoop([&handler1] {
2507       handler1->expectDetachTransaction();
2508       handler1->sendEOM();
2509     });
2510   });
2511   handler1->expectEgressPaused();
2512   flushRequestsAndLoop();
2513 
2514   hqSession_->dropConnection();
2515 }
2516 
TEST_P(HQDownstreamSessionTest,onErrorEmptyEnqueued)2517 TEST_P(HQDownstreamSessionTest, onErrorEmptyEnqueued) {
2518   IOBufQueue rst{IOBufQueue::cacheChainLength()};
2519   auto id1 = sendRequest();
2520 
2521   InSequence handlerSequence;
2522   auto handler1 = addSimpleStrictHandler();
2523   handler1->expectHeaders();
2524   handler1->expectEOM([&handler1, this, id1] {
2525     handler1->sendHeaders(200, 100);
2526     socketDriver_->setStreamFlowControlWindow(id1, 100);
2527     // After one loop, it will become stream flow control blocked, and txn
2528     // will think it is enqueued, but session will not.
2529     handler1->expectEgressPaused();
2530     handler1->sendBody(101);
2531     eventBase_.runInLoop([&handler1, this, id1] {
2532       handler1->expectError();
2533       handler1->expectDetachTransaction();
2534       socketDriver_->addReadError(id1,
2535                                   HTTP3::ErrorCode::HTTP_INTERNAL_ERROR,
2536                                   std::chrono::milliseconds(0));
2537     });
2538   });
2539   flushRequestsAndLoop();
2540 
2541   hqSession_->closeWhenIdle();
2542 }
2543 
TEST_P(HQDownstreamSessionTest,dropWhilePaused)2544 TEST_P(HQDownstreamSessionTest, dropWhilePaused) {
2545   IOBufQueue rst{IOBufQueue::cacheChainLength()};
2546   sendRequest();
2547 
2548   InSequence handlerSequence;
2549   auto handler1 = addSimpleStrictHandler();
2550   handler1->expectHeaders();
2551   handler1->expectEOM([&handler1, this] {
2552     // pause writes
2553     socketDriver_->setConnectionFlowControlWindow(0);
2554     // fill session buffer
2555     handler1->sendReplyWithBody(200, hqSession_->getWriteBufferLimit());
2556   });
2557   flushRequestsAndLoop();
2558 
2559   handler1->expectError([&](const HTTPException& ex) {
2560     EXPECT_EQ(ex.getProxygenError(), kErrorDropped);
2561   });
2562   handler1->expectDetachTransaction();
2563   hqSession_->dropConnection();
2564 }
2565 
TEST_P(HQDownstreamSessionTestH1qv2HQ,StopSendingOnUnknownUnidirectionalStreams)2566 TEST_P(HQDownstreamSessionTestH1qv2HQ,
2567        StopSendingOnUnknownUnidirectionalStreams) {
2568   auto greaseStreamId = nextUnidirectionalStreamId();
2569   createControlStream(socketDriver_.get(),
2570                       greaseStreamId,
2571                       proxygen::hq::UnidirectionalStreamType(
2572                           *getGreaseId(folly::Random::rand32(16))));
2573   auto idh = checkRequest();
2574   flushRequestsAndLoop();
2575 
2576   EXPECT_EQ(*socketDriver_->streams_[greaseStreamId].error,
2577             HTTP3::ErrorCode::HTTP_STREAM_CREATION_ERROR);
2578   // Also check that the request completes correctly
2579   EXPECT_GT(socketDriver_->streams_[idh.first].writeBuf.chainLength(), 110);
2580   EXPECT_TRUE(socketDriver_->streams_[idh.first].writeEOF);
2581   if (IS_HQ) {
2582     // Checks that the server response is sent using the QPACK dynamic table
2583     CHECK_GE(qpackCodec_.getCompressionInfo().ingress.headerTableSize_, 0);
2584   }
2585   hqSession_->closeWhenIdle();
2586 }
2587 
TEST_P(HQDownstreamSessionTestHQ,DataOnUnknownControlStream)2588 TEST_P(HQDownstreamSessionTestHQ, DataOnUnknownControlStream) {
2589   auto randPreface =
2590       hq::UnidirectionalStreamType(*getGreaseId(folly::Random::rand32(16)));
2591   // Create  unidirectional stream with an unknown stream preface
2592   folly::IOBufQueue writeBuf{folly::IOBufQueue::cacheChainLength()};
2593   generateStreamPreface(writeBuf, randPreface);
2594   socketDriver_->addReadEvent(14, writeBuf.move());
2595   flushRequestsAndLoop();
2596 
2597   // Send an extra varint on the same stream, ignoring STOP_SENDING
2598   folly::IOBufQueue writeBuf2{folly::IOBufQueue::cacheChainLength()};
2599   generateStreamPreface(writeBuf2, randPreface);
2600   socketDriver_->addReadEvent(14, writeBuf.move());
2601   flushRequestsAndLoop();
2602   hqSession_->closeWhenIdle();
2603 }
2604 
TEST_P(HQDownstreamSessionTestH1qv2HQ,eofControlStream)2605 TEST_P(HQDownstreamSessionTestH1qv2HQ, eofControlStream) {
2606   sendRequest();
2607 
2608   InSequence handlerSequence;
2609   auto handler = addSimpleStrictHandler();
2610   handler->expectHeaders();
2611   handler->expectEOM();
2612   handler->expectError([&](const HTTPException& ex) {
2613     EXPECT_EQ(ex.getProxygenError(), kErrorConnection);
2614   });
2615   handler->expectDetachTransaction();
2616   flushRequestsAndLoopN(1);
2617   socketDriver_->addReadEOF(connControlStreamId_);
2618   flushRequestsAndLoop();
2619 }
2620 
TEST_P(HQDownstreamSessionTestH1qv2HQ,resetControlStream)2621 TEST_P(HQDownstreamSessionTestH1qv2HQ, resetControlStream) {
2622   sendRequest();
2623 
2624   InSequence handlerSequence;
2625   auto handler = addSimpleStrictHandler();
2626   handler->expectHeaders();
2627   handler->expectEOM();
2628   handler->expectError([&](const HTTPException& ex) {
2629     EXPECT_EQ(ex.getProxygenError(), kErrorConnection);
2630   });
2631   handler->expectDetachTransaction();
2632   flushRequestsAndLoopN(1);
2633   socketDriver_->addReadError(connControlStreamId_,
2634                               HTTP3::ErrorCode::HTTP_INTERNAL_ERROR);
2635   flushRequestsAndLoop();
2636   EXPECT_EQ(*socketDriver_->streams_[kConnectionStreamId].error,
2637             HTTP3::ErrorCode::HTTP_CLOSED_CRITICAL_STREAM);
2638 }
2639 
TEST_P(HQDownstreamSessionTestHQ,controlStreamWriteError)2640 TEST_P(HQDownstreamSessionTestHQ, controlStreamWriteError) {
2641   sendRequest();
2642 
2643   InSequence handlerSequence;
2644   auto handler = addSimpleStrictHandler();
2645   handler->expectHeaders();
2646   handler->expectEOM([&handler] { handler->sendHeaders(200, 100); });
2647   handler->expectError([&](const HTTPException& ex) {
2648     EXPECT_EQ(ex.getProxygenError(), kErrorWrite);
2649   });
2650   handler->expectDetachTransaction();
2651   socketDriver_->setWriteError(kQPACKEncoderEgressStreamId);
2652   flushRequestsAndLoop();
2653   EXPECT_EQ(*socketDriver_->streams_[kConnectionStreamId].error,
2654             HTTP3::ErrorCode::HTTP_CLOSED_CRITICAL_STREAM);
2655 }
2656 
TEST_P(HQDownstreamSessionTestHQ,TooManyControlStreams)2657 TEST_P(HQDownstreamSessionTestHQ, TooManyControlStreams) {
2658   // This creates a request stream, so that we can check the HTTP3::ErrorCode
2659   // at the end of the test. With no active streams we would drop the
2660   // connection with no error instead.
2661   sendRequest();
2662   InSequence handlerSequence;
2663   auto handler = addSimpleStrictHandler();
2664   handler->expectHeaders();
2665   handler->expectEOM();
2666   handler->expectError([&](const HTTPException& ex) {
2667     EXPECT_EQ(ex.getProxygenError(), kErrorConnection);
2668   });
2669   handler->expectDetachTransaction();
2670   flushRequestsAndLoopN(1);
2671 
2672   // Create an extra control stream, that causes the connection to get dropped
2673   folly::IOBufQueue writeBuf{folly::IOBufQueue::cacheChainLength()};
2674   generateStreamPreface(writeBuf, UnidirectionalStreamType::CONTROL);
2675   socketDriver_->addReadEvent(14, writeBuf.move());
2676 
2677   flushRequestsAndLoop();
2678   EXPECT_EQ(*socketDriver_->streams_[kConnectionStreamId].error,
2679             HTTP3::ErrorCode::HTTP_STREAM_CREATION_ERROR);
2680 }
2681 
TEST_P(HQDownstreamSessionTestHQ,TestGreaseFramePerSession)2682 TEST_P(HQDownstreamSessionTestHQ, TestGreaseFramePerSession) {
2683   // a grease frame will be created in the first bidir stream
2684   auto idh1 = checkRequest();
2685   flushRequestsAndLoop();
2686   EXPECT_GT(socketDriver_->streams_[idh1.first].writeBuf.chainLength(), 110);
2687   FakeHTTPCodecCallback callback1;
2688   std::unique_ptr<HQStreamCodec> upstreamCodec =
2689       std::make_unique<hq::HQStreamCodec>(
2690           idh1.first,
2691           TransportDirection::UPSTREAM,
2692           qpackCodec_,
2693           encoderWriteBuf_,
2694           decoderWriteBuf_,
2695           [] { return std::numeric_limits<uint64_t>::max(); },
2696           ingressSettings_);
2697   upstreamCodec->setCallback(&callback1);
2698   upstreamCodec->onIngress(
2699       *socketDriver_->streams_[idh1.first].writeBuf.front());
2700   EXPECT_EQ(callback1.unknownFrames, 1);
2701   EXPECT_EQ(callback1.greaseFrames, 1);
2702 
2703   // no grease frame will be created in the second bidir stream
2704   auto idh2 = checkRequest();
2705   flushRequestsAndLoop();
2706   FakeHTTPCodecCallback callback2;
2707   upstreamCodec->setCallback(&callback2);
2708   upstreamCodec->onIngress(
2709       *socketDriver_->streams_[idh2.first].writeBuf.front());
2710   EXPECT_EQ(callback2.unknownFrames, 0);
2711   EXPECT_EQ(callback2.greaseFrames, 0);
2712   hqSession_->closeWhenIdle();
2713 }
2714 
TEST_P(HQDownstreamSessionTest,DelegateResponse)2715 TEST_P(HQDownstreamSessionTest, DelegateResponse) {
2716   if (!IS_HQ) {
2717     hqSession_->closeWhenIdle();
2718     return;
2719   }
2720   auto streamId = sendRequest("/cdn.thing", 0, true);
2721   InSequence handlerSequence;
2722   auto handler = addSimpleStrictHandler();
2723   handler->expectHeaders();
2724   auto dsrRequestSender = std::make_unique<MockQuicDSRRequestSender>();
2725   auto rawDsrSender = dsrRequestSender.get();
2726   handler->expectEOM([&]() {
2727     handler->txn_->setTransportCallback(&transportCallback_);
2728     EXPECT_CALL(*socketDriver_->getSocket(),
2729                 setDSRPacketizationRequestSenderRef(_, _))
2730         .Times(1)
2731         .WillOnce(Invoke(
2732             [&](StreamId,
2733                 const std::unique_ptr<quic::DSRPacketizationRequestSender>&
2734                     sender) {
2735               EXPECT_EQ(rawDsrSender, sender.get());
2736               return folly::unit;
2737             }));
2738     EXPECT_TRUE(handler->sendHeadersWithDelegate(
2739         200, 1000 * 20, std::move(dsrRequestSender)));
2740     EXPECT_GT(transportCallback_.bodyBytesGenerated_, 0);
2741     auto dataFrameHeaderSize = transportCallback_.bodyBytesGenerated_;
2742     EXPECT_TRUE(handler->txn_->isEgressStarted());
2743     handler->txn_->onWriteReady(10 * 1000, 1.0);
2744     EXPECT_EQ(transportCallback_.bodyBytesGenerated_,
2745               10 * 1000 + dataFrameHeaderSize);
2746     // from sendHeadersWithDelegate, to actually doing writeChain and
2747     // writeBufMeta, there is an extra loop. So the verification + abort also
2748     // needs to be placed in a later loop.
2749     eventBase_.runInLoop([&] {
2750       EXPECT_TRUE(transportCallback_.lastByteFlushed_);
2751       // Both onStopSending and terminate the handler can clear the buffered
2752       // BufMetas and make the transaction detachable.
2753       handler->expectDetachTransaction();
2754       hqSession_->onStopSending(streamId,
2755                                 HTTP3::ErrorCode::HTTP_REQUEST_REJECTED);
2756     });
2757   });
2758   flushRequestsAndLoop();
2759   hqSession_->closeWhenIdle();
2760 }
2761 
TEST_P(HQDownstreamSessionTest,H1QRejectsDelegate)2762 TEST_P(HQDownstreamSessionTest, H1QRejectsDelegate) {
2763   if (IS_HQ) {
2764     hqSession_->closeWhenIdle();
2765     return;
2766   }
2767   sendRequest("/cdn.thing", 0, true);
2768   InSequence handlerSequence;
2769   auto handler = addSimpleStrictHandler();
2770   handler->expectHeaders();
2771   auto dsrRequestSender = std::make_unique<MockQuicDSRRequestSender>();
2772   handler->expectEOM([&]() {
2773     EXPECT_FALSE(handler->sendHeadersWithDelegate(
2774         200, 1000 * 20, std::move(dsrRequestSender)));
2775     handler->terminate();
2776   });
2777   handler->expectDetachTransaction();
2778   flushRequestsAndLoop();
2779   hqSession_->closeWhenIdle();
2780 }
2781 
TEST_P(HQDownstreamSessionTest,getHTTPPriority)2782 TEST_P(HQDownstreamSessionTest, getHTTPPriority) {
2783   folly::Optional<HTTPPriority> expectedResults = HTTPPriority{1, true};
2784 
2785   auto request = getProgressiveGetRequest();
2786   sendRequest(request);
2787   auto handler = addSimpleStrictHandler();
2788   handler->expectHeaders();
2789   handler->expectEOM([&]() {
2790     auto resp = makeResponse(200, 0);
2791 
2792     if (!IS_HQ) { // H1Q tests do not support priority
2793       EXPECT_EQ(handler->txn_->getHTTPPriority(), folly::none);
2794     } else {
2795       EXPECT_CALL(*socketDriver_->getSocket(),
2796                   getStreamPriority(handler->txn_->getID()))
2797           .WillOnce(Return(quic::Priority(expectedResults.value().urgency,
2798                                           expectedResults.value().incremental)))
2799           .WillOnce(
2800               Return(folly::makeUnexpected(LocalErrorCode::STREAM_NOT_EXISTS)))
2801           .WillOnce(
2802               Return(quic::Priority(expectedResults.value().urgency,
2803                                     expectedResults.value().incremental)));
2804 
2805       auto urgencyIncremental = handler->txn_->getHTTPPriority().value();
2806       EXPECT_EQ(urgencyIncremental.urgency, expectedResults.value().urgency);
2807       EXPECT_EQ(urgencyIncremental.incremental,
2808                 expectedResults.value().incremental);
2809       EXPECT_EQ(handler->txn_->getHTTPPriority(), folly::none);
2810     }
2811     handler->sendRequest(*std::get<0>(resp));
2812   });
2813   handler->expectDetachTransaction();
2814   flushRequestsAndLoop();
2815   hqSession_->closeWhenIdle();
2816 }
2817 
2818 /**
2819  * Instantiate the Parametrized test cases
2820  */
2821 
2822 // Make sure all the tests keep working with all the supported protocol versions
2823 INSTANTIATE_TEST_CASE_P(HQDownstreamSessionTest,
2824                         HQDownstreamSessionTest,
2825                         Values(
__anond237a0707c02null2826                             [] {
2827                               TestParams tp;
2828                               tp.alpn_ = "h1q-fb";
2829                               return tp;
2830                             }(),
__anond237a0707d02null2831                             [] {
2832                               TestParams tp;
2833                               tp.alpn_ = "h1q-fb-v2";
2834                               return tp;
2835                             }(),
__anond237a0707e02null2836                             [] {
2837                               TestParams tp;
2838                               tp.alpn_ = "h3";
2839                               return tp;
2840                             }()),
2841                         paramsToTestName);
2842 
2843 // Instantiate h1q only tests that work on all versions
2844 INSTANTIATE_TEST_CASE_P(HQDownstreamSessionTest,
2845                         HQDownstreamSessionTestH1q,
2846                         Values(
__anond237a0707f02null2847                             [] {
2848                               TestParams tp;
2849                               tp.alpn_ = "h1q-fb";
2850                               return tp;
2851                             }(),
__anond237a0708002null2852                             [] {
2853                               TestParams tp;
2854                               tp.alpn_ = "h1q-fb-v2";
2855                               return tp;
2856                             }()),
2857                         paramsToTestName);
2858 
2859 // Instantiate common tests for h1q-fb-v2 and hq (goaway)
2860 INSTANTIATE_TEST_CASE_P(HQDownstreamSessionTest,
2861                         HQDownstreamSessionTestH1qv2HQ,
2862                         Values(
__anond237a0708102null2863                             [] {
2864                               TestParams tp;
2865                               tp.alpn_ = "h1q-fb-v2";
2866                               return tp;
2867                             }(),
__anond237a0708202null2868                             [] {
2869                               TestParams tp;
2870                               tp.alpn_ = "h3";
2871                               return tp;
2872                             }()),
2873                         paramsToTestName);
2874 
2875 INSTANTIATE_TEST_CASE_P(HQDownstreamSessionTest,
2876                         HQDownstreamSessionFilterTestHQ,
__anond237a0708302null2877                         Values([] {
2878                           TestParams tp;
2879                           tp.alpn_ = "h3";
2880                           tp.createQPACKStreams_ = true;
2881                           tp.shouldSendSettings_ = false;
2882                           return tp;
2883                         }()),
2884                         paramsToTestName);
2885 
2886 INSTANTIATE_TEST_CASE_P(HQDownstreamSessionBeforeTransportReadyTest,
2887                         HQDownstreamSessionBeforeTransportReadyTest,
2888                         Values(
__anond237a0708402null2889                             [] {
2890                               TestParams tp;
2891                               tp.alpn_ = "h1q-fb-v2";
2892                               return tp;
2893                             }(),
__anond237a0708502null2894                             [] {
2895                               TestParams tp;
2896                               tp.alpn_ = "h3";
2897                               return tp;
2898                             }()),
2899                         paramsToTestName);
2900 
2901 // Instantiate h1q-fb-v1 only tests
2902 INSTANTIATE_TEST_CASE_P(HQDownstreamSessionTest,
2903                         HQDownstreamSessionTestH1qv1,
__anond237a0708602null2904                         Values([] {
2905                           TestParams tp;
2906                           tp.alpn_ = "h1q-fb";
2907                           return tp;
2908                         }()),
2909                         paramsToTestName);
2910 
2911 // Instantiate hq only tests
2912 INSTANTIATE_TEST_CASE_P(HQDownstreamSessionTest,
2913                         HQDownstreamSessionTestHQ,
__anond237a0708702null2914                         Values([] {
2915                           TestParams tp;
2916                           tp.alpn_ = "h3";
2917                           return tp;
2918                         }()),
2919                         paramsToTestName);
2920 
TEST_P(HQDownstreamSessionTestHQPush,SimplePush)2921 TEST_P(HQDownstreamSessionTestHQPush, SimplePush) {
2922   auto id = sendRequest("/", 1);
2923   HTTPMessage promiseReq, res;
2924   promiseReq.getHeaders().set(HTTP_HEADER_HOST, "www.foo.com");
2925   promiseReq.setURL("/");
2926   res.setStatusCode(200);
2927   res.setStatusMessage("Ohai");
2928 
2929   auto handler = addSimpleStrictHandler();
2930   StrictMock<MockHTTPPushHandler> pushHandler;
2931   handler->expectHeaders();
2932   HTTPCodec::StreamID pushStreamId = 0;
2933   handler->expectEOM([&] {
2934     // Generate response for the associated stream
2935     handler->txn_->sendHeaders(res);
2936     handler->txn_->sendBody(makeBuf(100));
2937 
2938     // Different from H2, this counts as an outgoing stream as soon as the
2939     // txn is created.
2940     // TODO: maybe create the stream lazily when trying to send the real
2941     // headers instead?
2942     auto outgoingStreams = hqSession_->getNumOutgoingStreams();
2943     auto* pushTxn = handler->txn_->newPushedTransaction(&pushHandler);
2944     ASSERT_NE(pushTxn, nullptr);
2945     EXPECT_EQ(hqSession_->getNumOutgoingStreams(), outgoingStreams + 1);
2946     // Generate a push request (PUSH_PROMISE)
2947     pushTxn->sendHeaders(promiseReq);
2948     pushStreamId = pushTxn->getID();
2949     LOG(INFO) << "pushStreamId=" << pushStreamId;
2950     pushTxn->sendHeaders(res);
2951     pushTxn->sendBody(makeBuf(200));
2952     pushTxn->sendEOM();
2953   });
2954   EXPECT_CALL(pushHandler, setTransaction(_))
2955       .WillOnce(Invoke([&](HTTPTransaction* txn) { pushHandler.txn_ = txn; }));
2956   EXPECT_CALL(pushHandler, detachTransaction());
2957 
2958   flushRequestsAndLoopN(1);
2959   handler->txn_->sendEOM();
2960   handler->expectDetachTransaction();
2961   flushRequestsAndLoop();
2962   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
2963   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
2964   auto pushIt = pushes_.find(pushStreamId);
2965   ASSERT_TRUE(pushIt != pushes_.end());
2966   EXPECT_GT(socketDriver_->streams_[pushIt->first].writeBuf.chainLength(), 110);
2967   EXPECT_TRUE(socketDriver_->streams_[pushIt->first].writeEOF);
2968   hqSession_->closeWhenIdle();
2969 }
2970 
TEST_P(HQDownstreamSessionTestHQPush,PushPriorityCallback)2971 TEST_P(HQDownstreamSessionTestHQPush, PushPriorityCallback) {
2972   auto id = sendRequest("/", 1);
2973   HTTPMessage promiseReq, res;
2974   promiseReq.getHeaders().set(HTTP_HEADER_HOST, "www.foo.com");
2975   promiseReq.setURL("/");
2976   res.setStatusCode(200);
2977   res.setStatusMessage("Ohai");
2978 
2979   auto handler = addSimpleStrictHandler();
2980   StrictMock<MockHTTPPushHandler> pushHandler;
2981   handler->expectHeaders();
2982   HTTPCodec::StreamID pushStreamId = 0;
2983   handler->expectEOM([&] {
2984     handler->txn_->sendHeaders(res);
2985     handler->txn_->sendBody(makeBuf(100));
2986 
2987     auto outgoingStreams = hqSession_->getNumOutgoingStreams();
2988     auto* pushTxn = handler->txn_->newPushedTransaction(&pushHandler);
2989     ASSERT_NE(pushTxn, nullptr);
2990     EXPECT_EQ(hqSession_->getNumOutgoingStreams(), outgoingStreams + 1);
2991     // Generate a push request (PUSH_PROMISE)
2992     pushTxn->sendHeaders(promiseReq);
2993     pushStreamId = pushTxn->getID();
2994     pushTxn->sendHeaders(res);
2995     pushTxn->sendBody(makeBuf(200));
2996     pushTxn->sendEOM();
2997   });
2998   EXPECT_CALL(pushHandler, setTransaction(_))
2999       .WillOnce(Invoke([&](HTTPTransaction* txn) { pushHandler.txn_ = txn; }));
3000   EXPECT_CALL(pushHandler, detachTransaction());
3001 
3002   flushRequestsAndLoopN(1);
3003 
3004   // Push stream's priority can be updated either with stream id or push id:
3005   auto pushId = pushes_.find(pushStreamId)->second;
3006   EXPECT_CALL(*socketDriver_->getSocket(),
3007               setStreamPriority(pushStreamId, 6, true));
3008   hqSession_->onPushPriority(pushId, HTTPPriority(6, true));
3009   EXPECT_CALL(*socketDriver_->getSocket(),
3010               setStreamPriority(pushStreamId, 5, true));
3011   hqSession_->onPriority(pushStreamId, HTTPPriority(5, true));
3012 
3013   handler->txn_->sendEOM();
3014   handler->expectDetachTransaction();
3015   flushRequestsAndLoop();
3016   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
3017   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
3018   auto pushIt = pushes_.find(pushStreamId);
3019   ASSERT_TRUE(pushIt != pushes_.end());
3020   EXPECT_GT(socketDriver_->streams_[pushIt->first].writeBuf.chainLength(), 110);
3021   EXPECT_TRUE(socketDriver_->streams_[pushIt->first].writeEOF);
3022   hqSession_->closeWhenIdle();
3023 }
3024 
TEST_P(HQDownstreamSessionTestHQPush,StopSending)3025 TEST_P(HQDownstreamSessionTestHQPush, StopSending) {
3026   auto id = sendRequest("/", 1);
3027   HTTPMessage req, res;
3028   req.getHeaders().set("HOST", "www.foo.com");
3029   req.setURL("https://www.foo.com/");
3030   res.setStatusCode(200);
3031   res.setStatusMessage("Ohai");
3032 
3033   auto handler = addSimpleStrictHandler();
3034   StrictMock<MockHTTPPushHandler> pushHandler;
3035   handler->expectHeaders();
3036   HTTPCodec::StreamID pushStreamId = 0;
3037   handler->expectEOM([&] {
3038     // Generate response for the associated stream
3039     handler->txn_->sendHeaders(res);
3040     handler->txn_->sendBody(makeBuf(100));
3041 
3042     // Different from H2, this counts as an outgoing stream as soon as the
3043     // txn is created.
3044     // TODO: maybe create the stream lazily when trying to send the real
3045     // headers instead?
3046     auto outgoingStreams = hqSession_->getNumOutgoingStreams();
3047     auto* pushTxn = handler->txn_->newPushedTransaction(&pushHandler);
3048     ASSERT_NE(pushTxn, nullptr);
3049     EXPECT_EQ(hqSession_->getNumOutgoingStreams(), outgoingStreams + 1);
3050     // Generate a push request (PUSH_PROMISE)
3051     pushTxn->sendHeaders(req);
3052     pushStreamId = pushTxn->getID();
3053     LOG(INFO) << "pushStreamId=" << pushStreamId;
3054     pushTxn->sendHeaders(res);
3055     pushTxn->sendBody(makeBuf(200));
3056     // NO EOM
3057   });
3058   EXPECT_CALL(pushHandler, setTransaction(_))
3059       .WillOnce(Invoke([&](HTTPTransaction* txn) { pushHandler.txn_ = txn; }));
3060   EXPECT_CALL(pushHandler, onError(_));
3061   EXPECT_CALL(pushHandler, detachTransaction());
3062 
3063   flushRequestsAndLoopN(1);
3064   handler->txn_->sendEOM();
3065   handler->expectDetachTransaction();
3066   flushRequestsAndLoop();
3067   EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 110);
3068   EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
3069   auto pushIt = pushes_.find(pushStreamId);
3070   ASSERT_TRUE(pushIt != pushes_.end());
3071   EXPECT_GT(socketDriver_->streams_[pushIt->first].writeBuf.chainLength(), 110);
3072   EXPECT_FALSE(socketDriver_->streams_[pushIt->first].writeEOF);
3073   // Cancel the push with stop sending
3074   socketDriver_->addStopSending(pushIt->first,
3075                                 HTTP3::ErrorCode::HTTP_REQUEST_CANCELLED);
3076   flushRequestsAndLoop();
3077   hqSession_->closeWhenIdle();
3078 }
3079 
3080 using DropConnectionInTransportReadyTest =
3081     HQDownstreamSessionBeforeTransportReadyTest;
3082 
3083 INSTANTIATE_TEST_CASE_P(DropConnectionInTransportReadyTest,
3084                         DropConnectionInTransportReadyTest,
3085                         Values(
__anond237a0708e02null3086                             [] {
3087                               TestParams tp;
3088                               tp.alpn_ = "unsupported";
3089                               tp.expectOnTransportReady = false;
3090                               return tp;
3091                             }(),
__anond237a0708f02null3092                             [] {
3093                               TestParams tp;
3094                               tp.alpn_ = "h3";
3095                               tp.unidirectionalStreamsCredit = 1;
3096                               tp.expectOnTransportReady = false;
3097                               return tp;
3098                             }(),
__anond237a0709002null3099                             [] {
3100                               TestParams tp;
3101                               tp.alpn_ = "h1q-fb-v2";
3102                               tp.unidirectionalStreamsCredit = 0;
3103                               tp.expectOnTransportReady = false;
3104                               return tp;
3105                             }()),
3106                         paramsToTestName);
3107 // Instantiate hq server push tests
3108 INSTANTIATE_TEST_CASE_P(HQDownstreamSessionTest,
3109                         HQDownstreamSessionTestHQPush,
__anond237a0709102null3110                         Values([] {
3111                           TestParams tp;
3112                           tp.alpn_ = "h3";
3113                           tp.unidirectionalStreamsCredit = 8;
3114                           return tp;
3115                         }()),
3116                         paramsToTestName);
3117 
3118 // Use this test class for mismatched alpn tests
3119 class HQDownstreamSessionTestUnsupportedAlpn : public HQDownstreamSessionTest {
3120  public:
SetUp()3121   void SetUp() override {
3122     SetUpBase();
3123   }
3124 };
3125 
TEST_P(DropConnectionInTransportReadyTest,TransportReadyFailure)3126 TEST_P(DropConnectionInTransportReadyTest, TransportReadyFailure) {
3127   HQDownstreamSession::DestructorGuard dg(hqSession_);
3128   EXPECT_CALL(infoCb_, onTransportReady(_)).Times(0);
3129   EXPECT_CALL(infoCb_, onConnectionError(_))
3130       .WillOnce(Invoke([](const HTTPSessionBase& session) {
3131         const auto hqSession = dynamic_cast<const HQSession*>(&session);
3132         ASSERT_NE(hqSession, nullptr);
3133         ASSERT_NE(hqSession->getQuicSocket(), nullptr);
3134       }));
3135   SetUpOnTransportReady();
3136   EXPECT_EQ(hqSession_->getQuicSocket(), nullptr);
3137 }
3138 
TEST_P(HQDownstreamSessionTestHQDeliveryAck,DropConnectionWithDeliveryAckCbSetError)3139 TEST_P(HQDownstreamSessionTestHQDeliveryAck,
3140        DropConnectionWithDeliveryAckCbSetError) {
3141   auto req = getGetRequest();
3142   auto streamId = sendRequest(req);
3143   auto handler = addSimpleStrictHandler();
3144   handler->expectHeaders();
3145 
3146   // Start the response.
3147   handler->expectEOM([&]() {
3148     handler->txn_->setTransportCallback(&transportCallback_);
3149     handler->sendHeaders(200, 1723);
3150   });
3151 
3152   auto sock = socketDriver_->getSocket();
3153 
3154   // This is a copy of the one in MockQuicSocketDriver, only hijacks data stream
3155   // and forces an error.
3156   EXPECT_CALL(*sock,
3157               registerDeliveryCallback(testing::_, testing::_, testing::_))
3158       .WillRepeatedly(
3159           testing::Invoke([streamId, &socketDriver = socketDriver_](
3160                               quic::StreamId id,
3161                               uint64_t offset,
3162                               MockQuicSocket::ByteEventCallback* cb)
3163                               -> folly::Expected<folly::Unit, LocalErrorCode> {
3164             if (id == streamId) {
3165               return folly::makeUnexpected(LocalErrorCode::INVALID_OPERATION);
3166             }
3167 
3168             socketDriver->checkNotReadOnlyStream(id);
3169             auto it = socketDriver->streams_.find(id);
3170             if (it == socketDriver->streams_.end() ||
3171                 it->second.writeOffset >= offset) {
3172               return folly::makeUnexpected(LocalErrorCode::STREAM_NOT_EXISTS);
3173             }
3174             CHECK_NE(it->second.writeState,
3175                      MockQuicSocketDriver::StateEnum::CLOSED);
3176             it->second.deliveryCallbacks.push_back({offset, cb});
3177             return folly::unit;
3178           }));
3179 
3180   EXPECT_CALL(*handler, onError(_))
3181       .WillOnce(Invoke([](const HTTPException& error) {
3182         EXPECT_TRUE(std::string(error.what())
3183                         .find("failed to register delivery callback") !=
3184                     std::string::npos);
3185       }));
3186   handler->expectDetachTransaction();
3187 
3188   flushRequestsAndLoop();
3189   hqSession_->closeWhenIdle();
3190 }
3191 
TEST_P(HQDownstreamSessionTestHQDeliveryAck,TestBodyDeliveryAck)3192 TEST_P(HQDownstreamSessionTestHQDeliveryAck, TestBodyDeliveryAck) {
3193   auto req = getGetRequest();
3194   sendRequest(req);
3195   auto handler = addSimpleStrictHandler();
3196   handler->expectHeaders();
3197 
3198   // Start the response.
3199   handler->expectEOM([&]() {
3200     handler->txn_->setTransportCallback(&transportCallback_);
3201     handler->sendHeaders(200, 42);
3202     auto res = handler->txn_->setBodyLastByteDeliveryTrackingEnabled(true);
3203     EXPECT_TRUE(res);
3204     handler->sendBody(42);
3205     handler->sendEOM();
3206   });
3207 
3208   handler->expectDetachTransaction();
3209   flushRequestsAndLoop();
3210   EXPECT_EQ(transportCallback_.numBodyBytesDeliveredCalls_, 1);
3211   EXPECT_EQ(transportCallback_.bodyBytesDeliveredOffset_, 41);
3212 
3213   hqSession_->closeWhenIdle();
3214 }
3215 
TEST_P(HQDownstreamSessionTestHQDeliveryAck,TestBodyDeliveryAckMultiple)3216 TEST_P(HQDownstreamSessionTestHQDeliveryAck, TestBodyDeliveryAckMultiple) {
3217   auto req = getGetRequest();
3218   sendRequest(req);
3219   auto handler = addSimpleStrictHandler();
3220   handler->expectHeaders();
3221 
3222   // Start the response.
3223   handler->expectEOM([&]() {
3224     handler->txn_->setTransportCallback(&transportCallback_);
3225     handler->sendHeaders(200, 42 + 17);
3226     auto res = handler->txn_->setBodyLastByteDeliveryTrackingEnabled(true);
3227     EXPECT_TRUE(res);
3228     handler->sendBody(42);
3229     handler->sendBody(17);
3230     handler->sendEOM();
3231   });
3232 
3233   handler->expectDetachTransaction();
3234   flushRequestsAndLoop();
3235   EXPECT_EQ(transportCallback_.numBodyBytesDeliveredCalls_, 2);
3236   EXPECT_EQ(transportCallback_.bodyBytesDeliveredOffset_, 41 + 17);
3237 
3238   hqSession_->closeWhenIdle();
3239 }
3240 
TEST_P(HQDownstreamSessionTestHQDeliveryAck,TestBodyDeliveryErr)3241 TEST_P(HQDownstreamSessionTestHQDeliveryAck, TestBodyDeliveryErr) {
3242   auto req = getGetRequest();
3243   auto streamId = sendRequest(req);
3244   auto handler = addSimpleStrictHandler();
3245   handler->expectHeaders();
3246 
3247   // Start the response.
3248   handler->expectEOM([&]() {
3249     handler->txn_->setTransportCallback(&transportCallback_);
3250     handler->sendHeaders(200, 42);
3251     auto res = handler->txn_->setBodyLastByteDeliveryTrackingEnabled(true);
3252     EXPECT_TRUE(res);
3253   });
3254   flushRequestsAndLoop();
3255   EXPECT_TRUE(transportCallback_.lastEgressHeadersByteDelivered_);
3256 
3257   // One day, txn_->sendHeaders() will return number of bytes written, and we
3258   // won't need this. For now, H3 frame headers size is 2 bytes.
3259   const uint64_t frameHeaderSize = 2;
3260   const uint64_t streamOffsetAfterHeaders =
3261       (2 * frameHeaderSize) + transportCallback_.headerBytesGenerated_;
3262 
3263   auto sock = socketDriver_->getSocket();
3264 
3265   // This is a copy of the one in MockQuicSocketDriver, only hijacks data stream
3266   // and forces an error.
3267   EXPECT_CALL(*sock,
3268               registerDeliveryCallback(testing::_, testing::_, testing::_))
3269       .WillRepeatedly(testing::Invoke(
3270           [streamId,
3271            &streamOffsetAfterHeaders = streamOffsetAfterHeaders,
3272            &socketDriver = socketDriver_](quic::StreamId id,
3273                                           uint64_t offset,
3274                                           MockQuicSocket::ByteEventCallback* cb)
3275               -> folly::Expected<folly::Unit, LocalErrorCode> {
3276             if (id == streamId && offset > streamOffsetAfterHeaders) {
3277               for (auto& it : socketDriver->streams_) {
3278                 auto& stream = it.second;
3279                 stream.readState = quic::MockQuicSocketDriver::ERROR;
3280                 stream.writeState = quic::MockQuicSocketDriver::ERROR;
3281               }
3282               return folly::makeUnexpected(LocalErrorCode::INVALID_OPERATION);
3283             }
3284 
3285             socketDriver->checkNotReadOnlyStream(id);
3286             auto it = socketDriver->streams_.find(id);
3287             if (it == socketDriver->streams_.end() ||
3288                 it->second.writeOffset >= offset) {
3289               return folly::makeUnexpected(LocalErrorCode::STREAM_NOT_EXISTS);
3290             }
3291             CHECK_NE(it->second.writeState,
3292                      MockQuicSocketDriver::StateEnum::CLOSED);
3293             it->second.deliveryCallbacks.push_back({offset, cb});
3294             return folly::unit;
3295           }));
3296 
3297   EXPECT_CALL(*handler, onError(_))
3298       .WillOnce(Invoke([&handler = handler](const HTTPException& error) {
3299         EXPECT_TRUE(std::string(error.what())
3300                         .find("failed to register delivery callback") !=
3301                     std::string::npos);
3302         handler->txn_->sendAbort();
3303       }));
3304 
3305   handler->expectDetachTransaction();
3306 
3307   handler->sendBody(42);
3308   flushRequestsAndLoop();
3309 }
3310 
TEST_P(HQDownstreamSessionTestHQDeliveryAck,TestBodyDeliveryCancel)3311 TEST_P(HQDownstreamSessionTestHQDeliveryAck, TestBodyDeliveryCancel) {
3312   auto req = getGetRequest();
3313   sendRequest(req);
3314   auto handler = addSimpleStrictHandler();
3315   handler->expectHeaders();
3316 
3317   // Start the response.
3318   handler->expectEOM([&]() {
3319     handler->txn_->setTransportCallback(&transportCallback_);
3320     handler->sendHeaders(200, 42);
3321     auto res = handler->txn_->setBodyLastByteDeliveryTrackingEnabled(true);
3322     EXPECT_TRUE(res);
3323     handler->sendBody(42);
3324     // handler->sendEOM();
3325   });
3326 
3327   flushRequestsAndLoopN(1);
3328 
3329   EXPECT_CALL(*handler, onError(_)).Times(1);
3330   handler->expectDetachTransaction();
3331   socketDriver_->deliverErrorOnAllStreams(
3332       std::make_pair(LocalErrorCode::INVALID_OPERATION, "fake error"));
3333   flushRequestsAndLoop();
3334 
3335   EXPECT_EQ(transportCallback_.numBodyBytesCanceledCalls_, 1);
3336   EXPECT_EQ(transportCallback_.bodyBytesCanceledOffset_, 41);
3337 }
3338 
3339 INSTANTIATE_TEST_CASE_P(HQDownstreamSessionTest,
3340                         HQDownstreamSessionTestHQDeliveryAck,
__anond237a0709c02null3341                         Values([] {
3342                           TestParams tp;
3343                           tp.alpn_ = "h3";
3344                           return tp;
3345                         }()),
3346                         paramsToTestName);
3347