From 3347bcc4b24393c6778ea6e72faa7b3f5d3c3118 Mon Sep 17 00:00:00 2001 From: Alex Hultman Date: Mon, 11 Jan 2021 13:13:06 +0100 Subject: [PATCH] Questionable: support ancient Http and connection: close --- src/HttpContext.h | 23 +++++++++++++++++++++++ src/HttpParser.h | 8 ++++++++ src/HttpResponseData.h | 2 +- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/HttpContext.h b/src/HttpContext.h index 9a4cc34..e977bb4 100644 --- a/src/HttpContext.h +++ b/src/HttpContext.h @@ -151,6 +151,11 @@ private: /* Mark pending request and emit it */ httpResponseData->state = HttpResponseData::HTTP_RESPONSE_PENDING; + /* Mark this response as connectionClose if ancient or connection: close */ + if (httpRequest->isAncient() || httpRequest->getHeader("connection").length() == 5) { + httpResponseData->state |= HttpResponseData::HTTP_CONNECTION_CLOSE; + } + /* Route the method and URL */ httpContextData->router.getUserData() = {(HttpResponse *) s, httpRequest}; if (!httpContextData->router.route(httpRequest->getMethod(), httpRequest->getUrl())) { @@ -242,6 +247,15 @@ private: ((AsyncSocket *) s)->timeout(HTTP_IDLE_TIMEOUT_S); } + /* We need to check if we should close this socket here now */ + if (httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) { + if ((httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) == 0) { + if (((AsyncSocket *) s)->getBufferedAmount() == 0) { + ((AsyncSocket *) s)->shutdown(); + } + } + } + return (us_socket_t *) returnedSocket; } @@ -305,6 +319,15 @@ private: /* Drain any socket buffer, this might empty our backpressure and thus finish the request */ /*auto [written, failed] = */asyncSocket->write(nullptr, 0, true, 0); + /* Should we close this connection after a response - and is this response really done? */ + if (httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) { + if ((httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) == 0) { + if (asyncSocket->getBufferedAmount() == 0) { + asyncSocket->shutdown(); + } + } + } + /* Expect another writable event, or another request within the timeout */ asyncSocket->timeout(HTTP_IDLE_TIMEOUT_S); diff --git a/src/HttpParser.h b/src/HttpParser.h index 95e08ff..2a9e774 100644 --- a/src/HttpParser.h +++ b/src/HttpParser.h @@ -45,12 +45,17 @@ private: struct Header { std::string_view key, value; } headers[MAX_HEADERS]; + bool ancientHttp; unsigned int querySeparator; bool didYield; BloomFilter bf; std::pair currentParameters; public: + bool isAncient() { + return ancientHttp; + } + bool getYield() { return didYield; } @@ -226,6 +231,9 @@ private: length -= consumed; consumedTotal += consumed; + /* Store HTTP version (ancient 1.0 or 1.1) */ + req->ancientHttp = req->headers->value.length() && (req->headers->value[req->headers->value.length() - 1] == '0'); + /* Strip away tail of first "header value" aka URL */ req->headers->value = std::string_view(req->headers->value.data(), (size_t) std::max(0, (int) req->headers->value.length() - 9)); diff --git a/src/HttpResponseData.h b/src/HttpResponseData.h index 5746f4f..803fa55 100644 --- a/src/HttpResponseData.h +++ b/src/HttpResponseData.h @@ -39,7 +39,7 @@ private: HTTP_WRITE_CALLED = 2, // used HTTP_END_CALLED = 4, // used HTTP_RESPONSE_PENDING = 8, // used - HTTP_ENDED_STREAM_OUT = 16 // not used + HTTP_CONNECTION_CLOSE = 16 // used }; /* Per socket event handlers */