Skip to content

Commit

Permalink
Merge pull request #2352 from tchaloupka/processing
Browse files Browse the repository at this point in the history
HTTPServer - add support for HTTP informational status message sending
  • Loading branch information
s-ludwig authored Dec 5, 2019
2 parents 0fe69fa + 8999b9e commit 3e14a47
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 1 deletion.
10 changes: 10 additions & 0 deletions http/vibe/http/client.d
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@ final class HTTPClient {
}

Exception user_exception;
while (true)
{
scope (failure) {
m_responding = false;
Expand All @@ -562,6 +563,14 @@ final class HTTPClient {
logDebug("Error while handling response: %s", e.toString().sanitize());
user_exception = e;
}
if (res.statusCode < 200) {
// just an informational status -> read and handle next response
if (m_responding) res.dropBody();
if (m_conn) {
res = scoped!HTTPClientResponse(this, has_body, close_conn, request_allocator, connected_time);
continue;
}
}
if (m_responding) {
logDebug("Failed to handle the complete response of the server - disconnecting.");
res.disconnect();
Expand All @@ -570,6 +579,7 @@ final class HTTPClient {

if (user_exception || res.headers.get("Connection") == "close")
disconnect();
break;
}
if (user_exception) throw user_exception;
}
Expand Down
8 changes: 7 additions & 1 deletion http/vibe/http/server.d
Original file line number Diff line number Diff line change
Expand Up @@ -1432,6 +1432,7 @@ final class HTTPServerResponse : HTTPResponse {
if (m_bodyWriter) return m_bodyWriter;

assert(!m_headerWritten, "A void body was already written!");
assert(this.statusCode >= 200, "1xx responses can't have body");

if (m_isHeadResponse) {
// for HEAD requests, we define a NullOutputWriter for convenience
Expand Down Expand Up @@ -1538,6 +1539,7 @@ final class HTTPServerResponse : HTTPResponse {
if (protocol.length) headers["Upgrade"] = protocol;
writeVoidBody();
m_requiresConnectionClose = true;
m_headerWritten = true;
return createConnectionProxyStream(m_conn, m_rawConnection);
}
/// ditto
Expand All @@ -1547,6 +1549,7 @@ final class HTTPServerResponse : HTTPResponse {
if (protocol.length) headers["Upgrade"] = protocol;
writeVoidBody();
m_requiresConnectionClose = true;
m_headerWritten = true;
() @trusted {
auto conn = createConnectionProxyStreamFL(m_conn, m_rawConnection);
del(conn);
Expand Down Expand Up @@ -1717,7 +1720,10 @@ final class HTTPServerResponse : HTTPResponse {
import vibe.stream.wrapper;

assert(!m_bodyWriter && !m_headerWritten, "Try to write header after body has already begun.");
m_headerWritten = true;
assert(this.httpVersion != HTTPVersion.HTTP_1_0 || this.statusCode >= 200, "Informational status codes aren't supported by HTTP/1.0.");

// Don't set m_headerWritten for 1xx status codes
if (this.statusCode >= 200) m_headerWritten = true;
auto dst = streamOutputRange!1024(m_conn);

void writeLine(T...)(string fmt, T args)
Expand Down
2 changes: 2 additions & 0 deletions http/vibe/http/status.d
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ enum HTTPStatus {
gatewayTimeout = 504,
httpVersionNotSupported = 505,
// WebDAV status codes
processing = 102, /// See: https://tools.ietf.org/html/rfc2518#section-10.1
multiStatus = 207,
unprocessableEntity = 422,
locked = 423,
Expand Down Expand Up @@ -160,6 +161,7 @@ string httpStatusText(int code)
case HTTPStatus.locked : return "Locked";
case HTTPStatus.failedDependency : return "Failed Dependency";
case HTTPStatus.insufficientStorage : return "Insufficient Storage";
case HTTPStatus.processing : return "Processing";
}
if( code >= 600 ) return "Unknown";
if( code >= 500 ) return "Unknown server error";
Expand Down
3 changes: 3 additions & 0 deletions tests/vibe.http.server.informational-status/dub.sdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name "tests"
description "informational status response handling test"
dependency "vibe-d:http" path="../../"
49 changes: 49 additions & 0 deletions tests/vibe.http.server.informational-status/source/app.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import core.time;
import vibe.core.log;
import vibe.core.core : exitEventLoop, runApplication, runTask, sleep;
import vibe.http.client;
import vibe.http.server;
import vibe.stream.operations : readAllUTF8;

void handleRequest(scope HTTPServerRequest req, scope HTTPServerResponse res)
{
res.statusCode = HTTPStatus.processing;
res.writeVoidBody();

sleep(100.msecs);
res.statusCode = HTTPStatus.ok;
res.writeBody("Hello, World!", "text/plain");
}

void main()
{
auto settings = new HTTPServerSettings;
settings.port = 8099;
settings.bindAddresses = ["::1", "127.0.0.1"];

auto l = listenHTTP(settings, &handleRequest);
scope (exit) l.stopListening();

runTask({
bool got102, got200;
scope (exit) exitEventLoop();

requestHTTP("http://127.0.0.1:8099/", null,
(scope res) {
if (res.statusCode == HTTPStatus.processing) {
assert(!got200, "Status 200 received first");
got102 = true;
}
else if (res.statusCode == HTTPStatus.ok) {
got200 = true;
assert(res.bodyReader.readAllUTF8() == "Hello, World!");
}
}
);
assert(got102, "Status 102 wasn't received");
assert(got200, "Status 200 wasn't received");
logInfo("All web tests succeeded.");
});

runApplication();
}

0 comments on commit 3e14a47

Please sign in to comment.