From ecfd84c1712b1bfe92107e37843f97ecec537da9 Mon Sep 17 00:00:00 2001 From: yhirose Date: Wed, 9 Jul 2025 23:57:47 -0400 Subject: [PATCH 1/4] Release v0.23.0 --- httplib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httplib.h b/httplib.h index 07310e41eb..512f83c4a8 100644 --- a/httplib.h +++ b/httplib.h @@ -8,7 +8,7 @@ #ifndef CPPHTTPLIB_HTTPLIB_H #define CPPHTTPLIB_HTTPLIB_H -#define CPPHTTPLIB_VERSION "0.22.0" +#define CPPHTTPLIB_VERSION "0.23.0" /* * Platform compatibility check From 53ea9e8bb4750294ef820a213c4b2758b68117f2 Mon Sep 17 00:00:00 2001 From: yhirose Date: Thu, 10 Jul 2025 00:47:45 -0400 Subject: [PATCH 2/4] Fix #2111 (#2179) --- httplib.h | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/httplib.h b/httplib.h index 512f83c4a8..830c81e42a 100644 --- a/httplib.h +++ b/httplib.h @@ -3215,6 +3215,23 @@ inline int poll_wrapper(struct pollfd *fds, nfds_t nfds, int timeout) { template inline ssize_t select_impl(socket_t sock, time_t sec, time_t usec) { +#ifdef __APPLE__ + if (sock >= FD_SETSIZE) { return -1; } + + fd_set fds, *rfds, *wfds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + rfds = (Read ? &fds : nullptr); + wfds = (Read ? nullptr : &fds); + + timeval tv; + tv.tv_sec = static_cast(sec); + tv.tv_usec = static_cast(usec); + + return handle_EINTR([&]() { + return select(static_cast(sock + 1), rfds, wfds, nullptr, &tv); + }); +#else struct pollfd pfd; pfd.fd = sock; pfd.events = (Read ? POLLIN : POLLOUT); @@ -3222,6 +3239,7 @@ inline ssize_t select_impl(socket_t sock, time_t sec, time_t usec) { auto timeout = static_cast(sec * 1000 + usec / 1000); return handle_EINTR([&]() { return poll_wrapper(&pfd, 1, timeout); }); +#endif } inline ssize_t select_read(socket_t sock, time_t sec, time_t usec) { @@ -3234,6 +3252,36 @@ inline ssize_t select_write(socket_t sock, time_t sec, time_t usec) { inline Error wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) { +#ifdef __APPLE__ + if (sock >= FD_SETSIZE) { return Error::Connection; } + + fd_set fdsr, fdsw; + FD_ZERO(&fdsr); + FD_ZERO(&fdsw); + FD_SET(sock, &fdsr); + FD_SET(sock, &fdsw); + + timeval tv; + tv.tv_sec = static_cast(sec); + tv.tv_usec = static_cast(usec); + + auto ret = handle_EINTR([&]() { + return select(static_cast(sock + 1), &fdsr, &fdsw, nullptr, &tv); + }); + + if (ret == 0) { return Error::ConnectionTimeout; } + + if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) { + auto error = 0; + socklen_t len = sizeof(error); + auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR, + reinterpret_cast(&error), &len); + auto successful = res >= 0 && !error; + return successful ? Error::Success : Error::Connection; + } + + return Error::Connection; +#else struct pollfd pfd_read; pfd_read.fd = sock; pfd_read.events = POLLIN | POLLOUT; @@ -3255,6 +3303,7 @@ inline Error wait_until_socket_is_ready(socket_t sock, time_t sec, } return Error::Connection; +#endif } inline bool is_socket_alive(socket_t sock) { @@ -8001,6 +8050,16 @@ Server::process_request(Stream &strm, const std::string &remote_addr, res.version = "HTTP/1.1"; res.headers = default_headers_; +#ifdef __APPLE__ + // Socket file descriptor exceeded FD_SETSIZE... + if (strm.socket() >= FD_SETSIZE) { + Headers dummy; + detail::read_headers(strm, dummy); + res.status = StatusCode::InternalServerError_500; + return write_response(strm, close_connection, req, res); + } +#endif + // Request line and headers if (!parse_request_line(line_reader.ptr(), req) || !detail::read_headers(strm, req.headers)) { From 55b38907dcdf3d21d16e0dc21d5ac8336fcb21b7 Mon Sep 17 00:00:00 2001 From: yhirose Date: Thu, 10 Jul 2025 00:58:34 -0400 Subject: [PATCH 3/4] Resolve #1264 --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 66348cc52b..c079488c7f 100644 --- a/README.md +++ b/README.md @@ -1141,6 +1141,24 @@ Serving HTTP on 0.0.0.0 port 80 ... NOTE ---- +### Regular Expression Stack Overflow + +> [!CAUTION] +> When using complex regex patterns in route handlers, be aware that certain patterns may cause stack overflow during pattern matching. This is a known issue with `std::regex` implementations and affects the `dispatch_request()` method. +> +> ```cpp +> // This pattern can cause stack overflow with large input +> svr.Get(".*", handler); +> ``` +> +> Consider using simpler patterns or path parameters to avoid this issue: +> +> ```cpp +> // Safer alternatives +> svr.Get("/users/:id", handler); // Path parameters +> svr.Get(R"(/api/v\d+/.*)", handler); // More specific patterns +> ``` + ### g++ g++ 4.8 and below cannot build this library since `` in the versions are [broken](https://stackoverflow.com/questions/12530406/is-gcc-4-8-or-earlier-buggy-about-regular-expressions). From 8b28577ec6c389988ecebdd4dc1fd66c0a47b8bd Mon Sep 17 00:00:00 2001 From: yhirose Date: Thu, 10 Jul 2025 01:07:44 -0400 Subject: [PATCH 4/4] Resolve #366 --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index c079488c7f..75330a7477 100644 --- a/README.md +++ b/README.md @@ -990,6 +990,25 @@ auto res = cli.Get("/already%20encoded/path"); // Use pre-encoded paths - `true` (default): Automatically encodes spaces, plus signs, newlines, and other special characters - `false`: Sends paths as-is without encoding (useful for pre-encoded URLs) +### Performance Note for Local Connections + +> [!WARNING] +> On Windows systems with improperly configured IPv6 settings, using "localhost" as the hostname may cause significant connection delays (up to 2 seconds per request) due to DNS resolution issues. This affects both client and server operations. For better performance when connecting to local services, use "127.0.0.1" instead of "localhost". +> +> See: https://github.com/yhirose/cpp-httplib/issues/366#issuecomment-593004264 + +```cpp +// May be slower on Windows due to DNS resolution delays +httplib::Client cli("localhost", 8080); +httplib::Server svr; +svr.listen("localhost", 8080); + +// Faster alternative for local connections +httplib::Client cli("127.0.0.1", 8080); +httplib::Server svr; +svr.listen("127.0.0.1", 8080); +``` + Compression -----------