1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9 #include <proxygen/lib/http/session/test/HQUpstreamSessionTest.h>
10
11 #include <proxygen/lib/http/codec/CodecUtil.h>
12 #include <proxygen/lib/http/session/HQUpstreamSession.h>
13
14 #include <folly/futures/Future.h>
15 #include <folly/portability/GTest.h>
16 #include <limits>
17 #include <proxygen/lib/http/HTTPHeaderSize.h>
18 #include <proxygen/lib/http/codec/HQControlCodec.h>
19 #include <proxygen/lib/http/codec/HQStreamCodec.h>
20 #include <proxygen/lib/http/codec/HQUnidirectionalCodec.h>
21 #include <proxygen/lib/http/codec/HTTP1xCodec.h>
22 #include <proxygen/lib/http/codec/test/TestUtils.h>
23 #include <proxygen/lib/http/session/test/HQSessionMocks.h>
24 #include <proxygen/lib/http/session/test/HQSessionTestCommon.h>
25 #include <proxygen/lib/http/session/test/HTTPSessionMocks.h>
26 #include <proxygen/lib/http/session/test/HTTPTransactionMocks.h>
27 #include <proxygen/lib/http/session/test/MockQuicSocketDriver.h>
28 #include <proxygen/lib/http/session/test/TestUtils.h>
29 #include <quic/api/test/MockQuicSocket.h>
30 #include <wangle/acceptor/ConnectionManager.h>
31
32 using namespace proxygen;
33 using namespace proxygen::hq;
34 using namespace quic;
35 using namespace folly;
36 using namespace testing;
37 using namespace std::chrono;
38
39 namespace {
40 constexpr quic::StreamId kQPACKEncoderIngressStreamId = 7;
41 constexpr quic::StreamId kQPACKDecoderEgressStreamId = 10;
42 } // namespace
43
44 std::pair<HTTPCodec::StreamID, std::unique_ptr<HTTPCodec>>
makeCodec(HTTPCodec::StreamID id)45 HQUpstreamSessionTest::makeCodec(HTTPCodec::StreamID id) {
46 if (IS_HQ) {
47 return {id,
48 std::make_unique<hq::HQStreamCodec>(
49 id,
50 TransportDirection::DOWNSTREAM,
51 qpackCodec_,
52 encoderWriteBuf_,
53 decoderWriteBuf_,
54 [] { return std::numeric_limits<uint64_t>::max(); },
55 ingressSettings_)};
56 } else {
57 auto codec = std::make_unique<HTTP1xCodec>(TransportDirection::DOWNSTREAM);
58 // When the codec is created, need to fake the request
59 FakeHTTPCodecCallback cb;
60 codec->setCallback(&cb);
61 codec->onIngress(*folly::IOBuf::copyBuffer("GET / HTTP/1.1\r\n\r\n"));
62 return {1, std::move(codec)};
63 }
64 }
65
sendResponse(quic::StreamId id,const HTTPMessage & resp,std::unique_ptr<folly::IOBuf> body,bool eom)66 void HQUpstreamSessionTest::sendResponse(quic::StreamId id,
67 const HTTPMessage& resp,
68 std::unique_ptr<folly::IOBuf> body,
69 bool eom) {
70 auto c = makeCodec(id);
71 auto res =
72 streams_.emplace(std::piecewise_construct,
73 std::forward_as_tuple(id),
74 std::forward_as_tuple(c.first, std::move(c.second)));
75 auto& stream = res.first->second;
76 stream.readEOF = eom;
77 stream.codec->generateHeader(
78 stream.buf, stream.codecId, resp, body == nullptr ? eom : false);
79 if (body && body->computeChainDataLength() > 0) {
80 stream.codec->generateBody(
81 stream.buf, stream.codecId, std::move(body), folly::none, eom);
82 }
83 }
84
sendPartialBody(quic::StreamId id,std::unique_ptr<folly::IOBuf> body,bool eom)85 void HQUpstreamSessionTest::sendPartialBody(quic::StreamId id,
86 std::unique_ptr<folly::IOBuf> body,
87 bool eom) {
88 auto it = streams_.find(id);
89 CHECK(it != streams_.end());
90 auto& stream = it->second;
91
92 stream.readEOF = eom;
93 if (body) {
94 stream.codec->generateBody(
95 stream.buf, stream.codecId, std::move(body), folly::none, eom);
96 }
97 }
98
nextUnidirectionalStreamId()99 quic::StreamId HQUpstreamSessionTest::nextUnidirectionalStreamId() {
100 auto id = nextUnidirectionalStreamId_;
101 nextUnidirectionalStreamId_ += 4;
102 return id;
103 }
104
SetUp()105 void HQUpstreamSessionTest::SetUp() {
106 HQSessionTest::SetUp();
107 dynamic_cast<HQUpstreamSession*>(hqSession_)->setConnectCallback(&connectCb_);
108
109 EXPECT_CALL(connectCb_, connectSuccess());
110
111 hqSession_->onTransportReady();
112
113 createControlStreams();
114
115 flushAndLoop();
116 if (IS_HQ) {
117 EXPECT_EQ(httpCallbacks_.settings, 1);
118 }
119 }
120
TearDown()121 void HQUpstreamSessionTest::TearDown() {
122 if (!IS_H1Q_FB_V1) {
123 // With control streams we may need an extra loop for proper shutdown
124 if (!socketDriver_->isClosed()) {
125 // Send the first GOAWAY with MAX_STREAM_ID immediately
126 sendGoaway(HTTPCodec::MaxStreamID);
127 // Schedule the second GOAWAY with the last seen stream ID, after some
128 // delay
129 sendGoaway(socketDriver_->getMaxStreamId(), milliseconds(50));
130 }
131 eventBase_.loopOnce();
132 }
133 }
134
sendGoaway(quic::StreamId lastStreamId,milliseconds delay)135 void HQUpstreamSessionTest::sendGoaway(quic::StreamId lastStreamId,
136 milliseconds delay) {
137 folly::IOBufQueue writeBuf{folly::IOBufQueue::cacheChainLength()};
138 egressControlCodec_->generateGoaway(
139 writeBuf, lastStreamId, ErrorCode::NO_ERROR);
140 socketDriver_->addReadEvent(connControlStreamId_, writeBuf.move(), delay);
141 }
142
143 template <class HandlerType>
144 std::unique_ptr<StrictMock<HandlerType>>
openTransactionBase(bool expectStartPaused)145 HQUpstreamSessionTest::openTransactionBase(bool expectStartPaused) {
146 // Returns a mock handler with txn_ field set in it
147 auto handler = std::make_unique<StrictMock<HandlerType>>();
148 handler->expectTransaction();
149 if (expectStartPaused) {
150 handler->expectEgressPaused();
151 }
152 HTTPTransaction* txn = hqSession_->newTransaction(handler.get());
153 EXPECT_EQ(txn, handler->txn_);
154 return handler;
155 }
156
157 std::unique_ptr<StrictMock<MockHTTPHandler>>
openTransaction()158 HQUpstreamSessionTest::openTransaction() {
159 return openTransactionBase<MockHTTPHandler>();
160 }
161
flushAndLoop(bool eof,milliseconds eofDelay,milliseconds initialDelay,std::function<void ()> extraEventsFn)162 void HQUpstreamSessionTest::flushAndLoop(bool eof,
163 milliseconds eofDelay,
164 milliseconds initialDelay,
165 std::function<void()> extraEventsFn) {
166 flush(eof, eofDelay, initialDelay, extraEventsFn);
167 CHECK(eventBase_.loop());
168 }
169
flushAndLoopN(uint64_t n,bool eof,milliseconds eofDelay,milliseconds initialDelay,std::function<void ()> extraEventsFn)170 void HQUpstreamSessionTest::flushAndLoopN(uint64_t n,
171 bool eof,
172 milliseconds eofDelay,
173 milliseconds initialDelay,
174 std::function<void()> extraEventsFn) {
175 flush(eof, eofDelay, initialDelay, extraEventsFn);
176 for (uint64_t i = 0; i < n; i++) {
177 eventBase_.loopOnce();
178 }
179 }
180
flush(bool eof,milliseconds eofDelay,milliseconds initialDelay,std::function<void ()> extraEventsFn)181 bool HQUpstreamSessionTest::flush(bool eof,
182 milliseconds eofDelay,
183 milliseconds initialDelay,
184 std::function<void()> extraEventsFn) {
185 bool done = true;
186 if (!encoderWriteBuf_.empty()) {
187 socketDriver_->addReadEvent(
188 kQPACKEncoderIngressStreamId, encoderWriteBuf_.move(), milliseconds(0));
189 }
190 for (auto& stream : streams_) {
191 if (socketDriver_->isStreamIdle(stream.first)) {
192 continue;
193 }
194 if (stream.second.buf.chainLength() > 0) {
195 socketDriver_->addReadEvent(
196 stream.first, stream.second.buf.move(), initialDelay);
197 done = false;
198 }
199 // EOM -> stream EOF
200 if (stream.second.readEOF) {
201 socketDriver_->addReadEOF(stream.first, eofDelay);
202 done = false;
203 }
204 }
205 if (!socketDriver_->inDatagrams_.empty()) {
206 socketDriver_->addDatagramsAvailableReadEvent(initialDelay);
207 }
208 if (extraEventsFn) {
209 extraEventsFn();
210 }
211 if (eof || eofDelay.count() > 0) {
212 /* wonkiness. Should somehow close the connection?
213 * socketDriver_->addReadEOF(1, eofDelay);
214 */
215 }
216 return done;
217 }
218
getMockController()219 StrictMock<MockController>& HQUpstreamSessionTest::getMockController() {
220 return controllerContainer_.mockController;
221 }
222
223 // Use this test class for h1q-fb-v1 only tests
224 using HQUpstreamSessionTestH1qv1 = HQUpstreamSessionTest;
225 // Use this test class for h1q-fb-v2 and hq tests
226 using HQUpstreamSessionTestH1qv2HQ = HQUpstreamSessionTest;
227 // Use this test class for hq only tests
228 using HQUpstreamSessionTestHQ = HQUpstreamSessionTest;
229 // Use this test class for hq only tests with qpack encoder streams on/off
230 using HQUpstreamSessionTestQPACK = HQUpstreamSessionTest;
231 // Use this test class for hq only tests with Datagram support
232 using HQUpstreamSessionTestHQDatagram = HQUpstreamSessionTest;
233
TEST_P(HQUpstreamSessionTest,SimpleGet)234 TEST_P(HQUpstreamSessionTest, SimpleGet) {
235 auto handler = openTransaction();
236 handler->txn_->sendHeaders(getGetRequest());
237 handler->txn_->sendEOM();
238 handler->expectHeaders();
239 handler->expectBody();
240 handler->expectEOM();
241 handler->expectDetachTransaction();
242 auto resp = makeResponse(200, 100);
243 sendResponse(handler->txn_->getID(),
244 *std::get<0>(resp),
245 std::move(std::get<1>(resp)),
246 true);
247 flushAndLoop();
248 hqSession_->closeWhenIdle();
249 }
250
251 // H1Q does not support trailers, since it requires the messages to use HTTP
252 // chunk encoding
TEST_P(HQUpstreamSessionTestHQ,GetWithTrailers)253 TEST_P(HQUpstreamSessionTestHQ, GetWithTrailers) {
254 auto handler = openTransaction();
255 auto req = getGetRequest();
256 handler->txn_->sendHeaders(req);
257 HTTPHeaders trailers;
258 trailers.add("x-trailer-1", "trailer1");
259 handler->txn_->sendTrailers(trailers);
260 handler->txn_->sendEOM();
261 handler->expectHeaders();
262 handler->expectBody();
263 handler->expectTrailers();
264 handler->expectEOM();
265 handler->expectDetachTransaction();
266 auto resp = makeResponse(200, 100);
267 auto id = handler->txn_->getID();
268 sendResponse(id, *std::get<0>(resp), std::move(std::get<1>(resp)), false);
269 auto it = streams_.find(id);
270 CHECK(it != streams_.end());
271 auto& stream = it->second;
272 trailers.remove("x-trailer-1");
273 trailers.add("x-trailer-2", "trailer2");
274 stream.codec->generateTrailers(stream.buf, stream.codecId, trailers);
275 stream.codec->generateEOM(stream.buf, stream.codecId);
276 stream.readEOF = true;
277 flushAndLoop();
278 hqSession_->closeWhenIdle();
279 }
280
TEST_P(HQUpstreamSessionTest,PriorityUpdateIntoTransport)281 TEST_P(HQUpstreamSessionTest, PriorityUpdateIntoTransport) {
282 if (IS_HQ) {
283 auto handler = openTransaction();
284 auto req = getGetRequest();
285 req.getHeaders().add(HTTP_HEADER_PRIORITY, "u=3, i");
286 EXPECT_CALL(*socketDriver_->getSocket(), setStreamPriority(_, 3, true));
287 handler->txn_->sendHeadersWithEOM(req);
288
289 handler->expectHeaders();
290 handler->expectBody();
291 handler->expectEOM();
292 handler->expectDetachTransaction();
293 auto resp = makeResponse(200, 100);
294 std::get<0>(resp)->getHeaders().add(HTTP_HEADER_PRIORITY, "u=5");
295 sendResponse(handler->txn_->getID(),
296 *std::get<0>(resp),
297 std::move(std::get<1>(resp)),
298 true);
299 EXPECT_CALL(*socketDriver_->getSocket(), setStreamPriority(_, 5, false));
300 flushAndLoop();
301 }
302 hqSession_->closeWhenIdle();
303 }
304
TEST_P(HQUpstreamSessionTest,SendPriorityUpdate)305 TEST_P(HQUpstreamSessionTest, SendPriorityUpdate) {
306 if (IS_HQ) {
307 auto handler = openTransaction();
308 handler->txn_->sendHeaders(getGetRequest());
309 handler->expectHeaders();
310 handler->expectBody([&]() {
311 EXPECT_CALL(*socketDriver_->getSocket(),
312 setStreamPriority(handler->txn_->getID(), 5, true));
313 handler->txn_->updateAndSendPriority(5, true);
314 });
315 handler->txn_->sendEOM();
316 handler->expectEOM();
317 handler->expectDetachTransaction();
318 auto resp = makeResponse(200, 100);
319 sendResponse(handler->txn_->getID(),
320 *std::get<0>(resp),
321 std::move(std::get<1>(resp)),
322 true);
323 flushAndLoop();
324 }
325 hqSession_->closeWhenIdle();
326 }
327
TEST_P(HQUpstreamSessionTest,SkipPriorityUpdateAfterSeenEOM)328 TEST_P(HQUpstreamSessionTest, SkipPriorityUpdateAfterSeenEOM) {
329 if (IS_HQ) {
330 auto handler = openTransaction();
331 handler->txn_->sendHeaders(getGetRequest());
332 handler->expectHeaders();
333 handler->expectBody();
334 handler->expectEOM([&]() {
335 EXPECT_CALL(*socketDriver_->getSocket(),
336 setStreamPriority(handler->txn_->getID(), 5, true))
337 .Times(0);
338 handler->txn_->updateAndSendPriority(5, true);
339 });
340 handler->txn_->sendEOM();
341
342 handler->expectDetachTransaction();
343 auto resp = makeResponse(200, 100);
344 sendResponse(handler->txn_->getID(),
345 *std::get<0>(resp),
346 std::move(std::get<1>(resp)),
347 true);
348 flushAndLoop();
349 }
350 hqSession_->closeWhenIdle();
351 }
352
TEST_P(HQUpstreamSessionTest,NoNewTransactionIfSockIsNotGood)353 TEST_P(HQUpstreamSessionTest, NoNewTransactionIfSockIsNotGood) {
354 socketDriver_->sockGood_ = false;
355 EXPECT_EQ(hqSession_->newTransaction(nullptr), nullptr);
356 hqSession_->closeWhenIdle();
357 }
358
TEST_P(HQUpstreamSessionTest,DropConnectionWithEarlyDataFailedError)359 TEST_P(HQUpstreamSessionTest, DropConnectionWithEarlyDataFailedError) {
360 auto handler = openTransaction();
361 handler->txn_->sendHeaders(getGetRequest());
362 handler->txn_->sendEOM();
363
364 EXPECT_CALL(*handler, onError(_))
365 .WillOnce(Invoke([](const HTTPException& error) {
366 EXPECT_EQ(error.getProxygenError(), kErrorEarlyDataFailed);
367 EXPECT_TRUE(std::string(error.what()).find("quic loses race") !=
368 std::string::npos);
369 }));
370 handler->expectDetachTransaction();
371 socketDriver_->deliverConnectionError(
372 {HTTP3::ErrorCode::GIVEUP_ZERO_RTT, "quic loses race"});
373 }
374
TEST_P(HQUpstreamSessionTest,TestGetHistoricalMaxOutgoingStreams)375 TEST_P(HQUpstreamSessionTest, TestGetHistoricalMaxOutgoingStreams) {
376 EXPECT_EQ(hqSession_->getHistoricalMaxOutgoingStreams(), 0);
377 auto handler = openTransaction();
378 handler->txn_->sendHeaders(getGetRequest());
379 handler->txn_->sendEOM();
380 handler->expectHeaders();
381 handler->expectBody();
382 handler->expectEOM();
383 handler->expectDetachTransaction();
384 auto resp = makeResponse(200, 100);
385 sendResponse(handler->txn_->getID(),
386 *std::get<0>(resp),
387 std::move(std::get<1>(resp)),
388 true);
389 auto handler1 = openTransaction();
390 handler1->txn_->sendHeaders(getGetRequest());
391 handler1->txn_->sendEOM();
392 handler1->expectHeaders();
393 handler1->expectBody();
394 handler1->expectEOM();
395 handler1->expectDetachTransaction();
396 auto resp1 = makeResponse(200, 100);
397 sendResponse(handler1->txn_->getID(),
398 *std::get<0>(resp1),
399 std::move(std::get<1>(resp1)),
400 true);
401 flushAndLoop();
402 EXPECT_EQ(hqSession_->getHistoricalMaxOutgoingStreams(), 2);
403 hqSession_->closeWhenIdle();
404 }
405
TEST_P(HQUpstreamSessionTest,InjectTraceEvent)406 TEST_P(HQUpstreamSessionTest, InjectTraceEvent) {
407 EXPECT_EQ(hqSession_->getHistoricalMaxOutgoingStreams(), 0);
408
409 auto handler = openTransaction();
410 handler->expectDetachTransaction();
411
412 auto handler1 = openTransaction();
413 handler1->expectDetachTransaction();
414
415 EXPECT_CALL(*handler, traceEventAvailable(_)).Times(1);
416 EXPECT_CALL(*handler1, traceEventAvailable(_)).Times(1);
417
418 TraceEvent te(TraceEventType::TotalRequest);
419 hqSession_->injectTraceEventIntoAllTransactions(te);
420
421 handler->txn_->sendAbort();
422 handler1->txn_->sendAbort();
423
424 flushAndLoop();
425 EXPECT_EQ(hqSession_->getHistoricalMaxOutgoingStreams(), 2);
426 hqSession_->closeWhenIdle();
427 }
428
TEST_P(HQUpstreamSessionTest,ResponseTermedByFin)429 TEST_P(HQUpstreamSessionTest, ResponseTermedByFin) {
430 auto handler = openTransaction();
431 handler->txn_->sendHeaders(getGetRequest());
432 handler->txn_->sendEOM();
433 handler->expectHeaders();
434 handler->expectBody();
435 handler->expectEOM();
436 handler->expectDetachTransaction();
437 HTTPMessage resp;
438 resp.setStatusCode(200);
439 resp.setHTTPVersion(1, 0);
440 // HTTP/1.0 response with no content-length, termed by tranport FIN
441 sendResponse(handler->txn_->getID(), resp, makeBuf(100), true);
442 flushAndLoop();
443 hqSession_->closeWhenIdle();
444 }
445
TEST_P(HQUpstreamSessionTest,WaitForReplaySafeCallback)446 TEST_P(HQUpstreamSessionTest, WaitForReplaySafeCallback) {
447 auto handler = openTransaction();
448 StrictMock<folly::test::MockReplaySafetyCallback> cb1;
449 StrictMock<folly::test::MockReplaySafetyCallback> cb2;
450 StrictMock<folly::test::MockReplaySafetyCallback> cb3;
451
452 auto sock = socketDriver_->getSocket();
453 EXPECT_CALL(*sock, replaySafe()).WillRepeatedly(Return(false));
454 handler->txn_->addWaitingForReplaySafety(&cb1);
455 handler->txn_->addWaitingForReplaySafety(&cb2);
456 handler->txn_->addWaitingForReplaySafety(&cb3);
457 handler->txn_->removeWaitingForReplaySafety(&cb2);
458
459 ON_CALL(*sock, replaySafe()).WillByDefault(Return(true));
460 EXPECT_CALL(cb1, onReplaySafe_());
461 EXPECT_CALL(cb3, onReplaySafe_());
462 hqSession_->onReplaySafe();
463
464 handler->expectDetachTransaction();
465 handler->txn_->sendAbort();
466 hqSession_->closeWhenIdle();
467 eventBase_.loopOnce();
468 }
469
TEST_P(HQUpstreamSessionTest,AlreadyReplaySafe)470 TEST_P(HQUpstreamSessionTest, AlreadyReplaySafe) {
471 auto handler = openTransaction();
472
473 StrictMock<folly::test::MockReplaySafetyCallback> cb;
474
475 auto sock = socketDriver_->getSocket();
476 EXPECT_CALL(*sock, replaySafe()).WillRepeatedly(Return(true));
477 EXPECT_CALL(cb, onReplaySafe_());
478 handler->txn_->addWaitingForReplaySafety(&cb);
479
480 handler->expectDetachTransaction();
481 handler->txn_->sendAbort();
482 hqSession_->closeWhenIdle();
483 eventBase_.loopOnce();
484 }
485
TEST_P(HQUpstreamSessionTest,Test100Continue)486 TEST_P(HQUpstreamSessionTest, Test100Continue) {
487 InSequence enforceOrder;
488 auto handler = openTransaction();
489 auto req = getPostRequest(10);
490 req.getHeaders().add(HTTP_HEADER_EXPECT, "100-continue");
491 handler->txn_->sendHeaders(req);
492 handler->txn_->sendEOM();
493 handler->expectHeaders();
494 handler->expectHeaders();
495 handler->expectBody();
496 handler->expectEOM();
497 handler->expectDetachTransaction();
498 sendResponse(handler->txn_->getID(), *makeResponse(100), nullptr, false);
499 auto resp = makeResponse(200, 100);
500 sendResponse(handler->txn_->getID(),
501 *std::get<0>(resp),
502 std::move(std::get<1>(resp)),
503 true);
504 flushAndLoop();
505 hqSession_->closeWhenIdle();
506 }
507
TEST_P(HQUpstreamSessionTest,TestSetIngressTimeoutAfterSendEom)508 TEST_P(HQUpstreamSessionTest, TestSetIngressTimeoutAfterSendEom) {
509 hqSession_->setIngressTimeoutAfterEom(true);
510
511 // Send EOM separately.
512 auto handler1 = openTransaction();
513 handler1->expectHeaders();
514 handler1->expectBody();
515 handler1->expectEOM();
516 handler1->expectDetachTransaction();
517
518 auto transaction1 = handler1->txn_;
519 EXPECT_TRUE(transaction1->hasIdleTimeout());
520 transaction1->setIdleTimeout(std::chrono::milliseconds(100));
521 EXPECT_FALSE(transaction1->isScheduled());
522
523 transaction1->sendHeaders(getPostRequest(10));
524 eventBase_.loopOnce();
525 EXPECT_FALSE(transaction1->isScheduled());
526
527 transaction1->sendBody(makeBuf(100) /* body */);
528 eventBase_.loopOnce();
529 EXPECT_FALSE(transaction1->isScheduled());
530
531 transaction1->sendEOM();
532 eventBase_.loopOnce();
533 EXPECT_TRUE(transaction1->isScheduled());
534
535 auto response1 = makeResponse(200, 100);
536 sendResponse(transaction1->getID(),
537 *std::get<0>(response1),
538 std::move(std::get<1>(response1)),
539 true);
540 flushAndLoop();
541
542 // Send EOM with header.
543 auto handler2 = openTransaction();
544 handler2->expectHeaders();
545 handler2->expectBody();
546 handler2->expectEOM();
547 handler2->expectDetachTransaction();
548
549 auto transaction2 = handler2->txn_;
550 EXPECT_FALSE(transaction2->isScheduled());
551 transaction2->sendHeadersWithOptionalEOM(getPostRequest(), true /* eom */);
552 eventBase_.loopOnce();
553 EXPECT_TRUE(transaction2->isScheduled());
554
555 auto response2 = makeResponse(200, 100);
556 sendResponse(transaction2->getID(),
557 *std::get<0>(response2),
558 std::move(std::get<1>(response2)),
559 true);
560 flushAndLoop();
561
562 // Send EOM with body.
563 auto handler3 = openTransaction();
564 handler3->expectHeaders();
565 handler3->expectBody();
566 handler3->expectEOM();
567 handler3->expectDetachTransaction();
568
569 auto transaction3 = handler3->txn_;
570 EXPECT_FALSE(transaction3->isScheduled());
571 transaction3->sendHeaders(getPostRequest());
572 eventBase_.loopOnce();
573 EXPECT_FALSE(transaction3->isScheduled());
574 transaction3->sendBody(makeBuf(100) /* body */);
575 transaction3->sendEOM();
576 eventBase_.loopOnce();
577 EXPECT_TRUE(transaction3->isScheduled());
578
579 auto response3 = makeResponse(200, 100);
580 sendResponse(transaction3->getID(),
581 *std::get<0>(response3),
582 std::move(std::get<1>(response3)),
583 true);
584 flushAndLoop();
585 hqSession_->closeWhenIdle();
586 }
587
TEST_P(HQUpstreamSessionTest,GetAddresses)588 TEST_P(HQUpstreamSessionTest, GetAddresses) {
589 EXPECT_EQ(socketDriver_->localAddress_, hqSession_->getLocalAddress());
590 EXPECT_EQ(socketDriver_->peerAddress_, hqSession_->getPeerAddress());
591 hqSession_->dropConnection();
592 }
593
TEST_P(HQUpstreamSessionTest,GetAddressesFromBase)594 TEST_P(HQUpstreamSessionTest, GetAddressesFromBase) {
595 HTTPSessionBase* sessionBase = dynamic_cast<HTTPSessionBase*>(hqSession_);
596 EXPECT_EQ(socketDriver_->localAddress_, sessionBase->getLocalAddress());
597 EXPECT_EQ(socketDriver_->peerAddress_, sessionBase->getPeerAddress());
598 hqSession_->dropConnection();
599 }
600
TEST_P(HQUpstreamSessionTest,GetAddressesAfterDropConnection)601 TEST_P(HQUpstreamSessionTest, GetAddressesAfterDropConnection) {
602 HQSession::DestructorGuard dg(hqSession_);
603 hqSession_->dropConnection();
604 EXPECT_EQ(socketDriver_->localAddress_, hqSession_->getLocalAddress());
605 EXPECT_EQ(socketDriver_->peerAddress_, hqSession_->getPeerAddress());
606 }
607
TEST_P(HQUpstreamSessionTest,DropConnectionTwice)608 TEST_P(HQUpstreamSessionTest, DropConnectionTwice) {
609 HQSession::DestructorGuard dg(hqSession_);
610 hqSession_->closeWhenIdle();
611 hqSession_->dropConnection();
612 }
613
TEST_P(HQUpstreamSessionTest,DropConnectionTwiceWithPendingStreams)614 TEST_P(HQUpstreamSessionTest, DropConnectionTwiceWithPendingStreams) {
615 folly::IOBufQueue writeBuf{folly::IOBufQueue::cacheChainLength()};
616 socketDriver_->addReadEvent(15, writeBuf.move());
617 flushAndLoopN(1);
618 HQSession::DestructorGuard dg(hqSession_);
619 hqSession_->dropConnection();
620 eventBase_.loopOnce();
621 hqSession_->closeWhenIdle();
622 }
623
TEST_P(HQUpstreamSessionTest,DropConnectionAfterCloseWhenIdle)624 TEST_P(HQUpstreamSessionTest, DropConnectionAfterCloseWhenIdle) {
625 HQSession::DestructorGuard dg(hqSession_);
626 hqSession_->closeWhenIdle();
627 flushAndLoopN(1);
628 hqSession_->dropConnection();
629 }
630
TEST_P(HQUpstreamSessionTest,DropConnectionWithStreamAfterCloseWhenIdle)631 TEST_P(HQUpstreamSessionTest, DropConnectionWithStreamAfterCloseWhenIdle) {
632 HQSession::DestructorGuard dg(hqSession_);
633 auto handler = openTransaction();
634 handler->txn_->sendHeaders(getGetRequest());
635 hqSession_->closeWhenIdle();
636 flushAndLoopN(1);
637 handler->expectError([&](const HTTPException& err) {
638 EXPECT_TRUE(err.hasProxygenError());
639 EXPECT_EQ(err.getHttp3ErrorCode(), HTTP3::ErrorCode::HTTP_NO_ERROR);
640 });
641 handler->expectDetachTransaction();
642 hqSession_->dropConnection();
643 }
644
TEST_P(HQUpstreamSessionTest,NotifyConnectCallbackBeforeDestruct)645 TEST_P(HQUpstreamSessionTest, NotifyConnectCallbackBeforeDestruct) {
646 MockConnectCallback connectCb;
647 dynamic_cast<HQUpstreamSession*>(hqSession_)->setConnectCallback(&connectCb);
648 EXPECT_CALL(connectCb, connectError(_)).Times(1);
649 socketDriver_->deliverConnectionError(
650 {quic::LocalErrorCode::CONNECT_FAILED, "Peer closed"});
651 }
652
TEST_P(HQUpstreamSessionTest,DropFromConnectError)653 TEST_P(HQUpstreamSessionTest, DropFromConnectError) {
654 MockConnectCallback connectCb;
655 HQUpstreamSession* upstreamSess =
656 dynamic_cast<HQUpstreamSession*>(hqSession_);
657 upstreamSess->setConnectCallback(&connectCb);
658 EXPECT_CALL(connectCb, connectError(_)).WillOnce(InvokeWithoutArgs([&] {
659 hqSession_->dropConnection();
660 }));
661 socketDriver_->addOnConnectionEndEvent(0);
662 eventBase_.loop();
663 }
664
TEST_P(HQUpstreamSessionTest,FirstPeerPacketProcessed)665 TEST_P(HQUpstreamSessionTest, FirstPeerPacketProcessed) {
666 MockConnectCallback connectCb;
667 HQUpstreamSession* upstreamSess =
668 dynamic_cast<HQUpstreamSession*>(hqSession_);
669 upstreamSess->setConnectCallback(&connectCb);
670 EXPECT_CALL(connectCb, onFirstPeerPacketProcessed());
671 upstreamSess->onFirstPeerPacketProcessed();
672
673 upstreamSess->closeWhenIdle();
674 eventBase_.loopOnce();
675 }
676
TEST_P(HQUpstreamSessionTest,NotifyReplaySafeAfterTransportReady)677 TEST_P(HQUpstreamSessionTest, NotifyReplaySafeAfterTransportReady) {
678 MockConnectCallback connectCb;
679 HQUpstreamSession* upstreamSess =
680 dynamic_cast<HQUpstreamSession*>(hqSession_);
681 upstreamSess->setConnectCallback(&connectCb);
682
683 // onTransportReady gets called in SetUp() already
684
685 EXPECT_CALL(connectCb, onReplaySafe());
686 upstreamSess->onReplaySafe();
687
688 upstreamSess->closeWhenIdle();
689 eventBase_.loopOnce();
690 }
691
TEST_P(HQUpstreamSessionTest,TestConnectionToken)692 TEST_P(HQUpstreamSessionTest, TestConnectionToken) {
693 HQSession::DestructorGuard dg(hqSession_);
694 auto handler = openTransaction();
695 handler->expectError();
696 handler->expectDetachTransaction();
697
698 // The transaction should not have a connection token
699 // by default.
700 EXPECT_EQ(handler->txn_->getConnectionToken(), folly::none);
701
702 // Passing connection token to a session should
703 // make it visible to the transaction.
704 HTTPTransaction::ConnectionToken connToken{"TOKEN1234"};
705 hqSession_->setConnectionToken(connToken);
706
707 EXPECT_NE(handler->txn_->getConnectionToken(), folly::none);
708 EXPECT_EQ(*handler->txn_->getConnectionToken(), connToken);
709
710 // Clean up the session and the transaction.
711 hqSession_->onConnectionError(
712 std::make_pair(quic::LocalErrorCode::CONNECT_FAILED,
713 "Connect Failure with Open streams"));
714 eventBase_.loop();
715 EXPECT_EQ(hqSession_->getConnectionCloseReason(),
716 ConnectionCloseReason::SHUTDOWN);
717 }
718
TEST_P(HQUpstreamSessionTest,OnConnectionErrorWithOpenStreams)719 TEST_P(HQUpstreamSessionTest, OnConnectionErrorWithOpenStreams) {
720 HQSession::DestructorGuard dg(hqSession_);
721 auto handler = openTransaction();
722 handler->expectError();
723 handler->expectDetachTransaction();
724 hqSession_->onConnectionError(
725 std::make_pair(quic::LocalErrorCode::CONNECT_FAILED,
726 "Connect Failure with Open streams"));
727 eventBase_.loop();
728 EXPECT_EQ(hqSession_->getConnectionCloseReason(),
729 ConnectionCloseReason::SHUTDOWN);
730 }
731
TEST_P(HQUpstreamSessionTest,OnConnectionErrorWithOpenStreamsPause)732 TEST_P(HQUpstreamSessionTest, OnConnectionErrorWithOpenStreamsPause) {
733 HQSession::DestructorGuard dg(hqSession_);
734 auto handler1 = openTransaction();
735 auto handler2 = openTransaction();
736 handler1->txn_->sendHeaders(getGetRequest());
737 handler1->txn_->sendEOM();
738 handler2->txn_->sendHeaders(getGetRequest());
739 handler2->txn_->sendEOM();
740 auto resp = makeResponse(200, 100);
741 sendResponse(handler1->txn_->getID(),
742 *std::get<0>(resp),
743 std::move(std::get<1>(resp)),
744 true);
745 resp = makeResponse(200, 100);
746 sendResponse(handler2->txn_->getID(),
747 *std::get<0>(resp),
748 std::move(std::get<1>(resp)),
749 true);
750 flush();
751 eventBase_.runInLoop([&] {
752 hqSession_->onConnectionError(
753 std::make_pair(quic::LocalErrorCode::CONNECT_FAILED,
754 "Connect Failure with Open streams"));
755 });
756 handler1->expectError(
757 [&](const HTTPException&) { handler2->txn_->pauseIngress(); });
758 handler1->expectDetachTransaction();
759 handler2->expectError();
760 handler2->expectDetachTransaction();
761 eventBase_.loop();
762 EXPECT_EQ(hqSession_->getConnectionCloseReason(),
763 ConnectionCloseReason::SHUTDOWN);
764 }
765
TEST_P(HQUpstreamSessionTest,RejectDelegateSending)766 TEST_P(HQUpstreamSessionTest, RejectDelegateSending) {
767 auto handler = openTransaction();
768 auto dsrRequestSender = std::make_unique<MockDSRRequestSender>();
769 EXPECT_FALSE(handler->txn_->sendHeadersWithDelegate(
770 getGetRequest(), std::move(dsrRequestSender)));
771 handler->expectDetachTransaction();
772 handler->terminate();
773 eventBase_.loop();
774 hqSession_->closeWhenIdle();
775 }
776
TEST_P(HQUpstreamSessionTestH1qv2HQ,GoawayStreamsUnacknowledged)777 TEST_P(HQUpstreamSessionTestH1qv2HQ, GoawayStreamsUnacknowledged) {
778 std::vector<std::unique_ptr<StrictMock<MockHTTPHandler>>> handlers;
779 auto numStreams = 4;
780 quic::StreamId goawayId = (numStreams * 4) / 2 + 4;
781 for (auto n = 1; n <= numStreams; n++) {
782 handlers.emplace_back(openTransaction());
783 auto handler = handlers.back().get();
784 handler->txn_->sendHeaders(getGetRequest());
785 handler->txn_->sendEOM();
786 EXPECT_CALL(*handler, onGoaway(testing::_)).Times(2);
787 if (handler->txn_->getID() >= goawayId) {
788 handler->expectError([hdlr = handler](const HTTPException& err) {
789 EXPECT_TRUE(err.hasProxygenError());
790 EXPECT_EQ(err.getProxygenError(), kErrorStreamUnacknowledged);
791 ASSERT_EQ(
792 folly::to<std::string>("StreamUnacknowledged on transaction id: ",
793 hdlr->txn_->getID()),
794 std::string(err.what()));
795 });
796 } else {
797 handler->expectHeaders();
798 handler->expectBody();
799 handler->expectEOM();
800 }
801
802 if (n < numStreams) {
803 handler->expectDetachTransaction();
804 } else {
805 handler->expectDetachTransaction([&] {
806 // Make sure the session can't create any more transactions.
807 MockHTTPHandler handler2;
808 EXPECT_EQ(hqSession_->newTransaction(&handler2), nullptr);
809 // Send the responses for the acknowledged streams
810 for (auto& hdlr : handlers) {
811 auto id = hdlr->txn_->getID();
812 if (id < goawayId) {
813 auto resp = makeResponse(200, 100);
814 sendResponse(
815 id, *std::get<0>(resp), std::move(std::get<1>(resp)), true);
816 }
817 }
818 flush();
819 });
820 }
821 }
822
823 sendGoaway(HTTPCodec::MaxStreamID, milliseconds(50));
824 sendGoaway(goawayId, milliseconds(100));
825 flushAndLoop();
826 }
827
TEST_P(HQUpstreamSessionTestHQ,GoawayIncreased)828 TEST_P(HQUpstreamSessionTestHQ, GoawayIncreased) {
829 folly::IOBufQueue writeBuf{folly::IOBufQueue::cacheChainLength()};
830 egressControlCodec_->generateGoaway(writeBuf, 12, ErrorCode::NO_ERROR);
831 socketDriver_->addReadEvent(connControlStreamId_, writeBuf.move());
832 flushAndLoopN(1);
833 proxygen::hq::HQControlCodec egressControlCodec2(
834 nextUnidirectionalStreamId_,
835 proxygen::TransportDirection::DOWNSTREAM,
836 proxygen::hq::StreamDirection::EGRESS,
837 egressSettings_);
838 egressControlCodec2.generateGoaway(writeBuf, 16, ErrorCode::NO_ERROR);
839 socketDriver_->addReadEvent(connControlStreamId_, writeBuf.move());
840 flushAndLoop();
841 EXPECT_EQ(*socketDriver_->streams_[kConnectionStreamId].error,
842 HTTP3::ErrorCode::HTTP_ID_ERROR);
843 }
844
TEST_P(HQUpstreamSessionTestHQ,DelayedQPACK)845 TEST_P(HQUpstreamSessionTestHQ, DelayedQPACK) {
846 InSequence enforceOrder;
847 auto handler = openTransaction();
848 handler->txn_->sendHeaders(getGetRequest());
849 handler->txn_->sendEOM();
850 handler->expectHeaders();
851 handler->expectHeaders();
852 handler->expectBody();
853 handler->expectEOM();
854 handler->expectDetachTransaction();
855 auto cont = makeResponse(100);
856 auto resp = makeResponse(200, 100);
857 cont->getHeaders().add("X-FB-Debug", "jvrbfihvuvvclgvfkbkikjlcbruleekj");
858 std::get<0>(resp)->getHeaders().add("X-FB-Debug",
859 "egedljtrbullljdjjvtjkekebffefclj");
860 sendResponse(handler->txn_->getID(), *cont, nullptr, false);
861 sendResponse(handler->txn_->getID(),
862 *std::get<0>(resp),
863 std::move(std::get<1>(resp)),
864 true);
865 auto control = encoderWriteBuf_.move();
866 flushAndLoopN(1);
867 encoderWriteBuf_.append(std::move(control));
868 flushAndLoop();
869 hqSession_->closeWhenIdle();
870 }
871
TEST_P(HQUpstreamSessionTestHQ,DelayedQPACKTimeout)872 TEST_P(HQUpstreamSessionTestHQ, DelayedQPACKTimeout) {
873 InSequence enforceOrder;
874 auto handler = openTransaction();
875 handler->txn_->sendHeaders(getGetRequest());
876 handler->txn_->sendEOM();
877 handler->expectError();
878 auto resp = makeResponse(200, 100);
879 std::get<0>(resp)->getHeaders().add("X-FB-Debug",
880 "egedljtrbullljdjjvtjkekebffefclj");
881 sendResponse(handler->txn_->getID(),
882 *std::get<0>(resp),
883 std::move(std::get<1>(resp)),
884 true);
885 auto control = encoderWriteBuf_.move();
886 handler->expectDetachTransaction([this, &control]() mutable {
887 // have the header block arrive after destruction
888 encoderWriteBuf_.append(std::move(control));
889 eventBase_.runInLoop([this] { flush(); });
890 eventBase_.runAfterDelay([this] { hqSession_->closeWhenIdle(); }, 100);
891 });
892 flushAndLoop();
893 }
894
TEST_P(HQUpstreamSessionTestHQ,QPACKDecoderStreamFlushed)895 TEST_P(HQUpstreamSessionTestHQ, QPACKDecoderStreamFlushed) {
896 InSequence enforceOrder;
897 auto handler = openTransaction();
898 handler->txn_->sendHeadersWithOptionalEOM(getGetRequest(), true);
899 flushAndLoopN(1);
900 handler->expectDetachTransaction();
901 handler->txn_->sendAbort();
902 flushAndLoop();
903 auto& decoderStream = socketDriver_->streams_[kQPACKDecoderEgressStreamId];
904 // type byte plus cancel
905 EXPECT_EQ(decoderStream.writeBuf.chainLength(), 2);
906
907 handler = openTransaction();
908 handler->txn_->sendHeadersWithOptionalEOM(getGetRequest(), true);
909 handler->expectHeaders();
910 handler->expectBody();
911 handler->expectEOM();
912 auto resp = makeResponse(200, 100);
913 std::get<0>(resp)->getHeaders().add("Response", "Dynamic");
914 sendResponse(handler->txn_->getID(),
915 *std::get<0>(resp),
916 std::move(std::get<1>(resp)),
917 true);
918 auto qpackData = encoderWriteBuf_.move();
919 flushAndLoopN(1);
920 encoderWriteBuf_.append(std::move(qpackData));
921 handler->expectDetachTransaction();
922 hqSession_->closeWhenIdle();
923 flushAndLoop();
924 // type byte plus cancel plus ack
925 EXPECT_EQ(decoderStream.writeBuf.chainLength(), 3);
926 }
927
TEST_P(HQUpstreamSessionTestHQ,DelayedQPACKAfterReset)928 TEST_P(HQUpstreamSessionTestHQ, DelayedQPACKAfterReset) {
929 // Stand on your head and spit wooden nickels
930 // Ensure the session does not deliver input data to a transaction detached
931 // earlier the same loop
932 InSequence enforceOrder;
933 // Send two requests
934 auto handler1 = openTransaction();
935 auto handler2 = openTransaction();
936 handler1->txn_->sendHeadersWithOptionalEOM(getGetRequest(), true);
937 handler2->txn_->sendHeadersWithOptionalEOM(getGetRequest(), true);
938 // Send a response to txn1 that will block on QPACK data
939 auto resp1 = makeResponse(302, 0);
940 std::get<0>(resp1)->getHeaders().add("Response1", "Dynamic");
941 sendResponse(handler1->txn_->getID(),
942 *std::get<0>(resp1),
943 std::move(std::get<1>(resp1)),
944 true);
945 // Save first QPACK data
946 auto qpackData1 = encoderWriteBuf_.move();
947 // Send response to txn2 that will block on *different* QPACK data
948 auto resp2 = makeResponse(302, 0);
949 std::get<0>(resp2)->getHeaders().add("Respnse2", "Dynamic");
950 sendResponse(handler2->txn_->getID(),
951 *std::get<0>(resp2),
952 std::move(std::get<1>(resp2)),
953 false);
954 // Save second QPACK data
955 auto qpackData2 = encoderWriteBuf_.move();
956
957 // Abort *both* txns when txn1 gets headers. This will leave txn2 detached
958 // with pending input data in this loop.
959 handler1->expectHeaders([&] {
960 handler1->txn_->sendAbort();
961 handler2->txn_->sendAbort();
962 });
963
964 auto streamIt1 = streams_.find(handler1->txn_->getID());
965 CHECK(streamIt1 != streams_.end());
966 auto streamIt2 = streams_.find(handler2->txn_->getID());
967 CHECK(streamIt2 != streams_.end());
968 // add all the events in the same callback, with the stream data coming
969 // before the QPACK data
970 std::vector<MockQuicSocketDriver::ReadEvent> events;
971 events.emplace_back(handler2->txn_->getID(),
972 streamIt2->second.buf.move(),
973 streamIt2->second.readEOF,
974 folly::none,
975 false);
976 events.emplace_back(handler1->txn_->getID(),
977 streamIt1->second.buf.move(),
978 streamIt1->second.readEOF,
979 folly::none,
980 false);
981 events.emplace_back(kQPACKEncoderIngressStreamId,
982 std::move(qpackData1),
983 false,
984 folly::none,
985 false);
986 socketDriver_->addReadEvents(std::move(events));
987 handler2->expectDetachTransaction();
988 handler1->expectDetachTransaction();
989 eventBase_.loopOnce();
990 // Add the QPACK data that would unblock txn2. It's long gone and this
991 // should be a no-op.
992 socketDriver_->addReadEvent(kQPACKEncoderIngressStreamId,
993 std::move(qpackData2));
994 eventBase_.loopOnce();
995 hqSession_->closeWhenIdle();
996 }
997
TEST_P(HQUpstreamSessionTestQPACK,QPACKQueuedOnClose)998 TEST_P(HQUpstreamSessionTestQPACK, QPACKQueuedOnClose) {
999 InSequence enforceOrder;
1000 auto handler = openTransaction();
1001 handler->txn_->sendHeaders(getGetRequest());
1002 handler->txn_->sendEOM();
1003 handler->expectError();
1004 handler->expectDetachTransaction();
1005 auto resp = makeResponse(200, 100);
1006 std::get<0>(resp)->getHeaders().add("X-FB-Debug",
1007 "egedljtrbullljdjjvtjkekebffefclj");
1008 sendResponse(handler->txn_->getID(),
1009 *std::get<0>(resp),
1010 std::move(std::get<1>(resp)),
1011 true);
1012 auto control = encoderWriteBuf_.move();
1013 // Entire response is delivered from the transport to the session
1014 flushAndLoopN(1);
1015 // Connection end but the stream is still pending
1016 socketDriver_->addOnConnectionEndEvent(0);
1017 eventBase_.loop();
1018 }
1019
TEST_P(HQUpstreamSessionTestHQ,TestDropConnectionSynchronously)1020 TEST_P(HQUpstreamSessionTestHQ, TestDropConnectionSynchronously) {
1021 std::unique_ptr<testing::NiceMock<proxygen::MockHTTPSessionInfoCallback>>
1022 infoCb = std::make_unique<
1023 testing::NiceMock<proxygen::MockHTTPSessionInfoCallback>>();
1024 auto handler = openTransaction();
1025 handler->txn_->sendHeaders(getGetRequest());
1026 handler->expectError();
1027 handler->expectDetachTransaction();
1028 hqSession_->setInfoCallback(infoCb.get());
1029 // the session is destroyed synchronously, so the destroy callback gets
1030 // invoked
1031 EXPECT_CALL(*infoCb.get(), onDestroy(_)).Times(1);
1032 hqSession_->dropConnection();
1033 infoCb.reset();
1034 eventBase_.loopOnce();
1035 }
1036
TEST_P(HQUpstreamSessionTestHQ,TestOnStopSendingHTTPRequestRejected)1037 TEST_P(HQUpstreamSessionTestHQ, TestOnStopSendingHTTPRequestRejected) {
1038 auto handler = openTransaction();
1039 auto streamId = handler->txn_->getID();
1040 handler->txn_->sendHeaders(getGetRequest());
1041 eventBase_.loopOnce();
1042 EXPECT_CALL(*socketDriver_->getSocket(),
1043 resetStream(streamId, HTTP3::ErrorCode::HTTP_REQUEST_CANCELLED))
1044 .Times(2) // once from on stopSending and once from sendAbort
1045 .WillRepeatedly(
1046 Invoke([&](quic::StreamId id, quic::ApplicationErrorCode) {
1047 // setWriteError will cancaleDeliveryCallbacks which will invoke
1048 // onCanceled to decrementPendingByteEvents on the txn.
1049 socketDriver_->setWriteError(id);
1050 return folly::unit;
1051 }));
1052 EXPECT_CALL(*handler, onError(_))
1053 .Times(1)
1054 .WillOnce(Invoke([](HTTPException ex) {
1055 EXPECT_EQ(kErrorStreamUnacknowledged, ex.getProxygenError());
1056 }));
1057 handler->expectDetachTransaction();
1058 hqSession_->onStopSending(streamId, HTTP3::ErrorCode::HTTP_REQUEST_REJECTED);
1059 hqSession_->closeWhenIdle();
1060 }
1061
TEST_P(HQUpstreamSessionTestHQ,TestGreaseFramePerSession)1062 TEST_P(HQUpstreamSessionTestHQ, TestGreaseFramePerSession) {
1063 // a grease frame is created when creating the first transaction
1064 auto handler1 = openTransaction();
1065 auto streamId1 = handler1->txn_->getID();
1066 handler1->txn_->sendHeaders(getGetRequest());
1067 handler1->txn_->sendEOM();
1068 handler1->expectHeaders();
1069 handler1->expectBody();
1070 handler1->expectEOM();
1071 handler1->expectDetachTransaction();
1072 auto resp1 = makeResponse(200, 100);
1073 sendResponse(handler1->txn_->getID(),
1074 *std::get<0>(resp1),
1075 std::move(std::get<1>(resp1)),
1076 true);
1077 flushAndLoop();
1078 FakeHTTPCodecCallback callback1;
1079 std::unique_ptr<HQStreamCodec> downstreamCodec =
1080 std::make_unique<hq::HQStreamCodec>(
1081 streamId1,
1082 TransportDirection::DOWNSTREAM,
1083 qpackCodec_,
1084 encoderWriteBuf_,
1085 decoderWriteBuf_,
1086 [] { return std::numeric_limits<uint64_t>::max(); },
1087 ingressSettings_);
1088 downstreamCodec->setCallback(&callback1);
1089 downstreamCodec->onIngress(
1090 *socketDriver_->streams_[streamId1].writeBuf.front());
1091 EXPECT_EQ(callback1.unknownFrames, 1);
1092 EXPECT_EQ(callback1.greaseFrames, 1);
1093
1094 // no grease frame is created when creating the second transaction
1095 auto handler2 = openTransaction();
1096 auto streamId2 = handler2->txn_->getID();
1097 handler2->txn_->sendHeaders(getGetRequest());
1098 handler2->txn_->sendEOM();
1099 handler2->expectHeaders();
1100 handler2->expectBody();
1101 handler2->expectEOM();
1102 handler2->expectDetachTransaction();
1103 auto resp2 = makeResponse(200, 100);
1104 sendResponse(handler2->txn_->getID(),
1105 *std::get<0>(resp2),
1106 std::move(std::get<1>(resp2)),
1107 true);
1108 flushAndLoop();
1109 FakeHTTPCodecCallback callback2;
1110 downstreamCodec->setCallback(&callback2);
1111 downstreamCodec->onIngress(
1112 *socketDriver_->streams_[streamId2].writeBuf.front());
1113 EXPECT_EQ(callback2.unknownFrames, 0);
1114 EXPECT_EQ(callback2.greaseFrames, 0);
1115 hqSession_->closeWhenIdle();
1116 }
1117
1118 // This test is checking two different scenarios for different protocol
1119 // - in HQ we already have sent SETTINGS in SetUp, so tests that multiple
1120 // setting frames are not allowed
1121 // - in h1q-fb-v2 tests that receiving even a single SETTINGS frame errors
1122 // out the connection
TEST_P(HQUpstreamSessionTestH1qv2HQ,ExtraSettings)1123 TEST_P(HQUpstreamSessionTestH1qv2HQ, ExtraSettings) {
1124 auto handler = openTransaction();
1125 handler->txn_->sendHeaders(getGetRequest());
1126 handler->txn_->sendEOM();
1127 handler->expectError();
1128 handler->expectDetachTransaction();
1129
1130 // Need to use a new codec. Since generating settings twice is
1131 // forbidden
1132 HQControlCodec auxControlCodec_{nextUnidirectionalStreamId_,
1133 TransportDirection::DOWNSTREAM,
1134 StreamDirection::EGRESS,
1135 egressSettings_,
1136 UnidirectionalStreamType::H1Q_CONTROL};
1137 folly::IOBufQueue writeBuf{folly::IOBufQueue::cacheChainLength()};
1138 auxControlCodec_.generateSettings(writeBuf);
1139 socketDriver_->addReadEvent(
1140 connControlStreamId_, writeBuf.move(), milliseconds(0));
1141
1142 flushAndLoop();
1143
1144 EXPECT_EQ(*socketDriver_->streams_[kConnectionStreamId].error,
1145 HTTP3::ErrorCode::HTTP_FRAME_UNEXPECTED);
1146 }
1147
1148 // Test Cases for which Settings are not sent in the test SetUp
1149 using HQUpstreamSessionTestHQNoSettings = HQUpstreamSessionTest;
1150
1151 INSTANTIATE_TEST_CASE_P(HQUpstreamSessionTest,
1152 HQUpstreamSessionTestHQNoSettings,
__anon346abe7d1302null1153 Values([] {
1154 TestParams tp;
1155 tp.alpn_ = "h3";
1156 tp.shouldSendSettings_ = false;
1157 return tp;
1158 }()),
1159 paramsToTestName);
TEST_P(HQUpstreamSessionTestHQNoSettings,SimpleGet)1160 TEST_P(HQUpstreamSessionTestHQNoSettings, SimpleGet) {
1161 EXPECT_CALL(connectCb_, connectError(_)).Times(1);
1162 socketDriver_->deliverConnectionError(
1163 {quic::LocalErrorCode::CONNECT_FAILED, "Peer closed"});
1164 }
1165
TEST_P(HQUpstreamSessionTestHQNoSettings,GoawayBeforeSettings)1166 TEST_P(HQUpstreamSessionTestHQNoSettings, GoawayBeforeSettings) {
1167 auto handler = openTransaction();
1168 handler->txn_->sendHeaders(getGetRequest());
1169 handler->txn_->sendEOM();
1170 handler->expectError();
1171 handler->expectDetachTransaction();
1172
1173 sendGoaway(HTTPCodec::MaxStreamID);
1174 flushAndLoop();
1175
1176 EXPECT_EQ(*socketDriver_->streams_[kConnectionStreamId].error,
1177 HTTP3::ErrorCode::HTTP_MISSING_SETTINGS);
1178 }
1179
TEST_P(HQUpstreamSessionTestH1qv1,TestConnectionClose)1180 TEST_P(HQUpstreamSessionTestH1qv1, TestConnectionClose) {
1181 hqSession_->drain();
1182 auto handler = openTransaction();
1183 handler->txn_->sendHeaders(getGetRequest());
1184 handler->txn_->sendEOM();
1185 handler->expectHeaders();
1186 handler->expectBody();
1187 handler->expectEOM();
1188 handler->expectDetachTransaction();
1189 auto resp = makeResponse(200, 100);
1190 std::get<0>(resp)->getHeaders().set(HTTP_HEADER_CONNECTION, "close");
1191 sendResponse(handler->txn_->getID(),
1192 *std::get<0>(resp),
1193 std::move(std::get<1>(resp)),
1194 true);
1195 hqSession_->closeWhenIdle();
1196 flushAndLoop();
1197 }
1198
1199 /**
1200 * Push tests
1201 */
1202
1203 class HQUpstreamSessionTestHQPush : public HQUpstreamSessionTest {
1204 public:
SetUp()1205 void SetUp() override {
1206 HQUpstreamSessionTest::SetUp();
1207 SetUpAssocHandler();
1208 nextPushId_ = kInitialPushId;
1209 lastPushPromiseHeadersSize_.compressed = 0;
1210 lastPushPromiseHeadersSize_.uncompressed = 0;
1211 }
1212
SetUpAssocHandler()1213 void SetUpAssocHandler() {
1214 // Create the primary request
1215 assocHandler_ = openTransaction();
1216 assocHandler_->txn_->sendHeaders(getGetRequest());
1217 assocHandler_->expectDetachTransaction();
1218 }
1219
TearDown()1220 void TearDown() override {
1221 HQUpstreamSessionTest::TearDown();
1222 }
1223
SetUpServerPushLifecycleCallbacks()1224 void SetUpServerPushLifecycleCallbacks() {
1225 if (!SLCcallback_) {
1226 SLCcallback_ = std::make_unique<MockServerPushLifecycleCallback>();
1227 hqSession_->setServerPushLifecycleCallback(SLCcallback_.get());
1228 }
1229 }
1230
nextPushId()1231 hq::PushId nextPushId() {
1232 auto id = nextPushId_;
1233 nextPushId_ += kPushIdIncrement;
1234 return id;
1235 }
1236
1237 // NOTE: Using odd numbers for push ids, to allow detecting
1238 // subtle bugs where streamID and pushID are quietly misplaced
isPushIdValid(hq::PushId pushId)1239 bool isPushIdValid(hq::PushId pushId) {
1240 return (pushId % 2) == 1;
1241 }
1242
1243 using WriteFunctor = std::function<folly::Optional<size_t>(IOBufQueue&)>;
writeUpTo(quic::StreamId id,size_t maxlen,WriteFunctor functor)1244 folly::Optional<size_t> writeUpTo(quic::StreamId id,
1245 size_t maxlen,
1246 WriteFunctor functor) {
1247 // Lookup the stream
1248 auto findRes = streams_.find(id);
1249 if (findRes == streams_.end()) {
1250 return folly::none;
1251 }
1252
1253 IOBufQueue tmpbuf{IOBufQueue::cacheChainLength()};
1254 auto funcres = functor(tmpbuf);
1255 if (!funcres) {
1256 return folly::none;
1257 }
1258
1259 auto eventbuf = tmpbuf.splitAtMost(maxlen);
1260 auto wlen = eventbuf->length();
1261 CHECK_LE(wlen, maxlen) << "The written len must not exceed the max len";
1262 socketDriver_->addReadEvent(id, std::move(eventbuf), milliseconds(0));
1263 return wlen;
1264 }
1265
1266 // Use the common facilities to write the quic integer
writePushStreamPreface(quic::StreamId id,size_t maxlen)1267 folly::Optional<size_t> writePushStreamPreface(quic::StreamId id,
1268 size_t maxlen) {
1269 WriteFunctor f = [](IOBufQueue& outbuf) {
1270 return generateStreamPreface(outbuf, hq::UnidirectionalStreamType::PUSH);
1271 };
1272
1273 auto res = writeUpTo(id, maxlen, f);
1274 return res;
1275 }
1276
writeUnframedPushId(quic::StreamId id,size_t maxlen,hq::PushId pushId)1277 folly::Optional<size_t> writeUnframedPushId(quic::StreamId id,
1278 size_t maxlen,
1279 hq::PushId pushId) {
1280 WriteFunctor f = [=](IOBufQueue& outbuf) -> folly::Optional<size_t> {
1281 folly::io::QueueAppender appender(&outbuf, 8);
1282 uint8_t size = 1 << (folly::Random::rand32() % 4);
1283 auto wlen = encodeQuicIntegerWithAtLeast(pushId, size, appender);
1284 CHECK_GE(wlen, size);
1285 return wlen;
1286 };
1287
1288 auto res = writeUpTo(id, maxlen, f);
1289 return res;
1290 }
1291
expectPushPromiseBegin(std::function<void (HTTPCodec::StreamID,hq::PushId)> callback=std::function<void (HTTPCodec::StreamID,hq::PushId)> ())1292 void expectPushPromiseBegin(
1293 std::function<void(HTTPCodec::StreamID, hq::PushId)> callback =
1294 std::function<void(HTTPCodec::StreamID, hq::PushId)>()) {
1295 SetUpServerPushLifecycleCallbacks();
1296 SLCcallback_->expectPushPromiseBegin(callback);
1297 }
1298
expectPushPromise(std::function<void (HTTPCodec::StreamID,hq::PushId,HTTPMessage *)> callback=std::function<void (HTTPCodec::StreamID,hq::PushId,HTTPMessage *)> ())1299 void expectPushPromise(
1300 std::function<void(HTTPCodec::StreamID, hq::PushId, HTTPMessage*)>
1301 callback = std::function<
1302 void(HTTPCodec::StreamID, hq::PushId, HTTPMessage*)>()) {
1303 SetUpServerPushLifecycleCallbacks();
1304 SLCcallback_->expectPushPromise(callback);
1305 }
1306
expectNascentPushStreamBegin(std::function<void (HTTPCodec::StreamID,bool)> callback=std::function<void (HTTPCodec::StreamID,bool)> ())1307 void expectNascentPushStreamBegin(
1308 std::function<void(HTTPCodec::StreamID, bool)> callback =
1309 std::function<void(HTTPCodec::StreamID, bool)>()) {
1310 SetUpServerPushLifecycleCallbacks();
1311 SLCcallback_->expectNascentPushStreamBegin(callback);
1312 }
1313
expectNascentPushStream(std::function<void (HTTPCodec::StreamID,hq::PushId,bool)> callback=std::function<void (HTTPCodec::StreamID,hq::PushId,bool)> ())1314 void expectNascentPushStream(
1315 std::function<void(HTTPCodec::StreamID, hq::PushId, bool)> callback =
1316 std::function<void(HTTPCodec::StreamID, hq::PushId, bool)>()) {
1317 SetUpServerPushLifecycleCallbacks();
1318 SLCcallback_->expectNascentPushStream(callback);
1319 }
1320
expectNascentEof(std::function<void (HTTPCodec::StreamID,folly::Optional<hq::PushId>)> callback=std::function<void (HTTPCodec::StreamID,folly::Optional<hq::PushId>)> ())1321 void expectNascentEof(
1322 std::function<void(HTTPCodec::StreamID, folly::Optional<hq::PushId>)>
1323 callback = std::function<void(HTTPCodec::StreamID,
1324 folly::Optional<hq::PushId>)>()) {
1325 SetUpServerPushLifecycleCallbacks();
1326 SLCcallback_->expectNascentEof(callback);
1327 }
1328
expectOrphanedNascentStream(std::function<void (HTTPCodec::StreamID,folly::Optional<hq::PushId>)> callback=std::function<void (HTTPCodec::StreamID,folly::Optional<hq::PushId>)> ())1329 void expectOrphanedNascentStream(
1330 std::function<void(HTTPCodec::StreamID, folly::Optional<hq::PushId>)>
1331 callback = std::function<void(HTTPCodec::StreamID,
1332 folly::Optional<hq::PushId>)>()) {
1333
1334 SetUpServerPushLifecycleCallbacks();
1335 SLCcallback_->expectOrphanedNascentStream(callback);
1336 }
1337
expectHalfOpenPushedTxn(std::function<void (const HTTPTransaction *,hq::PushId,HTTPCodec::StreamID,bool)> callback=std::function<void (const HTTPTransaction *,hq::PushId,HTTPCodec::StreamID,bool)> ())1338 void expectHalfOpenPushedTxn(
1339 std::function<
1340 void(const HTTPTransaction*, hq::PushId, HTTPCodec::StreamID, bool)>
1341 callback = std::function<void(const HTTPTransaction*,
1342 hq::PushId,
1343 HTTPCodec::StreamID,
1344 bool)>()) {
1345 SetUpServerPushLifecycleCallbacks();
1346 SLCcallback_->expectHalfOpenPushedTxn(callback);
1347 }
1348
expectPushedTxn(std::function<void (const HTTPTransaction *,HTTPCodec::StreamID,hq::PushId,HTTPCodec::StreamID,bool)> callback=std::function<void (const HTTPTransaction *,HTTPCodec::StreamID,hq::PushId,HTTPCodec::StreamID,bool)> ())1349 void expectPushedTxn(std::function<void(const HTTPTransaction*,
1350 HTTPCodec::StreamID,
1351 hq::PushId,
1352 HTTPCodec::StreamID,
1353 bool)> callback =
1354 std::function<void(const HTTPTransaction*,
1355 HTTPCodec::StreamID,
1356 hq::PushId,
1357 HTTPCodec::StreamID,
1358 bool)>()) {
1359 SetUpServerPushLifecycleCallbacks();
1360 SLCcallback_->expectPushedTxn(callback);
1361 }
1362
expectPushedTxnTimeout(std::function<void (const HTTPTransaction *)> callback=std::function<void (const HTTPTransaction *)> ())1363 void expectPushedTxnTimeout(
1364 std::function<void(const HTTPTransaction*)> callback =
1365 std::function<void(const HTTPTransaction*)>()) {
1366 SetUpServerPushLifecycleCallbacks();
1367 SLCcallback_->expectPushedTxnTimeout(callback);
1368 }
1369
expectOrphanedHalfOpenPushedTxn(std::function<void (const HTTPTransaction *)> callback=std::function<void (const HTTPTransaction *)> ())1370 void expectOrphanedHalfOpenPushedTxn(
1371 std::function<void(const HTTPTransaction*)> callback =
1372 std::function<void(const HTTPTransaction*)>()) {
1373 SetUpServerPushLifecycleCallbacks();
1374 SLCcallback_->expectOrphanedHalfOpenPushedTxn(callback);
1375 }
1376
sendPushPromise(quic::StreamId streamId,hq::PushId pushId=kUnknownPushId,const std::string & url="/",proxygen::HTTPHeaderSize * outHeaderSize=nullptr,bool eom=false)1377 void sendPushPromise(quic::StreamId streamId,
1378 hq::PushId pushId = kUnknownPushId,
1379 const std::string& url = "/",
1380 proxygen::HTTPHeaderSize* outHeaderSize = nullptr,
1381 bool eom = false) {
1382 auto promise = getGetRequest(url);
1383 promise.setURL(url);
1384
1385 return sendPushPromise(streamId, promise, pushId, outHeaderSize, eom);
1386 }
1387
sendPushPromise(quic::StreamId streamId,const HTTPMessage & promiseHeadersBlock,hq::PushId pushId=kUnknownPushId,proxygen::HTTPHeaderSize * outHeaderSize=nullptr,bool eom=false)1388 void sendPushPromise(quic::StreamId streamId,
1389 const HTTPMessage& promiseHeadersBlock,
1390 hq::PushId pushId = kUnknownPushId,
1391 proxygen::HTTPHeaderSize* outHeaderSize = nullptr,
1392 bool eom = false) {
1393
1394 // In case the user is not interested in knowing the size
1395 // of headers, but just in the fact that the headers were
1396 // written, use a temporary size for checks
1397 if (outHeaderSize == nullptr) {
1398 outHeaderSize = &lastPushPromiseHeadersSize_;
1399 }
1400
1401 if (pushId == kUnknownPushId) {
1402 pushId = nextPushId();
1403 }
1404
1405 auto c = makeCodec(streamId);
1406 auto res =
1407 streams_.emplace(std::piecewise_construct,
1408 std::forward_as_tuple(streamId),
1409 std::forward_as_tuple(c.first, std::move(c.second)));
1410
1411 auto& pushPromiseRequest = res.first->second;
1412 pushPromiseRequest.id = streamId;
1413
1414 // Push promises should not have EOF set.
1415 pushPromiseRequest.readEOF = eom;
1416
1417 // Write the push promise to the request buffer.
1418 // The push promise includes the headers
1419 pushPromiseRequest.codec->generatePushPromise(pushPromiseRequest.buf,
1420 streamId,
1421 promiseHeadersBlock,
1422 pushId,
1423 eom,
1424 outHeaderSize);
1425 }
1426
1427 // Shared implementation for different push stream
1428 // methods
createPushStreamImpl(quic::StreamId streamId,folly::Optional<hq::PushId> pushId,std::size_t len=kUnlimited,bool eom=true)1429 ServerStream& createPushStreamImpl(quic::StreamId streamId,
1430 folly::Optional<hq::PushId> pushId,
1431 std::size_t len = kUnlimited,
1432 bool eom = true) {
1433
1434 auto c = makeCodec(streamId);
1435 // Setting a push id allows us to send push preface
1436 auto res = streams_.emplace(
1437 std::piecewise_construct,
1438 std::forward_as_tuple(streamId),
1439 std::forward_as_tuple(c.first, std::move(c.second), pushId));
1440
1441 auto& stream = res.first->second;
1442 stream.id = stream.codec->createStream();
1443 stream.readEOF = eom;
1444
1445 // Generate the push stream preface, and if there's enough headroom
1446 // the unframed push id that follows it
1447 auto prefaceRes = writePushStreamPreface(stream.id, len);
1448 if (pushId.has_value()) {
1449 if (prefaceRes) {
1450 len -= *prefaceRes;
1451 writeUnframedPushId(stream.id, len, *pushId);
1452 }
1453 }
1454
1455 return stream;
1456 }
1457
1458 // Create a push stream with a header block and body
createPushStream(quic::StreamId streamId,hq::PushId pushId,const HTTPMessage & resp,std::unique_ptr<folly::IOBuf> body=nullptr,bool eom=true)1459 void createPushStream(quic::StreamId streamId,
1460 hq::PushId pushId,
1461 const HTTPMessage& resp,
1462 std::unique_ptr<folly::IOBuf> body = nullptr,
1463 bool eom = true) {
1464
1465 auto& stream = createPushStreamImpl(streamId, pushId, kUnlimited, eom);
1466
1467 // Write the response
1468 stream.codec->generateHeader(
1469 stream.buf, stream.codecId, resp, body == nullptr ? eom : false);
1470 if (body) {
1471 stream.codec->generateBody(
1472 stream.buf, stream.codecId, std::move(body), folly::none, eom);
1473 }
1474 }
1475
1476 // Convenience method for creating a push stream without the
1477 // need to allocate transport stream id
createPushStream(hq::PushId pushId,const HTTPMessage & resp,std::unique_ptr<folly::IOBuf> body=nullptr,bool eom=true)1478 void createPushStream(hq::PushId pushId,
1479 const HTTPMessage& resp,
1480 std::unique_ptr<folly::IOBuf> body = nullptr,
1481 bool eom = true) {
1482 return createPushStream(
1483 nextUnidirectionalStreamId(), pushId, resp, std::move(body), eom);
1484 }
1485
1486 // Create nascent stream (no body)
createNascentPushStream(quic::StreamId streamId,folly::Optional<hq::PushId> pushId,std::size_t len=kUnlimited,bool eom=true)1487 void createNascentPushStream(quic::StreamId streamId,
1488 folly::Optional<hq::PushId> pushId,
1489 std::size_t len = kUnlimited,
1490 bool eom = true) {
1491 createPushStreamImpl(streamId, pushId, len, eom);
1492 }
1493
lastPushPromiseHeadersSizeValid()1494 bool lastPushPromiseHeadersSizeValid() {
1495 return ((lastPushPromiseHeadersSize_.uncompressed > 0) &&
1496 (lastPushPromiseHeadersSize_.compressed > 0));
1497 }
1498
createNascentPushStream(hq::PushId pushId,std::size_t prefaceBytes=kUnlimited,bool eom=true)1499 void createNascentPushStream(hq::PushId pushId,
1500 std::size_t prefaceBytes = kUnlimited,
1501 bool eom = true) {
1502 return createNascentPushStream(
1503 nextUnidirectionalStreamId(), pushId, prefaceBytes, eom);
1504 }
1505
expectPushResponse()1506 std::unique_ptr<MockHTTPHandler> expectPushResponse() {
1507 auto pushHandler = std::make_unique<MockHTTPHandler>();
1508 pushHandler->expectTransaction();
1509 assocHandler_->expectPushedTransaction(pushHandler.get());
1510 // Promise/Response - with no lambda it lacks RetiresOnSaturation
1511 pushHandler->expectHeaders([](std::shared_ptr<HTTPMessage>) {});
1512 pushHandler->expectHeaders([](std::shared_ptr<HTTPMessage>) {});
1513 pushHandler->expectBody();
1514 pushHandler->expectEOM();
1515 pushHandler->expectDetachTransaction();
1516 return pushHandler;
1517 }
1518
1519 proxygen::HTTPHeaderSize lastPushPromiseHeadersSize_;
1520 hq::PushId nextPushId_;
1521 std::unique_ptr<StrictMock<MockHTTPHandler>> assocHandler_;
1522
1523 std::unique_ptr<MockServerPushLifecycleCallback> SLCcallback_;
1524 };
1525
TEST_P(HQUpstreamSessionTestHQPush,DelayedQPACKPush)1526 TEST_P(HQUpstreamSessionTestHQPush, DelayedQPACKPush) {
1527 assocHandler_->txn_->sendAbort();
1528 assocHandler_ = openTransaction();
1529 assocHandler_->txn_->sendHeaders(getGetRequest());
1530 assocHandler_->txn_->sendEOM();
1531 assocHandler_->expectHeaders();
1532 assocHandler_->expectBody();
1533 auto pushHandler = expectPushResponse();
1534 assocHandler_->expectEOM();
1535 assocHandler_->expectDetachTransaction();
1536
1537 auto resp = makeResponse(200, 100);
1538 sendResponse(assocHandler_->txn_->getID(),
1539 *std::get<0>(resp),
1540 std::move(std::get<1>(resp)),
1541 false);
1542 flushAndLoopN(1);
1543 auto pushPromiseRequest = getGetRequest();
1544 pushPromiseRequest.getHeaders().set("Dynamic1", "a");
1545 hq::PushId pushId = nextPushId();
1546 sendPushPromise(assocHandler_->txn_->getID(), pushPromiseRequest, pushId);
1547 sendPartialBody(assocHandler_->txn_->getID(), nullptr, true);
1548
1549 auto control = encoderWriteBuf_.move();
1550 flushAndLoopN(1);
1551
1552 encoderWriteBuf_.append(std::move(control));
1553 flushAndLoopN(1);
1554
1555 HTTPMessage pushResp;
1556 pushResp.setStatusCode(200);
1557 pushResp.getHeaders().set("Dynamic2", "b");
1558 createPushStream(pushId, pushResp, makeBuf(100), true);
1559
1560 control = encoderWriteBuf_.move();
1561 flushAndLoopN(1);
1562
1563 encoderWriteBuf_.append(std::move(control));
1564 flushAndLoop();
1565 hqSession_->closeWhenIdle();
1566 }
1567
TEST_P(HQUpstreamSessionTestHQPush,TestPushPromiseCallbacksInvoked)1568 TEST_P(HQUpstreamSessionTestHQPush, TestPushPromiseCallbacksInvoked) {
1569 // the push promise is not followed by a push stream, and the eof is not
1570 // set.
1571 // The transaction is supposed to stay open and to time out eventually.
1572 assocHandler_->expectError([&](const HTTPException& ex) {
1573 ASSERT_EQ(ex.getProxygenError(), kErrorTimeout);
1574 });
1575
1576 hq::PushId pushId = nextPushId();
1577
1578 auto pushPromiseRequest = getGetRequest();
1579
1580 expectPushPromiseBegin(
1581 [&](HTTPCodec::StreamID owningStreamId, hq::PushId promisedPushId) {
1582 EXPECT_EQ(promisedPushId, pushId);
1583 EXPECT_EQ(owningStreamId, assocHandler_->txn_->getID());
1584 });
1585
1586 expectPushPromise([&](HTTPCodec::StreamID owningStreamId,
1587 hq::PushId promisedPushId,
1588 HTTPMessage* msg) {
1589 EXPECT_EQ(promisedPushId, pushId);
1590 EXPECT_EQ(owningStreamId, assocHandler_->txn_->getID());
1591
1592 EXPECT_THAT(msg, NotNull());
1593
1594 auto expectedHeaders = pushPromiseRequest.getHeaders();
1595 auto actualHeaders = msg->getHeaders();
1596
1597 expectedHeaders.forEach(
1598 [&](const std::string& header, const std::string& /* val */) {
1599 EXPECT_TRUE(actualHeaders.exists(header));
1600 EXPECT_EQ(expectedHeaders.getNumberOfValues(header),
1601 actualHeaders.getNumberOfValues(header));
1602 });
1603 });
1604
1605 HTTPCodec::StreamID nascentStreamId;
1606
1607 expectNascentPushStreamBegin([&](HTTPCodec::StreamID streamId, bool isEOF) {
1608 nascentStreamId = streamId;
1609 EXPECT_FALSE(isEOF);
1610 });
1611
1612 expectNascentPushStream([&](HTTPCodec::StreamID pushStreamId,
1613 hq::PushId pushStreamPushId,
1614 bool /* isEOF */) {
1615 EXPECT_EQ(pushStreamPushId, pushId);
1616 EXPECT_EQ(pushStreamId, nascentStreamId);
1617 });
1618
1619 sendPushPromise(assocHandler_->txn_->getID(), pushPromiseRequest, pushId);
1620 EXPECT_TRUE(lastPushPromiseHeadersSizeValid());
1621
1622 HTTPMessage resp;
1623 resp.setStatusCode(200);
1624 createPushStream(pushId, resp, makeBuf(100), true);
1625
1626 assocHandler_->txn_->sendEOM();
1627
1628 auto pushHandler = expectPushResponse();
1629
1630 hqSession_->closeWhenIdle();
1631 flushAndLoop();
1632 }
1633
TEST_P(HQUpstreamSessionTestHQPush,TestIngressPushStream)1634 TEST_P(HQUpstreamSessionTestHQPush, TestIngressPushStream) {
1635
1636 hq::PushId pushId = nextPushId();
1637
1638 auto pushPromiseRequest = getGetRequest();
1639
1640 HTTPCodec::StreamID nascentStreamId;
1641
1642 expectNascentPushStreamBegin([&](HTTPCodec::StreamID streamId, bool isEOF) {
1643 nascentStreamId = streamId;
1644 EXPECT_FALSE(isEOF);
1645 });
1646
1647 expectNascentPushStream([&](HTTPCodec::StreamID streamId,
1648 hq::PushId pushStreamPushId,
1649 bool isEOF) {
1650 EXPECT_EQ(streamId, nascentStreamId);
1651 EXPECT_EQ(pushId, pushStreamPushId);
1652 EXPECT_EQ(isEOF, false);
1653 });
1654
1655 // Since push promise is not sent, full ingress push stream
1656 // not going to be created
1657 /*
1658 expectOrphanedNascentStream([&](HTTPCodec::StreamID streamId,
1659 folly::Optional<hq::PushId> maybePushId) {
1660 ASSERT_EQ(streamId, nascentStreamId);
1661 EXPECT_EQ(maybePushId.has_value(), true);
1662 EXPECT_EQ(maybePushId.value(), pushId);
1663 });
1664 */
1665 HTTPMessage resp;
1666 resp.setStatusCode(200);
1667 createPushStream(pushId, resp, makeBuf(100), true);
1668
1669 // Currently, the new transaction is not created corectly,
1670 // and an error is expected. to be extended in the following
1671 // diffs which add creation of pushed transaction
1672 assocHandler_->expectError();
1673
1674 assocHandler_->txn_->sendEOM();
1675 hqSession_->closeWhenIdle();
1676 flushAndLoop(); // One read for the letter, one read for quic integer. Is
1677 // enough?
1678 }
1679
TEST_P(HQUpstreamSessionTestHQPush,TestPushPromiseFollowedByPushStream)1680 TEST_P(HQUpstreamSessionTestHQPush, TestPushPromiseFollowedByPushStream) {
1681 // the transaction is expected to timeout, since the PushPromise does not have
1682 // EOF set, and it is not followed by a PushStream.
1683 assocHandler_->expectError();
1684
1685 hq::PushId pushId = nextPushId();
1686
1687 auto pushPromiseRequest = getGetRequest();
1688
1689 expectPushPromiseBegin(
1690 [&](HTTPCodec::StreamID owningStreamId, hq::PushId promisedPushId) {
1691 EXPECT_EQ(promisedPushId, pushId);
1692 EXPECT_EQ(owningStreamId, assocHandler_->txn_->getID());
1693 });
1694
1695 expectPushPromise([&](HTTPCodec::StreamID owningStreamId,
1696 hq::PushId promisedPushId,
1697 HTTPMessage* msg) {
1698 EXPECT_EQ(promisedPushId, pushId);
1699 EXPECT_EQ(owningStreamId, assocHandler_->txn_->getID());
1700
1701 EXPECT_THAT(msg, NotNull());
1702
1703 auto expectedHeaders = pushPromiseRequest.getHeaders();
1704 auto actualHeaders = msg->getHeaders();
1705
1706 expectedHeaders.forEach(
1707 [&](const std::string& header, const std::string& /* val */) {
1708 EXPECT_TRUE(actualHeaders.exists(header));
1709 EXPECT_EQ(expectedHeaders.getNumberOfValues(header),
1710 actualHeaders.getNumberOfValues(header));
1711 });
1712 });
1713
1714 HTTPCodec::StreamID nascentStreamId;
1715
1716 expectNascentPushStreamBegin([&](HTTPCodec::StreamID streamId, bool isEOF) {
1717 nascentStreamId = streamId;
1718 folly::Optional<HTTPCodec::StreamID> expectedReadId(nascentStreamId);
1719 EXPECT_CALL(infoCb_, onRead(testing::_, testing::_, expectedReadId))
1720 .Times(testing::AtLeast(1));
1721 EXPECT_FALSE(isEOF);
1722 });
1723
1724 // since push stream arrives after the promise,
1725 // full ingress push stream has to be created
1726 expectNascentPushStream([&](HTTPCodec::StreamID pushStreamId,
1727 hq::PushId pushStreamPushId,
1728 bool /* isEOF */) {
1729 EXPECT_EQ(pushStreamPushId, pushId);
1730 EXPECT_EQ(pushStreamId, nascentStreamId);
1731 });
1732
1733 proxygen::HTTPHeaderSize pushPromiseSize;
1734
1735 sendPushPromise(assocHandler_->txn_->getID(),
1736 pushPromiseRequest,
1737 pushId,
1738 &pushPromiseSize);
1739 HTTPMessage resp;
1740 resp.setStatusCode(200);
1741 createPushStream(pushId, resp, makeBuf(100), true);
1742
1743 assocHandler_->txn_->sendEOM();
1744
1745 auto pushHandler = expectPushResponse();
1746
1747 hqSession_->closeWhenIdle();
1748 flushAndLoop();
1749 }
1750
TEST_P(HQUpstreamSessionTestHQPush,TestAbortedPushedTransactionAfterPromise)1751 TEST_P(HQUpstreamSessionTestHQPush, TestAbortedPushedTransactionAfterPromise) {
1752 assocHandler_->txn_->sendAbort();
1753 assocHandler_ = openTransaction();
1754 assocHandler_->txn_->sendHeaders(getGetRequest());
1755 assocHandler_->txn_->sendEOM();
1756 assocHandler_->expectHeaders();
1757 assocHandler_->expectBody();
1758 assocHandler_->expectEOM();
1759 assocHandler_->expectDetachTransaction();
1760
1761 auto resp = makeResponse(200, 100);
1762 sendResponse(assocHandler_->txn_->getID(),
1763 *std::get<0>(resp),
1764 std::move(std::get<1>(resp)),
1765 false);
1766 flushAndLoopN(1);
1767
1768 auto pushHandler = std::make_unique<MockHTTPHandler>();
1769 pushHandler->expectTransaction();
1770 assocHandler_->expectPushedTransaction(pushHandler.get());
1771 // Abort the pushed transaction upon reception of the push promise.
1772 pushHandler->expectHeaders(
1773 [&](std::shared_ptr<HTTPMessage>) { pushHandler->txn_->sendAbort(); });
1774
1775 auto pushPromiseRequest = getGetRequest();
1776 hq::PushId pushId = nextPushId();
1777 sendPushPromise(assocHandler_->txn_->getID(), pushPromiseRequest, pushId);
1778 // Send body to close the main request stream
1779 sendPartialBody(assocHandler_->txn_->getID(), nullptr, true);
1780 pushHandler->expectDetachTransaction();
1781
1782 flushAndLoop();
1783 hqSession_->closeWhenIdle();
1784 }
1785
TEST_P(HQUpstreamSessionTestHQPush,TestAbortedPushedTransactionAfterResponse)1786 TEST_P(HQUpstreamSessionTestHQPush, TestAbortedPushedTransactionAfterResponse) {
1787 assocHandler_->txn_->sendAbort();
1788 assocHandler_ = openTransaction();
1789 assocHandler_->txn_->sendHeaders(getGetRequest());
1790 assocHandler_->txn_->sendEOM();
1791 assocHandler_->expectHeaders();
1792 assocHandler_->expectBody();
1793 assocHandler_->expectEOM();
1794 assocHandler_->expectDetachTransaction();
1795
1796 auto resp = makeResponse(200, 100);
1797 sendResponse(assocHandler_->txn_->getID(),
1798 *std::get<0>(resp),
1799 std::move(std::get<1>(resp)),
1800 false);
1801 flushAndLoopN(1);
1802
1803 auto pushHandler = std::make_unique<MockHTTPHandler>();
1804 pushHandler->expectTransaction();
1805 assocHandler_->expectPushedTransaction(pushHandler.get());
1806 // Expect normal promise.
1807 pushHandler->expectHeaders([](std::shared_ptr<HTTPMessage>) {});
1808
1809 auto pushPromiseRequest = getGetRequest();
1810 pushPromiseRequest.getHeaders().set("Dynamic1", "a");
1811 hq::PushId pushId = nextPushId();
1812 sendPushPromise(assocHandler_->txn_->getID(), pushPromiseRequest, pushId);
1813 sendPartialBody(assocHandler_->txn_->getID(), nullptr, true);
1814 flushAndLoopN(1);
1815
1816 // Abort the pushed transaction on response.
1817 pushHandler->expectHeaders(
1818 [&](std::shared_ptr<HTTPMessage>) { pushHandler->txn_->sendAbort(); });
1819 pushHandler->expectDetachTransaction();
1820 HTTPMessage pushResp;
1821 pushResp.setStatusCode(200);
1822 pushResp.getHeaders().set("Dynamic2", "b");
1823 createPushStream(pushId, pushResp, makeBuf(100), true);
1824
1825 flushAndLoop();
1826 hqSession_->closeWhenIdle();
1827 }
1828
TEST_P(HQUpstreamSessionTestHQPush,TestOnPushedTransaction)1829 TEST_P(HQUpstreamSessionTestHQPush, TestOnPushedTransaction) {
1830 // the transaction is expected to timeout, since the PushPromise does not have
1831 // EOF set, and it is not followed by a PushStream.
1832 assocHandler_->expectError();
1833 // assocHandler_->expectHeaders();
1834
1835 hq::PushId pushId = nextPushId();
1836
1837 auto pushPromiseRequest = getGetRequest();
1838
1839 proxygen::HTTPHeaderSize pushPromiseSize;
1840
1841 sendPushPromise(assocHandler_->txn_->getID(),
1842 pushPromiseRequest,
1843 pushId,
1844 &pushPromiseSize);
1845
1846 HTTPMessage resp;
1847 resp.setStatusCode(200);
1848 createPushStream(pushId, resp, makeBuf(100), true);
1849
1850 // Once both push promise and push stream have been received, a push
1851 // transaction should be created
1852 assocHandler_->txn_->sendEOM();
1853
1854 auto pushHandler = expectPushResponse();
1855
1856 hqSession_->closeWhenIdle();
1857 flushAndLoop();
1858 }
1859
TEST_P(HQUpstreamSessionTestHQPush,TestOnPushedTransactionOutOfOrder)1860 TEST_P(HQUpstreamSessionTestHQPush, TestOnPushedTransactionOutOfOrder) {
1861 // the transaction is expected to timeout, since the PushPromise does not have
1862 // EOF set, and it is not followed by a PushStream.
1863 assocHandler_->expectError();
1864 // assocHandler_->expectHeaders();
1865
1866 hq::PushId pushId = nextPushId();
1867
1868 HTTPMessage resp;
1869 resp.setStatusCode(200);
1870 createPushStream(pushId, resp, makeBuf(100), true);
1871
1872 auto pushPromiseRequest = getGetRequest();
1873 proxygen::HTTPHeaderSize pushPromiseSize;
1874 sendPushPromise(assocHandler_->txn_->getID(),
1875 pushPromiseRequest,
1876 pushId,
1877 &pushPromiseSize);
1878
1879 // Once both push promise and push stream have been received, a push
1880 // transaction should be created
1881 auto pushHandler = expectPushResponse();
1882
1883 assocHandler_->txn_->sendEOM();
1884
1885 hqSession_->closeWhenIdle();
1886 flushAndLoop();
1887 }
1888
TEST_P(HQUpstreamSessionTestHQPush,TestCloseDroppedConnection)1889 TEST_P(HQUpstreamSessionTestHQPush, TestCloseDroppedConnection) {
1890 HQSession::DestructorGuard dg(hqSession_);
1891 // Two "onError" calls are expected:
1892 // the first when MockQuicSocketDriver closes the socket
1893 // the second when the error is propagated to the stream
1894 EXPECT_CALL(*assocHandler_, onError(testing::_)).Times(2);
1895
1896 // Create a nascent push stream with a preface only
1897 createNascentPushStream(1111 /* streamId */, folly::none /* pushId */);
1898
1899 // Run the event loop to let the dispatcher register the nascent stream
1900 flushAndLoop();
1901
1902 // Drop the connection
1903 hqSession_->dropConnection();
1904 flushAndLoop();
1905 }
1906
TEST_P(HQUpstreamSessionTestHQPush,TestOrphanedPushStream)1907 TEST_P(HQUpstreamSessionTestHQPush, TestOrphanedPushStream) {
1908 // the transaction is expected to timeout, since the PushPromise does not have
1909 // EOF set, and it is not followed by a PushStream.
1910 assocHandler_->expectError();
1911
1912 hq::PushId pushId = nextPushId();
1913
1914 HTTPMessage resp;
1915 resp.setStatusCode(200);
1916 createPushStream(pushId, resp, makeBuf(100), true);
1917
1918 assocHandler_->txn_->sendEOM();
1919
1920 hqSession_->closeWhenIdle();
1921 flushAndLoop();
1922 }
1923
TEST_P(HQUpstreamSessionTestHQ,TestNoDatagram)1924 TEST_P(HQUpstreamSessionTestHQ, TestNoDatagram) {
1925 EXPECT_FALSE(httpCallbacks_.datagramEnabled);
1926 auto handler = openTransaction();
1927 EXPECT_EQ(handler->txn_->getDatagramSizeLimit(), 0);
1928 auto resp = makeResponse(200, 100);
1929 sendResponse(handler->txn_->getID(),
1930 *std::get<0>(resp),
1931 std::move(std::get<1>(resp)),
1932 true);
1933 handler->txn_->sendHeaders(getGetRequest());
1934 handler->txn_->sendEOM();
1935 handler->expectHeaders();
1936 handler->expectBody();
1937 handler->expectEOM();
1938 handler->expectDetachTransaction();
1939 hqSession_->closeWhenIdle();
1940 flushAndLoop();
1941 }
1942
TEST_P(HQUpstreamSessionTestHQDatagram,TestDatagramSettings)1943 TEST_P(HQUpstreamSessionTestHQDatagram, TestDatagramSettings) {
1944 EXPECT_TRUE(httpCallbacks_.datagramEnabled);
1945 auto handler = openTransaction();
1946 EXPECT_GT(handler->txn_->getDatagramSizeLimit(), 0);
1947 auto resp = makeResponse(200, 100);
1948 sendResponse(handler->txn_->getID(),
1949 *std::get<0>(resp),
1950 std::move(std::get<1>(resp)),
1951 true);
1952 handler->txn_->sendHeaders(getGetRequest());
1953 handler->txn_->sendEOM();
1954 handler->expectHeaders();
1955 handler->expectBody();
1956 handler->expectEOM();
1957 handler->expectDetachTransaction();
1958 hqSession_->closeWhenIdle();
1959 flushAndLoop();
1960 }
1961
TEST_P(HQUpstreamSessionTestHQDatagram,TestReceiveDatagram)1962 TEST_P(HQUpstreamSessionTestHQDatagram, TestReceiveDatagram) {
1963 EXPECT_TRUE(httpCallbacks_.datagramEnabled);
1964 auto handler = openTransaction();
1965 auto id = handler->txn_->getID();
1966 EXPECT_GT(handler->txn_->getDatagramSizeLimit(), 0);
1967 MockHTTPTransactionTransportCallback transportCallback_;
1968 handler->txn_->setTransportCallback(&transportCallback_);
1969 EXPECT_CALL(transportCallback_, datagramBytesReceived(::testing::_)).Times(1);
1970 handler->txn_->sendHeaders(getGetRequest());
1971 handler->txn_->sendEOM();
1972 auto resp = makeResponse(200, 0);
1973 sendResponse(id, *std::get<0>(resp), std::move(std::get<1>(resp)), false);
1974 handler->expectHeaders();
1975 flushAndLoopN(1);
1976 auto h3Datagram = getH3Datagram(id, folly::IOBuf::wrapBuffer("testtest", 8));
1977 socketDriver_->addDatagram(std::move(h3Datagram));
1978 handler->expectDatagram();
1979 flushAndLoopN(1);
1980 auto it = streams_.find(id);
1981 CHECK(it != streams_.end());
1982 auto& stream = it->second;
1983 stream.readEOF = true;
1984 handler->expectEOM();
1985 handler->expectDetachTransaction();
1986 hqSession_->closeWhenIdle();
1987 flushAndLoop();
1988 }
1989
TEST_P(HQUpstreamSessionTestHQDatagram,TestReceiveEarlyDatagramsSingleStream)1990 TEST_P(HQUpstreamSessionTestHQDatagram, TestReceiveEarlyDatagramsSingleStream) {
1991 EXPECT_TRUE(httpCallbacks_.datagramEnabled);
1992 auto handler = openTransaction();
1993 auto id = handler->txn_->getID();
1994 EXPECT_GT(handler->txn_->getDatagramSizeLimit(), 0);
1995 handler->txn_->sendHeaders(getGetRequest());
1996 handler->txn_->sendEOM();
1997 for (auto i = 0; i < kDefaultMaxBufferedDatagrams * 2; ++i) {
1998 auto h3Datagram =
1999 getH3Datagram(id, folly::IOBuf::wrapBuffer("testtest", 8));
2000 socketDriver_->addDatagram(std::move(h3Datagram));
2001 }
2002 flushAndLoopN(1);
2003 auto resp = makeResponse(200, 0);
2004 sendResponse(id, *std::get<0>(resp), std::move(std::get<1>(resp)), false);
2005 handler->expectHeaders();
2006 EXPECT_CALL(*handler, onDatagram(testing::_))
2007 .Times(kDefaultMaxBufferedDatagrams);
2008 flushAndLoopN(1);
2009 auto it = streams_.find(id);
2010 CHECK(it != streams_.end());
2011 auto& stream = it->second;
2012 stream.readEOF = true;
2013 handler->expectEOM();
2014 handler->expectDetachTransaction();
2015 hqSession_->closeWhenIdle();
2016 flushAndLoop();
2017 }
2018
TEST_P(HQUpstreamSessionTestHQDatagram,TestReceiveEarlyDatagramsMultiStream)2019 TEST_P(HQUpstreamSessionTestHQDatagram, TestReceiveEarlyDatagramsMultiStream) {
2020 auto deliveredDatagrams = 0;
2021 EXPECT_TRUE(httpCallbacks_.datagramEnabled);
2022 std::vector<std::unique_ptr<StrictMock<MockHTTPHandler>>> handlers;
2023
2024 for (auto i = 0; i < kMaxStreamsWithBufferedDatagrams * 2; ++i) {
2025 handlers.emplace_back(openTransaction());
2026 auto handler = handlers.back().get();
2027 auto id = handler->txn_->getID();
2028 EXPECT_GT(handler->txn_->getDatagramSizeLimit(), 0);
2029 handler->txn_->sendHeaders(getGetRequest());
2030 handler->txn_->sendEOM();
2031 auto h3Datagram =
2032 getH3Datagram(id, folly::IOBuf::wrapBuffer("testtest", 8));
2033 socketDriver_->addDatagram(std::move(h3Datagram));
2034 flushAndLoopN(1);
2035 }
2036
2037 for (const auto& handler : handlers) {
2038 auto id = handler->txn_->getID();
2039 auto resp = makeResponse(200, 0);
2040 sendResponse(id, *std::get<0>(resp), std::move(std::get<1>(resp)), false);
2041 handler->expectHeaders();
2042 EXPECT_CALL(*handler, onDatagram(testing::_))
2043 .WillRepeatedly(InvokeWithoutArgs([&]() { deliveredDatagrams++; }));
2044 flushAndLoopN(1);
2045 auto it = streams_.find(id);
2046 CHECK(it != streams_.end());
2047 auto& stream = it->second;
2048 stream.readEOF = true;
2049 handler->expectEOM();
2050 handler->expectDetachTransaction();
2051 flushAndLoopN(1);
2052 }
2053 EXPECT_EQ(deliveredDatagrams, kMaxStreamsWithBufferedDatagrams);
2054 hqSession_->closeWhenIdle();
2055 flushAndLoop();
2056 }
2057
2058 /**
2059 * Instantiate the Parametrized test cases
2060 */
2061
2062 // Make sure all the tests keep working with all the supported protocol versions
2063 INSTANTIATE_TEST_CASE_P(HQUpstreamSessionTest,
2064 HQUpstreamSessionTest,
2065 Values(
__anon346abe7d2902null2066 [] {
2067 TestParams tp;
2068 tp.alpn_ = "h1q-fb";
2069 return tp;
2070 }(),
__anon346abe7d2a02null2071 [] {
2072 TestParams tp;
2073 tp.alpn_ = "h1q-fb-v2";
2074 return tp;
2075 }(),
__anon346abe7d2b02null2076 [] {
2077 TestParams tp;
2078 tp.alpn_ = "h3";
2079 return tp;
2080 }()),
2081 paramsToTestName);
2082
2083 // Instantiate h1q-fb-v2 and hq only tests (goaway tests)
2084 INSTANTIATE_TEST_CASE_P(HQUpstreamSessionTest,
2085 HQUpstreamSessionTestH1qv2HQ,
2086 Values(
__anon346abe7d2c02null2087 [] {
2088 TestParams tp;
2089 tp.alpn_ = "h1q-fb-v2";
2090 return tp;
2091 }(),
__anon346abe7d2d02null2092 [] {
2093 TestParams tp;
2094 tp.alpn_ = "h3";
2095 return tp;
2096 }()),
2097 paramsToTestName);
2098
2099 // Instantiate h1q-fb-v1 only tests
2100 INSTANTIATE_TEST_CASE_P(HQUpstreamSessionTest,
2101 HQUpstreamSessionTestH1qv1,
__anon346abe7d2e02null2102 Values([] {
2103 TestParams tp;
2104 tp.alpn_ = "h1q-fb";
2105 return tp;
2106 }()),
2107 paramsToTestName);
2108
2109 // Instantiate hq only tests
2110 INSTANTIATE_TEST_CASE_P(HQUpstreamSessionTest,
2111 HQUpstreamSessionTestHQ,
__anon346abe7d2f02null2112 Values([] {
2113 TestParams tp;
2114 tp.alpn_ = "h3";
2115 return tp;
2116 }()),
2117 paramsToTestName);
2118
2119 // Instantiate tests for H3 Push functionality (requires HQ)
2120 INSTANTIATE_TEST_CASE_P(HQUpstreamSessionTest,
2121 HQUpstreamSessionTestHQPush,
__anon346abe7d3002null2122 Values([] {
2123 TestParams tp;
2124 tp.alpn_ = "h3";
2125 tp.unidirectionalStreamsCredit = 4;
2126 return tp;
2127 }()),
2128 paramsToTestName);
2129
2130 // Instantiate tests with QPACK on/off
2131 INSTANTIATE_TEST_CASE_P(HQUpstreamSessionTest,
2132 HQUpstreamSessionTestQPACK,
2133 Values(
__anon346abe7d3102null2134 [] {
2135 TestParams tp;
2136 tp.alpn_ = "h3";
2137 return tp;
2138 }(),
__anon346abe7d3202null2139 [] {
2140 TestParams tp;
2141 tp.alpn_ = "h3";
2142 tp.createQPACKStreams_ = false;
2143 return tp;
2144 }()),
2145 paramsToTestName);
2146
2147 // Instantiate h3 datagram tests
2148 INSTANTIATE_TEST_CASE_P(HQUpstreamSessionTest,
2149 HQUpstreamSessionTestHQDatagram,
__anon346abe7d3302null2150 Values([] {
2151 TestParams tp;
2152 tp.alpn_ = "h3";
2153 tp.datagrams_ = true;
2154 return tp;
2155 }()),
2156 paramsToTestName);
2157