diff --git a/examples/http_server_test.cpp b/examples/http_server_test.cpp index 2b01c0011..0adb3aee4 100644 --- a/examples/http_server_test.cpp +++ b/examples/http_server_test.cpp @@ -97,6 +97,12 @@ int main(int argc, char** argv) { writer->End(); }); + // curl -v http://ip:port/close + // Test HTTP_STATUS_CLOSE: closes connection without sending any response + router.GET("/close", [](HttpRequest* req, HttpResponse* resp) { + return HTTP_STATUS_CLOSE; + }); + // middleware router.AllowCORS(); router.Use([](HttpRequest* req, HttpResponse* resp) { diff --git a/http/server/HttpHandler.cpp b/http/server/HttpHandler.cpp index 29aa363c4..005967328 100644 --- a/http/server/HttpHandler.cpp +++ b/http/server/HttpHandler.cpp @@ -254,6 +254,10 @@ void HttpHandler::onHeadersComplete() { handleRequestHeaders(); if (service->headerHandler) { const int status_code = customHttpHandler(service->headerHandler); + if (status_code == HTTP_STATUS_CLOSE) { + state = WANT_CLOSE; + return; + } if (status_code != HTTP_STATUS_OK && status_code != HTTP_STATUS_NEXT) { SetError(ERR_REQUEST, static_cast(status_code)); return; @@ -338,6 +342,10 @@ void HttpHandler::onMessageComplete() { } } else { status_code = HandleHttpRequest(); + if (status_code == HTTP_STATUS_CLOSE) { + state = WANT_CLOSE; + return; + } if (status_code != HTTP_STATUS_NEXT) { SendHttpResponse(); } @@ -478,12 +486,17 @@ int HttpHandler::HandleHttpRequest() { pResp->status_code = (http_status)status_code; if (pResp->status_code >= 400 && pResp->body.size() == 0 && pReq->method != HTTP_HEAD) { if (service->errorHandler) { - customHttpHandler(service->errorHandler); + status_code = customHttpHandler(service->errorHandler); } else { defaultErrorHandler(); } } } + // Handle HTTP_STATUS_CLOSE: close connection without response + if (status_code == HTTP_STATUS_CLOSE) { + state = WANT_CLOSE; + return HTTP_STATUS_CLOSE; + } if (fc) { pResp->content = fc->filebuf.base; pResp->content_length = fc->filebuf.len; @@ -492,7 +505,11 @@ int HttpHandler::HandleHttpRequest() { pResp->headers["Etag"] = fc->etag; } if (service->postprocessor) { - customHttpHandler(service->postprocessor); + status_code = customHttpHandler(service->postprocessor); + if (status_code == HTTP_STATUS_CLOSE) { + state = WANT_CLOSE; + return HTTP_STATUS_CLOSE; + } } if (writer && writer->state != hv::HttpResponseWriter::SEND_BEGIN) { @@ -760,7 +777,7 @@ int HttpHandler::GetSendData(char** data, size_t* len) { if (parser->IsComplete()) state = WANT_SEND; else return 0; case HANDLE_END: - state = WANT_SEND; + state = WANT_SEND; case WANT_SEND: state = SEND_HEADER; case SEND_HEADER: diff --git a/http/server/HttpService.h b/http/server/HttpService.h index 8124354f2..16ef7a3c2 100644 --- a/http/server/HttpService.h +++ b/http/server/HttpService.h @@ -29,11 +29,13 @@ /* * @param[in] req: parsed structured http request * @param[out] resp: structured http response - * @return 0: handle next - * http_status_code: handle done + * @return HTTP_STATUS_NEXT: handle next + * HTTP_STATUS_CLOSE: close connection + * http_status_code: handle done */ #define HTTP_STATUS_NEXT 0 #define HTTP_STATUS_UNFINISHED 0 +#define HTTP_STATUS_CLOSE -100 // NOTE: http_sync_handler run on IO thread typedef std::function http_sync_handler; // NOTE: http_async_handler run on hv::async threadpool