diff --git a/http/server/HttpHandler.cpp b/http/server/HttpHandler.cpp index 29aa363c4..71a96230a 100644 --- a/http/server/HttpHandler.cpp +++ b/http/server/HttpHandler.cpp @@ -86,6 +86,11 @@ bool HttpHandler::Init(int http_version) { tid = hv_gettid(); } parser->InitRequest(req.get()); + hookHttpCb(); + return true; +} + +void HttpHandler::hookHttpCb() { // NOTE: hook http_cb req->http_cb = [this](HttpMessage* msg, http_parser_state state, const char* data, size_t size) { if (this->state == WANT_CLOSE) return; @@ -105,23 +110,42 @@ bool HttpHandler::Init(int http_version) { break; } }; - return true; } void HttpHandler::Reset() { state = WANT_RECV; error = 0; - req->Reset(); - resp->Reset(); + // Create new request/response to avoid race condition with async handlers + // that may still hold shared_ptr references to the old req/resp objects. + // This prevents crashes when HTTP pipeline data arrives while an async + // response is still being written. + req = std::make_shared(); + resp = std::make_shared(); + if (protocol == HTTP_V2) { + resp->http_major = req->http_major = 2; + resp->http_minor = req->http_minor = 0; + } ctx = NULL; api_handler = NULL; closeFile(); if (writer) { - writer->Begin(); + // Retire old writer: mark DISCONNECTED and clear io_ so that + // ~Channel() won't close the hio_t when the async handler's + // shared_ptr reference is eventually released, and any + // further write attempts through the old writer fail gracefully. + writer->status = hv::SocketChannel::DISCONNECTED; + writer->io_ = NULL; writer->onwrite = NULL; writer->onclose = NULL; } + if (io) { + writer = std::make_shared(io, resp); + writer->status = hv::SocketChannel::CONNECTED; + } else { + writer = NULL; + } parser->InitRequest(req.get()); + hookHttpCb(); } void HttpHandler::Close() { diff --git a/http/server/HttpHandler.h b/http/server/HttpHandler.h index b72f07772..f9b1ba8ae 100644 --- a/http/server/HttpHandler.h +++ b/http/server/HttpHandler.h @@ -149,6 +149,7 @@ class HttpHandler { void addResponseHeaders(); // http_cb + void hookHttpCb(); void onHeadersComplete(); void onBody(const char* data, size_t size); void onMessageComplete();