Skip to content

Commit 4545e19

Browse files
Copilotithewei
andcommitted
Fix HTTP pipeline async response crash by creating new req/resp per request
Instead of resetting the existing HttpRequest/HttpResponse objects in HttpHandler::Reset(), create new ones. This prevents a race condition where async handlers (holding shared_ptr references to the old req/resp) could crash when FeedRecvData calls Reset() upon receiving HTTP pipeline data or an attack while the async response is still being written. The old req/resp objects remain alive through the shared_ptr references held by the async handler, while the handler gets fresh objects for the new incoming request. Co-authored-by: ithewei <26049660+ithewei@users.noreply.github.com>
1 parent 35c78cc commit 4545e19

1 file changed

Lines changed: 32 additions & 6 deletions

File tree

http/server/HttpHandler.cpp

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,43 @@ bool HttpHandler::Init(int http_version) {
111111
void HttpHandler::Reset() {
112112
state = WANT_RECV;
113113
error = 0;
114-
req->Reset();
115-
resp->Reset();
114+
// Create new request/response to avoid race condition with async handlers
115+
// that may still hold shared_ptr references to the old req/resp objects.
116+
// This prevents crashes when HTTP pipeline data arrives while an async
117+
// response is still being written.
118+
req = std::make_shared<HttpRequest>();
119+
resp = std::make_shared<HttpResponse>();
120+
if (protocol == HTTP_V2) {
121+
resp->http_major = req->http_major = 2;
122+
resp->http_minor = req->http_minor = 0;
123+
}
116124
ctx = NULL;
117125
api_handler = NULL;
118126
closeFile();
119-
if (writer) {
120-
writer->Begin();
121-
writer->onwrite = NULL;
122-
writer->onclose = NULL;
127+
if (io) {
128+
writer = std::make_shared<HttpResponseWriter>(io, resp);
129+
writer->status = hv::SocketChannel::CONNECTED;
123130
}
124131
parser->InitRequest(req.get());
132+
// Re-hook http_cb for the new request object
133+
req->http_cb = [this](HttpMessage* msg, http_parser_state state, const char* data, size_t size) {
134+
if (this->state == WANT_CLOSE) return;
135+
switch (state) {
136+
case HP_HEADERS_COMPLETE:
137+
if (this->error != 0) return;
138+
onHeadersComplete();
139+
break;
140+
case HP_BODY:
141+
if (this->error != 0) return;
142+
onBody(data, size);
143+
break;
144+
case HP_MESSAGE_COMPLETE:
145+
onMessageComplete();
146+
break;
147+
default:
148+
break;
149+
}
150+
};
125151
}
126152

127153
void HttpHandler::Close() {

0 commit comments

Comments
 (0)