Unverified Commit 3079784b authored by Kenton Varda's avatar Kenton Varda Committed by GitHub

Merge pull request #638 from capnproto/ignore-client-body

Extend HttpServer to inform the caller when a connection ends cleanly on drain().
parents 35bead7b 098004cd
......@@ -80,7 +80,7 @@ public:
uint64_t n = kj::min(limit - doneSoFar, sizeof(buffer));
if (n == 0) return doneSoFar;
return input.tryRead(buffer, 1, sizeof(buffer))
return input.tryRead(buffer, 1, n)
.then([this](size_t amount) -> Promise<uint64_t> {
if (amount == 0) return doneSoFar; // EOF
doneSoFar += amount;
......
......@@ -1704,10 +1704,6 @@ public:
} else if (url == "/ws-inline") {
auto ws = response.acceptWebSocket(responseHeaders);
return doWebSocket(*ws, "start-inline").attach(kj::mv(ws));
} else if (url == "/ws-detached") {
auto ws = response.acceptWebSocket(responseHeaders);
tasks.add(doWebSocket(*ws, "start-detached").attach(kj::mv(ws)));
return kj::READY_NOW;
} else {
KJ_FAIL_ASSERT("unexpected path", url);
}
......@@ -1767,8 +1763,6 @@ const char WEBSOCKET_RESPONSE_HANDSHAKE_ERROR[] =
"\r\n";
const byte WEBSOCKET_FIRST_MESSAGE_INLINE[] =
{ 0x81, 0x0c, 's','t','a','r','t','-','i','n','l','i','n','e' };
const byte WEBSOCKET_FIRST_MESSAGE_DETACHED[] =
{ 0x81, 0x0e, 's','t','a','r','t','-','d','e','t','a','c','h','e','d' };
const byte WEBSOCKET_SEND_MESSAGE[] =
{ 0x81, 0x83, 12, 34, 56, 78, 'b'^12, 'a'^34, 'r'^56 };
const byte WEBSOCKET_REPLY_MESSAGE[] =
......@@ -1909,31 +1903,6 @@ KJ_TEST("HttpServer WebSocket handshake") {
listenTask.wait(io.waitScope);
}
KJ_TEST("HttpServer WebSocket handshake detached") {
auto io = kj::setupAsyncIo();
auto pipe = io.provider->newTwoWayPipe();
HttpHeaderTable::Builder tableBuilder;
HttpHeaderId hMyHeader = tableBuilder.add("My-Header");
auto headerTable = tableBuilder.build();
TestWebSocketService service(*headerTable, hMyHeader);
HttpServer server(io.provider->getTimer(), *headerTable, service);
auto listenTask = server.listenHttp(kj::mv(pipe.ends[0]));
auto request = kj::str("GET /ws-detached", WEBSOCKET_REQUEST_HANDSHAKE);
pipe.ends[1]->write({request.asBytes()}).wait(io.waitScope);
expectRead(*pipe.ends[1], WEBSOCKET_RESPONSE_HANDSHAKE).wait(io.waitScope);
listenTask.wait(io.waitScope);
expectRead(*pipe.ends[1], WEBSOCKET_FIRST_MESSAGE_DETACHED).wait(io.waitScope);
pipe.ends[1]->write({WEBSOCKET_SEND_MESSAGE}).wait(io.waitScope);
expectRead(*pipe.ends[1], WEBSOCKET_REPLY_MESSAGE).wait(io.waitScope);
pipe.ends[1]->write({WEBSOCKET_SEND_CLOSE}).wait(io.waitScope);
expectRead(*pipe.ends[1], WEBSOCKET_REPLY_CLOSE).wait(io.waitScope);
}
KJ_TEST("HttpServer WebSocket handshake error") {
auto io = kj::setupAsyncIo();
auto pipe = io.provider->newTwoWayPipe();
......
This diff is collapsed.
......@@ -640,6 +640,14 @@ struct HttpServerSettings {
kj::Duration pipelineTimeout = 5 * kj::SECONDS;
// After one request/response completes, we'll wait up to this long for a pipelined request to
// arrive.
kj::Duration canceledUploadGacePeriod = 1 * kj::SECONDS;
size_t canceledUploadGraceBytes = 65536;
// If the HttpService sends a response and returns without having read the entire request body,
// then we have to decide whether to close the connection or wait for the client to finish the
// request so that it can pipeline the next one. We'll give them a grace period defined by the
// above two values -- if they hit either one, we'll close the socket, but if the request
// completes, we'll let the connection stay open to handle more requests.
};
class HttpServer: private kj::TaskSet::ErrorHandler {
......@@ -680,6 +688,14 @@ public:
// The promise throws if an unparseable request is received or if some I/O error occurs. Dropping
// the returned promise will cancel all I/O on the connection and cancel any in-flight requests.
kj::Promise<bool> listenHttpCleanDrain(kj::AsyncIoStream& connection);
// Like listenHttp(), but allows you to potentially drain the server without closing connections.
// The returned promise resolves to `true` if the connection has been left in a state where a
// new HttpServer could potentially accept further requests from it. If `false`, then the
// connection is either in an inconsistent state or already completed a closing handshake; the
// caller should close it without any further reads/writes. Note this only ever returns `true`
// if you called `drain()` -- otherwise this server would keep handling the connection.
private:
class Connection;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment