mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-22 11:46:13 +00:00
Send 100 Continue only when the request body is read
The server wrote 100 Continue as soon as it saw the expectation, before pre_routing_handler, pre_request_handler, or routing ran. A request those handlers rejected, or one that matched no route, still invited the client to send a body the server would never read. Defer the interim response until the body is about to be read. If the request is answered without reading the body, 100 Continue is never sent and the connection is closed, since whether and when the client sends the body is unknown. Also treat a 417 returned by expect_100_continue_handler as the final response. It used to be written as a bare status line, after which the request was processed and a second response was written.
This commit is contained in:
1 parent
2e5480ad65
commit
09c02f1335
3 files changed
+186
-11
No files matched your search
@@ -1756,6 +1756,7 @@ struct Request {
|
||||
|
||||
// private members...
|
||||
bool body_consumed_ = false;
|
||||
bool expect_100_continue_pending_ = false;
|
||||
size_t redirect_count_ = CPPHTTPLIB_REDIRECT_MAX_COUNT;
|
||||
size_t content_length_ = 0;
|
||||
ContentProvider content_provider_;
|
||||
@@ -13298,7 +13299,10 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
|
||||
// Prepare additional headers
|
||||
if (close_connection ||
|
||||
detail::has_header_token(req.headers, "Connection", "close") ||
|
||||
400 <= res.status) { // Don't leave connections open after errors
|
||||
400 <= res.status || // Don't leave connections open after errors
|
||||
// The client withholds the body until `100 Continue`, which was never
|
||||
// sent, so whether and when the body follows is unknown.
|
||||
(req.expect_100_continue_pending_ && detail::has_framed_body(req))) {
|
||||
res.set_header("Connection", "close");
|
||||
} else {
|
||||
std::string s = "timeout=";
|
||||
@@ -13549,6 +13553,13 @@ inline bool Server::read_content_core(
|
||||
}
|
||||
#endif
|
||||
|
||||
// The client is waiting for this before it sends the body.
|
||||
if (req.expect_100_continue_pending_) {
|
||||
req.expect_100_continue_pending_ = false;
|
||||
detail::write_response_line(strm, StatusCode::Continue_100);
|
||||
strm.write("\r\n");
|
||||
}
|
||||
|
||||
if (!detail::read_content(strm, req, payload_max_length_, res.status, nullptr,
|
||||
out, true)) {
|
||||
return false;
|
||||
@@ -14386,19 +14397,20 @@ Server::process_request(Stream &strm, const std::string &remote_addr,
|
||||
// case-insensitive, and a 100-continue expectation in an HTTP/1.0 request
|
||||
// must be ignored. An expectation we do not recognize is left alone; the
|
||||
// 417 the section allows for one is a MAY, not a requirement.
|
||||
//
|
||||
// `100 Continue` itself is deferred until the body is actually read (see
|
||||
// read_content_core), so a request rejected by a later handler never
|
||||
// invites the client to send a body nobody will read.
|
||||
if (req.version != "HTTP/1.0" &&
|
||||
detail::has_header_token(req.headers, "Expect", "100-continue")) {
|
||||
int status = StatusCode::Continue_100;
|
||||
if (expect_100_continue_handler_) {
|
||||
status = expect_100_continue_handler_(req, res);
|
||||
}
|
||||
switch (status) {
|
||||
case StatusCode::Continue_100:
|
||||
case StatusCode::ExpectationFailed_417:
|
||||
detail::write_response_line(strm, status);
|
||||
strm.write("\r\n");
|
||||
break;
|
||||
default:
|
||||
if (status == StatusCode::Continue_100) {
|
||||
req.expect_100_continue_pending_ = true;
|
||||
} else {
|
||||
if (res.status == -1) { res.status = status; }
|
||||
connection_closed = true;
|
||||
return write_response(strm, true, req, res);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user