Skip to content

Commit 924fff0

Browse files
dcsommerfacebook-github-bot
authored andcommitted
S471570 repro and fix
Summary: Without the fixes to the state machine, this new test crashes in the same way as the SEV. See also https://fburl.com/logview/9t8mibce Credit to hanidamlaj for creating the repro. Reviewed By: afrind Differential Revision: D66457655 fbshipit-source-id: 2e75d636be273172a3b8c9bacb389f6f3b275fed
1 parent ee61e6d commit 924fff0

File tree

4 files changed

+77
-10
lines changed

4 files changed

+77
-10
lines changed

proxygen/lib/http/session/HTTPTransaction.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,11 +1447,7 @@ size_t HTTPTransaction::maybeSendDeferredNoError() {
14471447

14481448
void HTTPTransaction::sendPadding(uint16_t bytes) {
14491449
VLOG(4) << "egress padding=" << bytes << " on " << *this;
1450-
if (!validateEgressStateTransition(
1451-
// Sending padding is valid only when you can send body
1452-
HTTPTransactionEgressSM::Event::sendBody)) {
1453-
return;
1454-
}
1450+
// Padding is allowed at any time, even before headers and after EOM
14551451
transport_.sendPadding(this, bytes);
14561452
}
14571453

proxygen/lib/http/session/HTTPTransaction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1239,7 +1239,7 @@ class HTTPTransaction
12391239
* is currently implemented only for HTTP/2 and HTTP/3 and will do nothing on
12401240
* HTTP/1 connections.
12411241
*
1242-
* sendPadding() may be called only when sendBody() is also valid to call.
1242+
* sendPadding() may be called at any time, even before headers and after EOM.
12431243
*
12441244
* @param bytes The number of bytes of padding to send on this transaction.
12451245
* The actual serialized size of the padding will be greater than this number

proxygen/lib/http/session/test/HQDownstreamSessionTest.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,49 @@ TEST_P(HQDownstreamSessionTest, SimplePostWithPadding) {
604604
hqSession_->closeWhenIdle();
605605
}
606606

607+
TEST_P(HQDownstreamSessionTest, PaddingSM) {
608+
auto id = nextStreamId();
609+
auto res = requests_.emplace(std::piecewise_construct,
610+
std::forward_as_tuple(id),
611+
std::forward_as_tuple(makeCodec(id)));
612+
auto& request = res.first->second;
613+
request.id = request.codec->createStream();
614+
request.readEOF = false;
615+
request.codec->generatePadding(request.buf, request.id, 1'000);
616+
request.codec->generateHeader(
617+
request.buf, request.id, getPostRequest(100), false);
618+
request.codec->generatePadding(request.buf, request.id, 2'000);
619+
request.codec->generateBody(
620+
request.buf, request.id, makeBuf(100), HTTPCodec::NoPadding, true);
621+
request.codec->generatePadding(request.buf, request.id, 4'000);
622+
request.readEOF = true;
623+
624+
auto handler = addSimpleStrictHandler();
625+
handler->expectHeaders();
626+
handler->expectBody([](uint64_t, std::shared_ptr<folly::IOBuf> body) {
627+
EXPECT_EQ(body->computeChainDataLength(), 100);
628+
});
629+
handler->expectEOM([&handler] {
630+
handler->txn_->sendPadding(100);
631+
handler->txn_->sendHeaders(getResponse(200));
632+
handler->txn_->sendPadding(100);
633+
handler->txn_->sendChunkHeader(10);
634+
handler->txn_->sendPadding(100);
635+
handler->txn_->sendBody(makeBuf(10));
636+
handler->txn_->sendPadding(100);
637+
handler->txn_->sendChunkTerminator();
638+
handler->txn_->sendPadding(100);
639+
handler->txn_->sendEOM();
640+
handler->txn_->sendPadding(100);
641+
});
642+
handler->expectDetachTransaction();
643+
flushRequestsAndLoop();
644+
EXPECT_GT(socketDriver_->streams_[id].readOffset, 7'100);
645+
EXPECT_GT(socketDriver_->streams_[id].writeBuf.chainLength(), 610);
646+
EXPECT_TRUE(socketDriver_->streams_[id].writeEOF);
647+
hqSession_->closeWhenIdle();
648+
}
649+
607650
TEST_P(HQDownstreamSessionTest, SimpleGetEofDelay) {
608651
auto idh = checkRequest();
609652
flushRequestsAndLoop(false, std::chrono::milliseconds(10));

proxygen/lib/http/session/test/HTTPDownstreamSessionTest.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,11 +1114,33 @@ TEST_F(HTTPDownstreamSessionTest, BadContentLength) {
11141114
TEST_F(HTTP2DownstreamSessionTest, FrameBasedPadding) {
11151115
// Send a request with padding. Padding should not affect anything.
11161116
auto handler = addSimpleStrictHandler();
1117-
auto id = sendHeader();
1118-
clientCodec_->generatePadding(requests_, id, 123);
1119-
clientCodec_->generateEOM(requests_, id);
1117+
1118+
const auto streamID = clientCodec_->createStream();
1119+
clientCodec_->generatePadding(requests_, streamID, 100);
1120+
clientCodec_->generateHeader(
1121+
requests_, streamID, getPostRequest(1'000), false);
1122+
clientCodec_->generatePadding(requests_, streamID, 200);
1123+
clientCodec_->generateBody(
1124+
requests_, streamID, makeBuf(1'000), HTTPCodec::NoPadding, false);
1125+
clientCodec_->generatePadding(requests_, streamID, 400);
1126+
clientCodec_->generateEOM(requests_, streamID);
1127+
clientCodec_->generatePadding(requests_, streamID, 800);
1128+
11201129
handler->expectHeaders();
1121-
handler->expectEOM([&handler] { handler->sendReplyWithBody(200, 100); });
1130+
handler->expectBody();
1131+
handler->expectEOM([&handler] {
1132+
handler->txn_->sendPadding(100);
1133+
handler->txn_->sendHeaders(getResponse(200));
1134+
handler->txn_->sendPadding(100);
1135+
handler->txn_->sendChunkHeader(10);
1136+
handler->txn_->sendPadding(100);
1137+
handler->txn_->sendBody(makeBuf(10));
1138+
handler->txn_->sendPadding(100);
1139+
handler->txn_->sendChunkTerminator();
1140+
handler->txn_->sendPadding(100);
1141+
handler->txn_->sendEOM();
1142+
handler->txn_->sendPadding(100);
1143+
});
11221144
handler->expectGoaway();
11231145
flushRequestsAndLoopN(1);
11241146
handler->expectDetachTransaction();
@@ -1130,6 +1152,12 @@ TEST_F(HTTP2DownstreamSessionTest, FrameBasedPadding) {
11301152

11311153
InSequence enforceOrder;
11321154
EXPECT_CALL(callbacks, onHeadersComplete(_, _));
1155+
// No chunk header received, since it is not allowed in HTTP/2
1156+
// EXPECT_CALL(callbacks, onChunkHeader(_, 10));
1157+
EXPECT_CALL(callbacks, onBody(_, _, 0));
1158+
// No chunk terminator received, since it is not allowed in HTTP/2
1159+
// EXPECT_CALL(callbacks, onChunkComplete(_));
1160+
EXPECT_CALL(callbacks, onMessageComplete(_, _));
11331161
parseOutput(*clientCodec_);
11341162
}
11351163

0 commit comments

Comments
 (0)