From 42381a878b99740f9833e49e780fe3752ff5bd6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 20 Jan 2025 12:29:46 +0100 Subject: [PATCH] Output the HTTPStatusException message as the response status phrase. This has been the intent for the message parameter the whole time, but just now attracted attention, because in the HTTP/1.x server the status phrase has actually never been set appropriately. --- source/vibe/http/common.d | 8 +++++ source/vibe/http/internal/http1/server.d | 3 ++ .../vibe.http.server.statusexception/dub.sdl | 4 +++ .../source/app.d | 36 +++++++++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 tests/vibe.http.server.statusexception/dub.sdl create mode 100644 tests/vibe.http.server.statusexception/source/app.d diff --git a/source/vibe/http/common.d b/source/vibe/http/common.d index 85ecb76..faf8785 100644 --- a/source/vibe/http/common.d +++ b/source/vibe/http/common.d @@ -332,8 +332,16 @@ class HTTPStatusException : Exception { int m_status; } + /** Construct a new exception corresponding to a particular HTTP status code. + + Params: + status = The HTTP status code associated with the exception + message = HTTP status phrase sent together with the status code - + must be a single-line string + */ this(int status, string message = null, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { + assert(message.indexOf('\n') < 0, "HTTP status phrase must be single-line!"); super(message.length ? message : httpStatusText(status), file, line, next); m_status = status; } diff --git a/source/vibe/http/internal/http1/server.d b/source/vibe/http/internal/http1/server.d index b164bd2..5a606b7 100644 --- a/source/vibe/http/internal/http1/server.d +++ b/source/vibe/http/internal/http1/server.d @@ -121,8 +121,11 @@ private bool handleRequest(TLSStreamType, Allocator)(StreamProxy http_stream, TC void errorOut(int code, string msg, string debug_msg, Throwable ex) @safe { assert(!res.headerWritten); + assert(msg.length > 0 && !msg.canFind('\n'), "HTTP error status message must be a non-empty single-line string"); res.statusCode = code; + res.statusPhrase = msg; + if (settings && settings.errorPageHandler) { /*scope*/ auto err = new HTTPServerErrorInfo; err.code = code; diff --git a/tests/vibe.http.server.statusexception/dub.sdl b/tests/vibe.http.server.statusexception/dub.sdl new file mode 100644 index 0000000..ec0c7a3 --- /dev/null +++ b/tests/vibe.http.server.statusexception/dub.sdl @@ -0,0 +1,4 @@ +name "tests" +description "Wrong host header tests" +dependency "vibe-http" path="../../" +versions "VibeDefaultMain" diff --git a/tests/vibe.http.server.statusexception/source/app.d b/tests/vibe.http.server.statusexception/source/app.d new file mode 100644 index 0000000..f30a431 --- /dev/null +++ b/tests/vibe.http.server.statusexception/source/app.d @@ -0,0 +1,36 @@ +import vibe.core.core; +import vibe.core.log : logInfo; +import vibe.core.net; +import vibe.http.server; +import vibe.stream.operations; +import core.time : msecs, seconds; +import std.datetime : Clock, UTC; + +shared static this() +{ + auto s1 = new HTTPServerSettings; + s1.options &= ~HTTPServerOption.errorStackTraces; + s1.port = 0; + s1.bindAddresses = ["127.0.0.1"]; + immutable serverAddr = listenHTTP(s1, &handler).bindAddresses[0]; + + runTask({ + try { + auto conn = connectTCP(serverAddr); + conn.write("GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n"); + string res = cast(string)conn.readLine(); + assert(res == "HTTP/1.1 403 This is not accessible!", res); + while (conn.readLine().length > 0) {} + assert(cast(string)conn.readAllUTF8() == "403 - Forbidden\n\nThis is not accessible!"); + } catch (Exception e) { + assert(false, e.msg); + } + + scope (exit) exitEventLoop(); + }); +} + +void handler(scope HTTPServerRequest req, scope HTTPServerResponse res) +{ + throw new HTTPStatusException(HTTPStatus.forbidden, "This is not accessible!"); +}