Unverified Commit 8ce98f7f authored by Kenton Varda's avatar Kenton Varda Committed by GitHub

Merge pull request #671 from capnproto/incomplete-http-response

Don't log/throw exceptions if the service returned successfully witho…
parents 3fa95beb e010fee4
......@@ -2131,6 +2131,52 @@ KJ_TEST("HttpServer threw exception after starting response") {
"foo", text);
}
class PartialResponseNoThrowService final: public HttpService {
// HttpService that sends a partial response then returns without throwing.
public:
kj::Promise<void> request(
HttpMethod method, kj::StringPtr url, const HttpHeaders& headers,
kj::AsyncInputStream& requestBody, Response& response) override {
return requestBody.readAllBytes()
.then([this,&response](kj::Array<byte>&&) -> kj::Promise<void> {
HttpHeaders headers(table);
auto body = response.send(200, "OK", headers, 32);
auto promise = body->write("foo", 3);
return promise.attach(kj::mv(body));
});
}
private:
kj::Maybe<kj::Exception> exception;
HttpHeaderTable table;
};
KJ_TEST("HttpServer failed to write complete response but didn't throw") {
auto PIPELINE_TESTS = pipelineTestCases();
kj::EventLoop eventLoop;
kj::WaitScope waitScope(eventLoop);
kj::TimerImpl timer(kj::origin<kj::TimePoint>());
auto pipe = kj::newTwoWayPipe();
HttpHeaderTable table;
PartialResponseNoThrowService service;
HttpServer server(timer, table, service);
auto listenTask = server.listenHttp(kj::mv(pipe.ends[0]));
// Do one request.
pipe.ends[1]->write(PIPELINE_TESTS[0].request.raw.begin(), PIPELINE_TESTS[0].request.raw.size())
.wait(waitScope);
auto text = pipe.ends[1]->readAllText().wait(waitScope);
KJ_EXPECT(text ==
"HTTP/1.1 200 OK\r\n"
"Content-Length: 32\r\n"
"\r\n"
"foo", text);
}
class SimpleInputStream final: public kj::AsyncInputStream {
// An InputStream that returns bytes out of a static string.
......
......@@ -1614,6 +1614,10 @@ public:
return !writeInProgress && inBody;
}
bool isBroken() {
return broken;
}
void writeHeaders(String content) {
// Writes some header content and begins a new entity body.
......@@ -4175,6 +4179,15 @@ public:
"ERROR: The HttpService did not generate a response."));
}
if (httpOutput.isBroken()) {
// We started a response but didn't finish it. But HttpService returns success? Perhaps
// it decided that it doesn't want to finish this response. We'll have to disconnect
// here. If the response body is not complete (e.g. Content-Length not reached), the
// client should notice. We don't want to log an error because this condition might be
// intentional on the service's part.
return false;
}
return httpOutput.flush().then(kj::mvCapture(body,
[this](kj::Own<kj::AsyncInputStream> body) -> kj::Promise<bool> {
if (httpInput.canReuse()) {
......
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