Skip to content

Commit 18675b6

Browse files
authored
vendor : update cpp-httplib to 0.45.0 (ggml-org#23103)
1 parent 2555826 commit 18675b6

3 files changed

Lines changed: 36 additions & 35 deletions

File tree

scripts/sync_vendor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import sys
66
import subprocess
77

8-
HTTPLIB_VERSION = "refs/tags/v0.44.0"
8+
HTTPLIB_VERSION = "refs/tags/v0.45.0"
99

1010
vendor = {
1111
"https://github.com/nlohmann/json/releases/latest/download/json.hpp": "vendor/nlohmann/json.hpp",

vendor/cpp-httplib/httplib.cpp

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4723,17 +4723,24 @@ write_multipart_ranges_data(Stream &strm, const Request &req, Response &res,
47234723
});
47244724
}
47254725

4726+
bool has_framed_body(const Request &req) {
4727+
return is_chunked_transfer_encoding(req.headers) ||
4728+
req.get_header_value_u64("Content-Length") > 0;
4729+
}
4730+
4731+
bool is_connection_persistent(const Request &req) {
4732+
auto conn = req.get_header_value("Connection");
4733+
if (conn == "close") { return false; }
4734+
if (req.version == "HTTP/1.0" && conn != "Keep-Alive") { return false; }
4735+
return true;
4736+
}
4737+
47264738
bool expect_content(const Request &req) {
47274739
if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH" ||
47284740
req.method == "DELETE") {
47294741
return true;
47304742
}
4731-
if (req.has_header("Content-Length") &&
4732-
req.get_header_value_u64("Content-Length") > 0) {
4733-
return true;
4734-
}
4735-
if (is_chunked_transfer_encoding(req.headers)) { return true; }
4736-
return false;
4743+
return has_framed_body(req);
47374744
}
47384745

47394746
#ifdef _WIN32
@@ -7449,29 +7456,18 @@ bool Server::read_content_core(
74497456
size_t /*len*/) { return receiver(buf, n); };
74507457
}
74517458

7452-
// RFC 7230 Section 3.3.3: If this is a request message and none of the above
7453-
// are true (no Transfer-Encoding and no Content-Length), then the message
7454-
// body length is zero (no message body is present).
7455-
//
7456-
// For non-SSL builds, detect clients that send a body without a
7457-
// Content-Length header (raw HTTP over TCP). Check both the stream's
7458-
// internal read buffer (data already read from the socket during header
7459-
// parsing) and the socket itself for pending data. If data is found and
7460-
// exceeds the configured payload limit, reject with 413.
7461-
// For SSL builds we cannot reliably peek the decrypted application bytes,
7462-
// so keep the original behaviour.
7459+
// RFC 9112 §6: no Transfer-Encoding and no Content-Length means no body.
7460+
// For non-SSL builds we still scan non-persistent connections for stray
7461+
// body bytes so the payload limit is enforced (413). On keep-alive,
7462+
// pending bytes may be the next request (issue #2450), so skip.
74637463
#if !defined(CPPHTTPLIB_SSL_ENABLED)
74647464
if (!req.has_header("Content-Length") &&
74657465
!detail::is_chunked_transfer_encoding(req.headers)) {
7466-
// Only check if payload_max_length is set to a finite value
7467-
if (payload_max_length_ > 0 &&
7466+
if (!detail::is_connection_persistent(req) && payload_max_length_ > 0 &&
74687467
payload_max_length_ < (std::numeric_limits<size_t>::max)()) {
7469-
// Check if there is data already buffered in the stream (read during
7470-
// header parsing) or pending on the socket. Use a non-blocking socket
7471-
// check to avoid deadlock when the client sends no body.
7472-
bool has_data = strm.is_readable();
7468+
auto has_data = strm.is_readable();
74737469
if (!has_data) {
7474-
socket_t s = strm.socket();
7470+
auto s = strm.socket();
74757471
if (s != INVALID_SOCKET) {
74767472
has_data = detail::select_read(s, 0, 0) > 0;
74777473
}
@@ -8033,6 +8029,11 @@ get_client_ip(const std::string &x_forwarded_for,
80338029
ip_list.emplace_back(std::string(b + r.first, b + r.second));
80348030
});
80358031

8032+
// A malformed X-Forwarded-For (empty, comma-only, whitespace-only) yields
8033+
// no segments. Signal "no client IP derived" with an empty string so the
8034+
// caller can fall back to the connection-level remote address.
8035+
if (ip_list.empty()) { return std::string(); }
8036+
80368037
for (size_t i = 0; i < ip_list.size(); ++i) {
80378038
auto ip = ip_list[i];
80388039

@@ -8123,7 +8124,8 @@ Server::process_request(Stream &strm, const std::string &remote_addr,
81238124

81248125
if (!trusted_proxies_.empty() && req.has_header("X-Forwarded-For")) {
81258126
auto x_forwarded_for = req.get_header_value("X-Forwarded-For");
8126-
req.remote_addr = get_client_ip(x_forwarded_for, trusted_proxies_);
8127+
auto derived = get_client_ip(x_forwarded_for, trusted_proxies_);
8128+
req.remote_addr = derived.empty() ? remote_addr : derived;
81278129
} else {
81288130
req.remote_addr = remote_addr;
81298131
}
@@ -8325,15 +8327,14 @@ Server::process_request(Stream &strm, const std::string &remote_addr,
83258327
ret = write_response(strm, close_connection, req, res);
83268328
}
83278329

8328-
// Drain any unconsumed request body to prevent request smuggling on
8329-
// keep-alive connections.
8330-
if (!req.body_consumed_ && detail::expect_content(req)) {
8331-
int drain_status = 200; // required by read_content signature
8330+
// Drain any unconsumed framed body to prevent request smuggling on
8331+
// keep-alive. Without framing there is no body to drain — reading would
8332+
// consume the next request (issue #2450).
8333+
if (!req.body_consumed_ && detail::has_framed_body(req)) {
8334+
int dummy_status;
83328335
if (!detail::read_content(
8333-
strm, req, payload_max_length_, drain_status, nullptr,
8336+
strm, req, payload_max_length_, dummy_status, nullptr,
83348337
[](const char *, size_t, size_t, size_t) { return true; }, false)) {
8335-
// Body exceeds payload limit or read error — close the connection
8336-
// to prevent leftover bytes from being misinterpreted.
83378338
connection_closed = true;
83388339
}
83398340
}

vendor/cpp-httplib/httplib.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
#ifndef CPPHTTPLIB_HTTPLIB_H
99
#define CPPHTTPLIB_HTTPLIB_H
1010

11-
#define CPPHTTPLIB_VERSION "0.44.0"
12-
#define CPPHTTPLIB_VERSION_NUM "0x002c00"
11+
#define CPPHTTPLIB_VERSION "0.45.0"
12+
#define CPPHTTPLIB_VERSION_NUM "0x002d00"
1313

1414
#ifdef _WIN32
1515
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0A00

0 commit comments

Comments
 (0)