From 09fe1cbb11e5f40d865cbb173e046b2220c9dd79 Mon Sep 17 00:00:00 2001 From: --global Date: Thu, 16 Jul 2026 16:36:31 +0300 Subject: [PATCH 1/2] fix: tighten HTTP/1.1 request handling in the server Require Host, fail closed on bad or incomplete bodies, echo Connection, and answer errors with HTTP/1.1 instead of HTTP/1.0. Co-authored-by: Cursor --- net/net-http_server.c++m | 136 ++++++++++++++++++--------- net/net-http_server.test.c++ | 175 +++++++++++++++++++++++++++++++++++ 2 files changed, 265 insertions(+), 46 deletions(-) diff --git a/net/net-http_server.c++m b/net/net-http_server.c++m index 7b8cb22..2adb7b2 100644 --- a/net/net-http_server.c++m +++ b/net/net-http_server.c++m @@ -407,15 +407,47 @@ private: << std::pair{"request_id", request_id} << std::pair{"duration_ms", request_duration} << net::flush; - stream << "HTTP/1.0 " << status_bad_request << net::crlf + stream << "HTTP/1.1 " << status_bad_request << net::crlf << "Date: " << date() << net::crlf << "Server: " << host() << net::crlf << "Content-Type: " << m_content_type << net::crlf << "Content-Length: 0" << net::crlf + << "Connection: close" << net::crlf << net::crlf << net::flush; break; } + // HTTP/1.1 requires Host + if(!hs.contains("host") || hs["host"].empty()) + { + const auto request_duration = duration_cast(system_clock::now() - request_start).count(); + net::slog << net::warning("HTTP_MISSING_HOST") << "missing Host header from " << endpoint << ":" << port + << std::pair{"ip"sv, endpoint} + << std::pair{"port", port} + << std::pair{"method", method} + << std::pair{"uri", std::string{uri}} + << std::pair{"status", status_bad_request} + << std::pair{"request_id", request_id} + << std::pair{"duration_ms", request_duration} + << net::flush; + stream << "HTTP/1.1 " << status_bad_request << net::crlf + << "Date: " << date() << net::crlf + << "Server: " << host() << net::crlf + << "Content-Type: " << m_content_type << net::crlf + << "Content-Length: 0" << net::crlf + << "Connection: close" << net::crlf + << net::crlf << net::flush; + break; + } + + auto close_connection = false; + if(hs.contains("connection")) + { + auto connection = hs["connection"]; + utils::ascii_to_lower(connection); + close_connection = connection.contains("close"sv); + } + // Extract additional headers for logging auto user_agent = ""s; if(hs.contains("user-agent")) @@ -443,51 +475,42 @@ private: } long long content_length = 0; + auto content_length_ok = true; if(hs.contains("content-length")) { try { content_length = utils::stoll(hs["content-length"]); if(content_length < 0) - { - net::slog << net::warning("HTTP_INVALID_CONTENT_LENGTH") << "negative content-length from " << endpoint << ":" << port - << std::pair{"ip"sv, endpoint} - << std::pair{"port", port} - << std::pair{"content_length", content_length} - << net::flush; - content_length = 0; - } - } - catch(const std::invalid_argument&) - { - net::slog << net::warning("HTTP_INVALID_CONTENT_LENGTH") << "invalid content-length format \"" << hs["content-length"] << "\" from " << endpoint << ":" << port - << std::pair{"ip"sv, endpoint} - << std::pair{"port", port} - << std::pair{"content_length_str", hs["content-length"]} - << net::flush; - content_length = 0; + content_length_ok = false; } - catch(const std::out_of_range&) + catch(const std::exception&) { - net::slog << net::warning("HTTP_INVALID_CONTENT_LENGTH") << "content-length out of range \"" << hs["content-length"] << "\" from " << endpoint << ":" << port - << std::pair{"ip"sv, endpoint} - << std::pair{"port", port} - << std::pair{"content_length_str", hs["content-length"]} - << net::flush; - content_length = 0; - } - catch(const std::exception& e) - { - net::slog << net::warning("HTTP_INVALID_CONTENT_LENGTH") << "error parsing content-length \"" << hs["content-length"] << "\" from " << endpoint << ":" << port << ": " << e.what() - << std::pair{"ip"sv, endpoint} - << std::pair{"port", port} - << std::pair{"content_length_str", hs["content-length"]} - << net::flush; - content_length = 0; + content_length_ok = false; } } + if(!content_length_ok) + { + net::slog << net::warning("HTTP_INVALID_CONTENT_LENGTH") << "invalid content-length from " << endpoint << ":" << port + << std::pair{"ip"sv, endpoint} + << std::pair{"port", port} + << std::pair{"content_length_str", hs["content-length"]} + << std::pair{"status", status_bad_request} + << std::pair{"request_id", request_id} + << net::flush; + stream << "HTTP/1.1 " << status_bad_request << net::crlf + << "Date: " << date() << net::crlf + << "Server: " << host() << net::crlf + << "Content-Type: " << m_content_type << net::crlf + << "Content-Length: 0" << net::crlf + << "Connection: close" << net::crlf + << net::crlf << net::flush; + break; + } + std::string body(static_cast(content_length), ' '); + auto body_complete = true; try { for(auto& c : body) @@ -495,11 +518,7 @@ private: auto ch = stream.get(); if(stream.eof() || stream.fail()) { - net::slog << net::warning("HTTP_INCOMPLETE_BODY") << "incomplete body read from " << endpoint << ":" << port << " (expected " << content_length << " bytes)" - << std::pair{"ip"sv, endpoint} - << std::pair{"port", port} - << std::pair{"expected_bytes", static_cast(content_length)} - << net::flush; + body_complete = false; break; } c = static_cast(ch); @@ -507,12 +526,32 @@ private: } catch(const std::exception& e) { + body_complete = false; net::slog << net::error("HTTP_BODY_READ_ERROR") << "error reading body from " << endpoint << ":" << port << ": " << e.what() << std::pair{"ip"sv, endpoint} << std::pair{"port", port} << net::flush; } + if(!body_complete) + { + net::slog << net::warning("HTTP_INCOMPLETE_BODY") << "incomplete body read from " << endpoint << ":" << port << " (expected " << content_length << " bytes)" + << std::pair{"ip"sv, endpoint} + << std::pair{"port", port} + << std::pair{"expected_bytes", static_cast(content_length)} + << std::pair{"status", status_bad_request} + << std::pair{"request_id", request_id} + << net::flush; + stream << "HTTP/1.1 " << status_bad_request << net::crlf + << "Date: " << date() << net::crlf + << "Server: " << host() << net::crlf + << "Content-Type: " << m_content_type << net::crlf + << "Content-Length: 0" << net::crlf + << "Connection: close" << net::crlf + << net::crlf << net::flush; + break; + } + net::slog << net::debug("HTTP_REQUEST_BODY") << "request body \"" << body << "\"" << std::pair{"ip"sv, endpoint} << std::pair{"port", port} @@ -680,11 +719,12 @@ private: << "Date: " << date() << net::crlf << "Server: " << host() << net::crlf << "Content-Type: " << res_type << net::crlf - << "Content-Length: " << res_content.length() << net::crlf; - + << "Content-Length: " << res_content.length() << net::crlf + << "Connection: " << (close_connection ? "close"sv : "keep-alive"sv) << net::crlf; + if(custom_headers.has_value()) stream << custom_headers.value(); - + stream << "Cache-Control: private" << net::crlf << net::crlf << (method != "HEAD" ? res_content : "") << net::flush; @@ -703,15 +743,19 @@ private: << std::pair{"request_id", request_id} << std::pair{"duration_ms", request_duration} << net::flush; - stream << "HTTP/1.0 " << status_not_found << net::crlf + stream << "HTTP/1.1 " << status_not_found << net::crlf << "Date: " << date() << net::crlf << "Server: " << host() << net::crlf << "Content-Type: " << m_content_type << net::crlf << "Content-Length: 0" << net::crlf + << "Connection: " << (close_connection ? "close"sv : "keep-alive"sv) << net::crlf << "Cache-Control: private" << net::crlf << net::crlf << net::flush; } } + + if(close_connection) + break; } const auto conn_duration = duration_cast(system_clock::now() - conn_start).count(); net::slog << net::info("HTTP_CONN_CLOSED") << "connection closed" @@ -730,7 +774,7 @@ private: << net::flush; try { - stream << "HTTP/1.0 " << status_internal_server_error << net::crlf + stream << "HTTP/1.1 " << status_internal_server_error << net::crlf << "Date: " << date() << net::crlf << "Server: " << host() << net::crlf << "Content-Type: " << m_content_type << net::crlf @@ -754,7 +798,7 @@ private: << net::flush; try { - stream << "HTTP/1.0 " << status_internal_server_error << net::crlf + stream << "HTTP/1.1 " << status_internal_server_error << net::crlf << "Date: " << date() << net::crlf << "Server: " << host() << net::crlf << "Content-Type: " << m_content_type << net::crlf @@ -778,7 +822,7 @@ private: << net::flush; try { - stream << "HTTP/1.0 " << status_internal_server_error << net::crlf + stream << "HTTP/1.1 " << status_internal_server_error << net::crlf << "Date: " << date() << net::crlf << "Server: " << host() << net::crlf << "Content-Type: " << m_content_type << net::crlf diff --git a/net/net-http_server.test.c++ b/net/net-http_server.test.c++ index bb1b769..051b9ec 100644 --- a/net/net-http_server.test.c++ +++ b/net/net-http_server.test.c++ @@ -784,6 +784,181 @@ auto register_server_tests() }; }; + tester::bdd::scenario("400 Bad Request when Host header is missing, [net]") = [] { + if(!network_tests_enabled()) return; + + tester::bdd::given("An HTTP server with a route registered") = [] { + auto server = std::make_shared(); + server->get("/test").text("OK"); + server->timeout(std::chrono::seconds{1}); + + tester::bdd::when("A GET request is made without a Host header") = [server] { + auto response_status = std::make_shared(""); + + std::promise started; + auto started_future = started.get_future(); + + std::thread server_thread{[server, &started]{ + try { + started.set_value(); + server->listen("8089"); + } catch(...) {} + }}; + + using namespace std::chrono_literals; + if (started_future.wait_for(2s) == std::future_status::ready) { + std::this_thread::sleep_for(200ms); + + try { + auto stream = connect("127.0.0.1", "8089"); + stream << "GET /test HTTP/1.1" << net::crlf + << "Connection: close" << net::crlf + << net::crlf + << net::flush; + + std::string line; + if(stream && std::getline(stream, line)) { + if(!line.empty() && line.back() == '\r') + line.pop_back(); + auto space1 = line.find(' '); + if(space1 != std::string::npos) { + auto space2 = line.find(' ', space1 + 1); + *response_status = space2 != std::string::npos + ? line.substr(space1 + 1, space2 - space1 - 1) + : line.substr(space1 + 1); + } + } + } catch(...) {} + + std::this_thread::sleep_for(200ms); + server->stop(); + } + + if (server_thread.joinable()) server_thread.join(); + + tester::bdd::then("Response status is 400 Bad Request") = [response_status] { + check_eq(*response_status, "400"); + }; + }; + }; + }; + + tester::bdd::scenario("400 Bad Request when Content-Length is invalid, [net]") = [] { + if(!network_tests_enabled()) return; + + tester::bdd::given("An HTTP server with a route registered") = [] { + auto server = std::make_shared(); + server->post("/test").text("OK"); + server->timeout(std::chrono::seconds{1}); + + tester::bdd::when("A POST request has a non-numeric Content-Length") = [server] { + auto response_status = std::make_shared(""); + + std::promise started; + auto started_future = started.get_future(); + + std::thread server_thread{[server, &started]{ + try { + started.set_value(); + server->listen("8090"); + } catch(...) {} + }}; + + using namespace std::chrono_literals; + if (started_future.wait_for(2s) == std::future_status::ready) { + std::this_thread::sleep_for(200ms); + + try { + auto stream = connect("127.0.0.1", "8090"); + stream << "POST /test HTTP/1.1" << net::crlf + << "Host: 127.0.0.1:8090" << net::crlf + << "Content-Length: not-a-number" << net::crlf + << "Connection: close" << net::crlf + << net::crlf + << net::flush; + + std::string line; + if(stream && std::getline(stream, line)) { + if(!line.empty() && line.back() == '\r') + line.pop_back(); + auto space1 = line.find(' '); + if(space1 != std::string::npos) { + auto space2 = line.find(' ', space1 + 1); + *response_status = space2 != std::string::npos + ? line.substr(space1 + 1, space2 - space1 - 1) + : line.substr(space1 + 1); + } + } + } catch(...) {} + + std::this_thread::sleep_for(200ms); + server->stop(); + } + + if (server_thread.joinable()) server_thread.join(); + + tester::bdd::then("Response status is 400 Bad Request") = [response_status] { + check_eq(*response_status, "400"); + }; + }; + }; + }; + + tester::bdd::scenario("Connection header is echoed on successful responses, [net]") = [] { + if(!network_tests_enabled()) return; + + tester::bdd::given("An HTTP server with a route registered") = [] { + auto server = std::make_shared(); + server->get("/test").text("OK"); + server->timeout(std::chrono::seconds{1}); + + tester::bdd::when("A GET request asks to close the connection") = [server] { + auto response_headers = std::make_shared(""); + + std::promise started; + auto started_future = started.get_future(); + + std::thread server_thread{[server, &started]{ + try { + started.set_value(); + server->listen("8091"); + } catch(...) {} + }}; + + using namespace std::chrono_literals; + if (started_future.wait_for(2s) == std::future_status::ready) { + std::this_thread::sleep_for(200ms); + + try { + auto stream = connect("127.0.0.1", "8091"); + stream << "GET /test HTTP/1.1" << net::crlf + << "Host: 127.0.0.1:8091" << net::crlf + << "Connection: close" << net::crlf + << net::crlf + << net::flush; + + std::string line; + int line_count = 0; + while(line_count < 20 && stream && std::getline(stream, line)) { + *response_headers += line + "\n"; + line_count++; + if(line.empty() || line == "\r") break; + } + } catch(...) {} + + std::this_thread::sleep_for(200ms); + server->stop(); + } + + if (server_thread.joinable()) server_thread.join(); + + tester::bdd::then("Response includes Connection: close") = [response_headers] { + check_contains(*response_headers, "Connection: close"); + }; + }; + }; + }; + return true; } From bed4108818b492583fb0d21e78a2999cdb95bb9c Mon Sep 17 00:00:00 2001 From: --global Date: Thu, 16 Jul 2026 16:42:21 +0300 Subject: [PATCH 2/2] style: prefer and/or/not alternative tokens Use C++ alternative tokens for boolean operators across net sources and tests; leave != and move references unchanged. Co-authored-by: Cursor --- net/net-acceptor.c++m | 6 +- net/net-acceptor.test.c++ | 12 ++-- net/net-acceptor_connector.test.c++ | 2 +- net/net-address_info.c++m | 6 +- net/net-connector.c++m | 2 +- net/net-connector.test.c++ | 4 +- net/net-endpoint_buf.c++m | 8 +-- net/net-endpoint_buf.test.c++ | 14 ++--- net/net-endpoint_stream.c++m | 4 +- net/net-endpoint_stream.test.c++ | 2 +- net/net-gsl.c++m | 2 +- net/net-http_base64.c++m | 6 +- net/net-http_escape.c++m | 2 +- net/net-http_headers.c++m | 8 +-- net/net-http_server.c++m | 30 ++++----- net/net-http_server.test.c++ | 80 ++++++++++++------------ net/net-http_server_middlewares.c++m | 38 +++++------ net/net-http_server_middlewares.test.c++ | 2 +- net/net-posix.c++m | 2 +- net/net-posix.test.c++ | 4 +- net/net-readme_examples.test.c++ | 4 +- net/net-receiver.c++m | 2 +- net/net-receiver.test.c++ | 4 +- net/net-receiver_sender.test.c++ | 8 +-- net/net-sender.c++m | 2 +- net/net-sender.test.c++ | 6 +- net/net-socket.test.c++ | 14 ++--- net/net-structured_log_stream.c++m | 72 ++++++++++----------- net/net-structured_log_stream.test.c++ | 10 +-- net/net-uri.c++m | 10 +-- net/net-utils.c++m | 18 +++--- net/net-uuid.test.c++ | 14 ++--- 32 files changed, 199 insertions(+), 199 deletions(-) diff --git a/net/net-acceptor.c++m b/net/net-acceptor.c++m index db25b9b..e31c4b5 100644 --- a/net/net-acceptor.c++m +++ b/net/net-acceptor.c++m @@ -25,7 +25,7 @@ public: for(const auto& address : local_address) { socket s{address.ai_family, address.ai_socktype, address.ai_protocol}; - if(!s) continue; + if(not s) continue; auto yes = 1; if(posix::setsockopt(s, posix::sol_socket, posix::so_reuseaddr, &yes, sizeof yes) < 0) continue; if(posix::bind(s, address.ai_addr, address.ai_addrlen) < 0) continue; @@ -44,7 +44,7 @@ public: auto sas = posix::sockaddr_storage{}; auto saslen = posix::socklen_t{sizeof sas}; socket s = posix::accept(fd, reinterpret_cast(&sas), &saslen); - if(!s) throw std::system_error{posix::get_errno(), std::system_category(),"accept failed"}; + if(not s) throw std::system_error{posix::get_errno(), std::system_category(),"accept failed"}; char hbuf[posix::ni_maxhost]; char sbuf[posix::ni_maxserv]; @@ -88,7 +88,7 @@ private: static_cast(m_timeout.count() / 1000), static_cast(m_timeout.count() % 1000 * 1000) }; - if(!posix::select(max_fd+1, &fds, nullptr, nullptr, &tv)) + if(not posix::select(max_fd+1, &fds, nullptr, nullptr, &tv)) throw std::system_error{posix::get_errno(), std::system_category(), "accept timeouted"}; } else diff --git a/net/net-acceptor.test.c++ b/net/net-acceptor.test.c++ index 5498467..bce3479 100644 --- a/net/net-acceptor.test.c++ +++ b/net/net-acceptor.test.c++ @@ -20,7 +20,7 @@ inline bool network_tests_enabled() auto register_acceptor_tests() { - if(!network_tests_enabled()) return false; + if(not network_tests_enabled()) return false; tester::bdd::scenario("Basic construction, [net]") = [] { tester::bdd::given("An acceptor for localhost:54321") = [] { @@ -72,25 +72,25 @@ auto register_acceptor_tests() }}; auto start = std::chrono::steady_clock::now(); - while (!accepted && (std::chrono::steady_clock::now() - start) < 5s) { + while (not accepted and (std::chrono::steady_clock::now() - start) < 5s) { std::this_thread::sleep_for(100ms); } - if (!accepted) { + if (not accepted) { failed("Accept test timed out"); } t1.join(); t2.join(); - check_true(!accept_threw); - check_true(!connect_threw); + check_true(not accept_threw); + check_true(not connect_threw); check_true(connect_ok); check_true(stream_ok); { auto lock = std::lock_guard{host_mutex}; // host might be ::1 on some systems or 127.0.0.1 - check_true(host_value == "localhost" || host_value == "::1" || host_value == "127.0.0.1"); + check_true(host_value == "localhost" or host_value == "::1" or host_value == "127.0.0.1"); } }; }; diff --git a/net/net-acceptor_connector.test.c++ b/net/net-acceptor_connector.test.c++ index 6e1733d..1babca4 100644 --- a/net/net-acceptor_connector.test.c++ +++ b/net/net-acceptor_connector.test.c++ @@ -19,7 +19,7 @@ inline bool network_tests_enabled() auto register_acceptor_connector_tests() { - if(!network_tests_enabled()) return false; + if(not network_tests_enabled()) return false; std::array data; for (int i = 0; i < 100; ++i) data[i] = i + 1; diff --git a/net/net-address_info.c++m b/net/net-address_info.c++m index ab0695b..66651a3 100644 --- a/net/net-address_info.c++m +++ b/net/net-address_info.c++m @@ -37,14 +37,14 @@ public: hints.ai_family = family; hints.ai_socktype = socktype; - const auto is_any = node.empty() || node == "0.0.0.0" || node == "::"; + const auto is_any = node.empty() or node == "0.0.0.0" or node == "::"; const auto node_str = std::string{node}; const auto service_str = std::string{service_or_port}; - if (!service_str.empty() && std::isdigit(static_cast(service_str[0]))) { + if (not service_str.empty() and std::isdigit(static_cast(service_str[0]))) { hints.ai_flags |= posix::ai_numericserv; } - if (!is_any && !node_str.empty() && std::isdigit(static_cast(node_str[0]))) { + if (not is_any and not node_str.empty() and std::isdigit(static_cast(node_str[0]))) { hints.ai_flags |= posix::ai_numericnode; } diff --git a/net/net-connector.c++m b/net/net-connector.c++m index db1e8c5..cf0efb9 100644 --- a/net/net-connector.c++m +++ b/net/net-connector.c++m @@ -57,7 +57,7 @@ endpointstream connect(std::string_view host, for(const auto& address : remote_address) { socket s{address.ai_family, address.ai_socktype, address.ai_protocol}; - if(!s) continue; + if(not s) continue; if (posix::so_nosigpipe > 0) { // macOS: prevent SIGPIPE on broken pipe writes. diff --git a/net/net-connector.test.c++ b/net/net-connector.test.c++ index 8b9480c..521fcaf 100644 --- a/net/net-connector.test.c++ +++ b/net/net-connector.test.c++ @@ -22,7 +22,7 @@ inline bool network_tests_enabled() auto register_connector_tests() { - if(!network_tests_enabled()) return false; + if(not network_tests_enabled()) return false; tester::bdd::scenario("Basic construction, [net]") = [] { tester::bdd::given("A connector to google.com:http") = [] { @@ -37,7 +37,7 @@ auto register_connector_tests() tester::bdd::given("A connection to google.com:http") = [] { check_nothrow([] { const auto s = net::connect("google.com","http"); - check_true(!(!s)); + check_true(not(not s)); }); }; }; diff --git a/net/net-endpoint_buf.c++m b/net/net-endpoint_buf.c++m index 19230c5..11b7c14 100644 --- a/net/net-endpoint_buf.c++m +++ b/net/net-endpoint_buf.c++m @@ -101,7 +101,7 @@ protected: int_type overflow(int_type ch = traits_type::eof()) override { if (sync() == -1) return traits_type::eof(); - if (!traits_type::eq_int_type(ch, traits_type::eof())) { + if (not traits_type::eq_int_type(ch, traits_type::eof())) { *pptr() = traits_type::to_char_type(ch); pbump(1); return ch; @@ -112,7 +112,7 @@ protected: int sync() override { auto pending = pptr() - pbase(); if (pending > 0) { - if (!send_all(pbase(), static_cast(pending))) return -1; + if (not send_all(pbase(), static_cast(pending))) return -1; setp(m_output.data(), m_output.data() + N - 1); } return 0; @@ -126,8 +126,8 @@ private: if (res <= 0) { auto err = posix::get_errno(); if (err == posix::eintr) continue; - if (err == posix::ewouldblock || err == posix::eagain) { - if (!const_cast(m_socket).wait()) return false; + if (err == posix::ewouldblock or err == posix::eagain) { + if (not const_cast(m_socket).wait()) return false; continue; } return false; diff --git a/net/net-endpoint_buf.test.c++ b/net/net-endpoint_buf.test.c++ index b6c70b6..95caf13 100644 --- a/net/net-endpoint_buf.test.c++ +++ b/net/net-endpoint_buf.test.c++ @@ -29,7 +29,7 @@ auto register_endpointbuf_tests() tester::bdd::scenario("endpointbuf_base construction, [net]") = [] { tester::bdd::given("A socket") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; auto s = socket{posix::af_inet, posix::sock_stream}; check_nothrow([&s] { @@ -41,7 +41,7 @@ auto register_endpointbuf_tests() tester::bdd::scenario("endpointbuf_base wait_for, [net]") = [] { tester::bdd::given("An endpointbuf_base with a new socket") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; auto s = socket{posix::af_inet, posix::sock_stream}; endpointbuf_base buf{std::move(s)}; @@ -49,14 +49,14 @@ auto register_endpointbuf_tests() tester::bdd::when("Calling wait_for with a short timeout") = [&buf] { using namespace std::chrono_literals; auto result = buf.wait_for(1ms); - check_true(!result); + check_true(not result); }; }; }; tester::bdd::scenario("endpointbuf template construction, [net]") = [] { tester::bdd::given("A socket") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; auto s = socket{posix::af_inet, posix::sock_stream}; check_nothrow([&s] { @@ -68,7 +68,7 @@ auto register_endpointbuf_tests() tester::bdd::scenario("Type aliases, [net]") = [] { tester::bdd::given("TCP and UDP endpointbuf type aliases") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; auto s1 = socket{posix::af_inet, posix::sock_stream}; auto s2 = socket{posix::af_inet, posix::sock_dgram}; @@ -83,7 +83,7 @@ auto register_endpointbuf_tests() tester::bdd::scenario("endpointbuf buffer initialization, [net]") = [] { tester::bdd::given("An endpointbuf with a socket") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; auto s = socket{posix::af_inet, posix::sock_stream}; endpointbuf<512> buf{std::move(s)}; @@ -99,7 +99,7 @@ auto register_endpointbuf_tests() tester::bdd::scenario("endpointbuf construction with different sizes, [net]") = [] { tester::bdd::given("Sockets for different buffer sizes") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::when("Creating endpointbuf with different buffer sizes") = [] { check_nothrow([] { diff --git a/net/net-endpoint_stream.c++m b/net/net-endpoint_stream.c++m index 2e2c69c..1269797 100644 --- a/net/net-endpoint_stream.c++m +++ b/net/net-endpoint_stream.c++m @@ -14,7 +14,7 @@ public: ~iendpointstream() override { if(m_buf) delete m_buf; } iendpointstream& operator=(iendpointstream&& s) noexcept { if(m_buf) delete m_buf; m_buf = s.m_buf; s.m_buf = nullptr; init(m_buf); return *this; } void close() noexcept { if(m_buf) { delete m_buf; m_buf = nullptr; } } - bool wait_for(const std::chrono::milliseconds& timeout) { return m_buf->wait_for(timeout) && peek() != std::char_traits::eof(); } + bool wait_for(const std::chrono::milliseconds& timeout) { return m_buf->wait_for(timeout) and peek() != std::char_traits::eof(); } private: iendpointstream(const iendpointstream&) = delete; gsl::owner m_buf; @@ -41,7 +41,7 @@ public: ~endpointstream() override { if(m_buf) delete m_buf; } endpointstream& operator=(endpointstream&& s) noexcept { if(m_buf) delete m_buf; m_buf = s.m_buf; s.m_buf = nullptr; init(m_buf); return *this; } void close() noexcept { if(m_buf) { delete m_buf; m_buf = nullptr; } } - bool wait_for(const std::chrono::milliseconds& timeout) { return m_buf->wait_for(timeout) && peek() != std::char_traits::eof(); } + bool wait_for(const std::chrono::milliseconds& timeout) { return m_buf->wait_for(timeout) and peek() != std::char_traits::eof(); } private: endpointstream(const endpointstream&) = delete; gsl::owner m_buf; diff --git a/net/net-endpoint_stream.test.c++ b/net/net-endpoint_stream.test.c++ index d37cdc2..8bc9bd2 100644 --- a/net/net-endpoint_stream.test.c++ +++ b/net/net-endpoint_stream.test.c++ @@ -20,7 +20,7 @@ inline bool network_tests_enabled() auto register_endpointstream_tests() { - if(!network_tests_enabled()) return false; + if(not network_tests_enabled()) return false; tester::bdd::scenario("Join and Distribute (Dgram), [net]") = [] { tester::bdd::given("A multicast join and distribute") = [] { diff --git a/net/net-gsl.c++m b/net/net-gsl.c++m index 36f1c1e..0a7eee7 100644 --- a/net/net-gsl.c++m +++ b/net/net-gsl.c++m @@ -59,7 +59,7 @@ public: bool operator==(const T& rhs) const {return m_ptr == rhs;} - bool operator!=(const T& rhs) const {return !(*this == rhs);} + bool operator!=(const T& rhs) const {return not(*this == rhs);} private: diff --git a/net/net-http_base64.c++m b/net/net-http_base64.c++m index e456e75..33e3895 100644 --- a/net/net-http_base64.c++m +++ b/net/net-http_base64.c++m @@ -12,9 +12,9 @@ export namespace http::base64 { constexpr char to_index(char c) { if(c == '=') return 64; - if(c >= 'a' && c <= 'z') return ('Z'-'A') + 1 + (c - 'a'); - if(c >= 'A' && c <= 'Z') return (c - 'A'); - if(c >= '0' && c <= '9') return ('Z'-'A') + ('z'-'a') + 2 + (c - '0'); + if(c >= 'a' and c <= 'z') return ('Z'-'A') + 1 + (c - 'a'); + if(c >= 'A' and c <= 'Z') return (c - 'A'); + if(c >= '0' and c <= '9') return ('Z'-'A') + ('z'-'a') + 2 + (c - '0'); if(c == '+') return 62; if(c == '/') return 63; return 64; diff --git a/net/net-http_escape.c++m b/net/net-http_escape.c++m index b8f40f9..94c7f36 100644 --- a/net/net-http_escape.c++m +++ b/net/net-http_escape.c++m @@ -17,7 +17,7 @@ namespace detail { inline constexpr bool url_unreserved(unsigned char c) { - return std::isalnum(c) != 0 || c == '-' || c == '_' || c == '.' || c == '~'; + return std::isalnum(c) != 0 or c == '-' or c == '_' or c == '.' or c == '~'; } inline void write_html_escaped(std::ostream& os, std::string_view value) diff --git a/net/net-http_headers.c++m b/net/net-http_headers.c++m index 868997b..9974cb9 100644 --- a/net/net-http_headers.c++m +++ b/net/net-http_headers.c++m @@ -45,7 +45,7 @@ inline std::istream& operator >> (std::istream &is, headers &hdrs) while(is.good() and is.peek() != '\r' and is.peek() != '\n') { std::string line; - if (!std::getline(is, line) || line == "\r" || line.empty()) break; + if (not std::getline(is, line) or line == "\r" or line.empty()) break; auto sv = std::string_view{line}; auto pos = sv.find(':'); @@ -73,11 +73,11 @@ inline bool accepts_json(const headers& hdr) { using namespace std::string_literals; using namespace std::string_view_literals; - if(!hdr.contains("accept"s)) + if(not hdr.contains("accept"s)) return true; // No Accept header means accept anything const auto accept_value = hdr["accept"s]; - return accept_value.contains("*/*"sv) || - accept_value.contains("application/json"sv) || + return accept_value.contains("*/*"sv) or + accept_value.contains("application/json"sv) or accept_value.contains("application/*"sv); } diff --git a/net/net-http_server.c++m b/net/net-http_server.c++m index 2adb7b2..1cebb29 100644 --- a/net/net-http_server.c++m +++ b/net/net-http_server.c++m @@ -227,7 +227,7 @@ public: if(on_bound) on_bound(); - while(!m_stop.load()) + while(not m_stop.load()) { try { @@ -302,7 +302,7 @@ private: // Prefer C++23 chrono formatting where it is stable. // clang-22 (macOS) is known to crash compiling chrono formatting via std::format/std::vformat in our modules setup. // Keep local dev stable while still enabling CI coverage on Linux. -#if defined(__APPLE__) && defined(__clang__) && (__clang_major__ >= 22) +#if defined(__APPLE__) and defined(__clang__) and (__clang_major__ >= 22) return utils::rfc1123_legacy(std::chrono::system_clock::now()); #else using namespace std::chrono; @@ -328,7 +328,7 @@ private: auto tmp = ""s; for(const auto& m : m_methods) { - if(!tmp.empty()) tmp += ", "; + if(not tmp.empty()) tmp += ", "; tmp += m; } return tmp; @@ -352,7 +352,7 @@ private: std::string method, uri, version; stream >> method >> uri >> version >> net::crlf; - if(!stream.good()) + if(not stream.good()) { if(stream.eof()) { @@ -418,7 +418,7 @@ private: } // HTTP/1.1 requires Host - if(!hs.contains("host") || hs["host"].empty()) + if(not hs.contains("host") or hs["host"].empty()) { const auto request_duration = duration_cast(system_clock::now() - request_start).count(); net::slog << net::warning("HTTP_MISSING_HOST") << "missing Host header from " << endpoint << ":" << port @@ -462,7 +462,7 @@ private: accept = hs["accept"]; // Log additional headers if present - if(!user_agent.empty() || !content_type.empty() || !accept.empty()) + if(not user_agent.empty() or not content_type.empty() or not accept.empty()) { net::slog << net::debug("HTTP_REQUEST_HEADERS") << "request headers" << std::pair{"ip"sv, endpoint} @@ -490,7 +490,7 @@ private: } } - if(!content_length_ok) + if(not content_length_ok) { net::slog << net::warning("HTTP_INVALID_CONTENT_LENGTH") << "invalid content-length from " << endpoint << ":" << port << std::pair{"ip"sv, endpoint} @@ -516,7 +516,7 @@ private: for(auto& c : body) { auto ch = stream.get(); - if(stream.eof() || stream.fail()) + if(stream.eof() or stream.fail()) { body_complete = false; break; @@ -533,7 +533,7 @@ private: << net::flush; } - if(!body_complete) + if(not body_complete) { net::slog << net::warning("HTTP_INCOMPLETE_BODY") << "incomplete body read from " << endpoint << ":" << port << " (expected " << content_length << " bytes)" << std::pair{"ip"sv, endpoint} @@ -578,7 +578,7 @@ private: << "Content-Length: 0" << net::crlf << net::crlf << net::flush; } - else if(!m_methods.contains(method)) + else if(not m_methods.contains(method)) { const auto request_duration = duration_cast(system_clock::now() - request_start).count(); net::slog << net::warning("HTTP_UNSUPPORTED_METHOD") << "unsupported HTTP method \"" << method << "\" for \"" << uri << "\" from " << endpoint << ":" << port @@ -629,7 +629,7 @@ private: route_found = true; auto it = methods_map.find(method); // If HEAD method not found, try GET as fallback for HEAD requests - if(it == methods_map.end() && method == method_head) + if(it == methods_map.end() and method == method_head) it = methods_map.find(method_get); if(it != methods_map.end()) @@ -638,7 +638,7 @@ private: try { std::tie(res_status, res_content, res_type, custom_headers) = it->second.render(uri, body, hs); - if(!res_type.empty()) + if(not res_type.empty()) break; } catch(const std::exception& e) @@ -665,7 +665,7 @@ private: // Handle OPTIONS preflight requests - if no route found, return 204 with empty body // CORS middleware will add CORS headers if configured - if(method == method_options && !route_found && res_type.empty()) + if(method == method_options and not route_found and res_type.empty()) { res_status = status_no_content; res_content = ""; @@ -673,7 +673,7 @@ private: custom_headers = std::nullopt; } // If route found but method not allowed, return 405 Method Not Allowed - else if(route_found && !method_allowed && res_type.empty()) + else if(route_found and not method_allowed and res_type.empty()) { const auto request_duration = duration_cast(system_clock::now() - request_start).count(); net::slog << net::warning("HTTP_METHOD_NOT_ALLOWED") << "method not allowed for \"" << method << " " << uri << "\" from " << endpoint << ":" << port @@ -691,7 +691,7 @@ private: custom_headers = std::nullopt; } - if(!res_type.empty()) + if(not res_type.empty()) { // Extract status code from status string (e.g., "200 OK" -> 200) auto status_code = 200ll; diff --git a/net/net-http_server.test.c++ b/net/net-http_server.test.c++ index 051b9ec..8af0d71 100644 --- a/net/net-http_server.test.c++ +++ b/net/net-http_server.test.c++ @@ -63,7 +63,7 @@ auto register_server_tests() }; tester::bdd::scenario("Server start and stop sequence, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with a route") = [] { auto server = std::make_shared(); @@ -96,7 +96,7 @@ auto register_server_tests() }; tester::bdd::scenario("Structured logging fields in HTTP requests, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with logging configured") = [] { auto captured_output = std::make_shared(); @@ -140,10 +140,10 @@ auto register_server_tests() std::string response; std::string line; int line_count = 0; - while(line_count < 20 && stream && std::getline(stream, line)) { + while(line_count < 20 and stream and std::getline(stream, line)) { response += line + "\n"; line_count++; - if(line.empty() || line == "\r") break; + if(line.empty() or line == "\r") break; } } catch(...) {} @@ -186,7 +186,7 @@ auto register_server_tests() } } - if(!request_id_value.empty()) { + if(not request_id_value.empty()) { check_contains(output, "\"request_id\":\"" + request_id_value + "\""); } }; @@ -195,7 +195,7 @@ auto register_server_tests() }; tester::bdd::scenario("Request duration tracking in HTTP responses, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with a slow endpoint") = [] { auto captured_output = std::make_shared(); @@ -239,10 +239,10 @@ auto register_server_tests() std::string response; std::string line; int line_count = 0; - while(line_count < 20 && stream && std::getline(stream, line)) { + while(line_count < 20 and stream and std::getline(stream, line)) { response += line + "\n"; line_count++; - if(line.empty() || line == "\r") break; + if(line.empty() or line == "\r") break; } } catch(...) {} @@ -282,7 +282,7 @@ auto register_server_tests() }; tester::bdd::scenario("HTTP headers logging when no headers present, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with logging configured") = [] { auto captured_output = std::make_shared(); @@ -323,10 +323,10 @@ auto register_server_tests() std::string response; std::string line; int line_count = 0; - while(line_count < 20 && stream && std::getline(stream, line)) { + while(line_count < 20 and stream and std::getline(stream, line)) { response += line + "\n"; line_count++; - if(line.empty() || line == "\r") break; + if(line.empty() or line == "\r") break; } } catch(...) {} @@ -348,7 +348,7 @@ auto register_server_tests() }; tester::bdd::scenario("HTTP headers logging with partial headers, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with logging configured") = [] { auto captured_output = std::make_shared(); @@ -390,10 +390,10 @@ auto register_server_tests() std::string response; std::string line; int line_count = 0; - while(line_count < 20 && stream && std::getline(stream, line)) { + while(line_count < 20 and stream and std::getline(stream, line)) { response += line + "\n"; line_count++; - if(line.empty() || line == "\r") break; + if(line.empty() or line == "\r") break; } } catch(...) {} @@ -416,7 +416,7 @@ auto register_server_tests() }; tester::bdd::scenario("HTTP headers logging with empty header values, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with logging configured") = [] { auto captured_output = std::make_shared(); @@ -460,10 +460,10 @@ auto register_server_tests() std::string response; std::string line; int line_count = 0; - while(line_count < 20 && stream && std::getline(stream, line)) { + while(line_count < 20 and stream and std::getline(stream, line)) { response += line + "\n"; line_count++; - if(line.empty() || line == "\r") break; + if(line.empty() or line == "\r") break; } } catch(...) {} @@ -484,7 +484,7 @@ auto register_server_tests() }; tester::bdd::scenario("X-Correlation-ID generation when missing, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with logging configured") = [] { auto captured_output = std::make_shared(); @@ -525,10 +525,10 @@ auto register_server_tests() std::string response; std::string line; int line_count = 0; - while(line_count < 20 && stream && std::getline(stream, line)) { + while(line_count < 20 and stream and std::getline(stream, line)) { response += line + "\n"; line_count++; - if(line.empty() || line == "\r") break; + if(line.empty() or line == "\r") break; } } catch(...) {} @@ -567,7 +567,7 @@ auto register_server_tests() }; tester::bdd::scenario("X-Correlation-ID preservation when provided, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with logging configured") = [] { auto captured_output = std::make_shared(); @@ -610,10 +610,10 @@ auto register_server_tests() std::string response; std::string line; int line_count = 0; - while(line_count < 20 && stream && std::getline(stream, line)) { + while(line_count < 20 and stream and std::getline(stream, line)) { response += line + "\n"; line_count++; - if(line.empty() || line == "\r") break; + if(line.empty() or line == "\r") break; } } catch(...) {} @@ -634,7 +634,7 @@ auto register_server_tests() }; tester::bdd::scenario("405 Method Not Allowed when route exists but method doesn't, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with a GET route registered") = [] { auto server = std::make_shared(); @@ -673,13 +673,13 @@ auto register_server_tests() std::string response; std::string line; int line_count = 0; - while(line_count < 5 && stream && std::getline(stream, line)) { + while(line_count < 5 and stream and std::getline(stream, line)) { response += line + "\n"; line_count++; if(line_count == 1) { // First line is status line: "HTTP/1.1 405 Method Not Allowed" // Remove trailing \r if present - if(!line.empty() && line.back() == '\r') { + if(not line.empty() and line.back() == '\r') { line.pop_back(); } auto space1 = line.find(' '); @@ -693,7 +693,7 @@ auto register_server_tests() } } } - if(line.empty() || line == "\r") break; + if(line.empty() or line == "\r") break; } } catch(...) {} @@ -711,7 +711,7 @@ auto register_server_tests() }; tester::bdd::scenario("404 Not Found when route doesn't exist, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with a route registered") = [] { auto server = std::make_shared(); @@ -747,13 +747,13 @@ auto register_server_tests() std::string response; std::string line; int line_count = 0; - while(line_count < 5 && stream && std::getline(stream, line)) { + while(line_count < 5 and stream and std::getline(stream, line)) { response += line + "\n"; line_count++; if(line_count == 1) { // First line is status line: "HTTP/1.0 404 Not Found" or "HTTP/1.1 404 Not Found" // Remove trailing \r if present - if(!line.empty() && line.back() == '\r') { + if(not line.empty() and line.back() == '\r') { line.pop_back(); } auto space1 = line.find(' '); @@ -767,7 +767,7 @@ auto register_server_tests() } } } - if(line.empty() || line == "\r") break; + if(line.empty() or line == "\r") break; } } catch(...) {} @@ -785,7 +785,7 @@ auto register_server_tests() }; tester::bdd::scenario("400 Bad Request when Host header is missing, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with a route registered") = [] { auto server = std::make_shared(); @@ -817,8 +817,8 @@ auto register_server_tests() << net::flush; std::string line; - if(stream && std::getline(stream, line)) { - if(!line.empty() && line.back() == '\r') + if(stream and std::getline(stream, line)) { + if(not line.empty() and line.back() == '\r') line.pop_back(); auto space1 = line.find(' '); if(space1 != std::string::npos) { @@ -844,7 +844,7 @@ auto register_server_tests() }; tester::bdd::scenario("400 Bad Request when Content-Length is invalid, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with a route registered") = [] { auto server = std::make_shared(); @@ -878,8 +878,8 @@ auto register_server_tests() << net::flush; std::string line; - if(stream && std::getline(stream, line)) { - if(!line.empty() && line.back() == '\r') + if(stream and std::getline(stream, line)) { + if(not line.empty() and line.back() == '\r') line.pop_back(); auto space1 = line.find(' '); if(space1 != std::string::npos) { @@ -905,7 +905,7 @@ auto register_server_tests() }; tester::bdd::scenario("Connection header is echoed on successful responses, [net]") = [] { - if(!network_tests_enabled()) return; + if(not network_tests_enabled()) return; tester::bdd::given("An HTTP server with a route registered") = [] { auto server = std::make_shared(); @@ -939,10 +939,10 @@ auto register_server_tests() std::string line; int line_count = 0; - while(line_count < 20 && stream && std::getline(stream, line)) { + while(line_count < 20 and stream and std::getline(stream, line)) { *response_headers += line + "\n"; line_count++; - if(line.empty() || line == "\r") break; + if(line.empty() or line == "\r") break; } } catch(...) {} diff --git a/net/net-http_server_middlewares.c++m b/net/net-http_server_middlewares.c++m index 163d7c6..76629dd 100644 --- a/net/net-http_server_middlewares.c++m +++ b/net/net-http_server_middlewares.c++m @@ -100,7 +100,7 @@ inline auto authentication_middleware( } // Validate token - if(authorization.empty() || !validate_token(authorization)) + if(authorization.empty() or not validate_token(authorization)) { // Return 401 Unauthorized with WWW-Authenticate header auto error_headers = headers{}; @@ -152,17 +152,17 @@ inline auto accept_validation_middleware(std::string_view required_content_type else { // Check if Accept header contains the required content type - if(!hdr.contains("accept"s)) + if(not hdr.contains("accept"s)) accepted = true; // No Accept header means accept anything else { const auto accept_value = hdr["accept"s]; - accepted = accept_value.contains("*/*"sv) || + accepted = accept_value.contains("*/*"sv) or accept_value.contains(required_content_type); } } - if(!accepted) + if(not accepted) { using namespace std::string_literals; auto error_message = "Not Acceptable: This resource only supports "s + required_content_type + " content type"s; @@ -184,7 +184,7 @@ inline auto correlation_id_middleware() using namespace std::string_literals; // Ensure X-Correlation-ID header exists - modify headers in-place - if(!hdr.contains("x-correlation-id"s)) + if(not hdr.contains("x-correlation-id"s)) { const auto correlation_id = net::generate_uuid_v4(); hdr.set("x-correlation-id"s, correlation_id); @@ -285,7 +285,7 @@ inline auto rate_limiting_middleware( } // Check rate limit - if(!rate_limit_tracker().check_limit(key, max_requests, window_seconds)) + if(not rate_limit_tracker().check_limit(key, max_requests, window_seconds)) { // Rate limit exceeded - use standardized error response auto error_message = std::format( @@ -352,13 +352,13 @@ inline auto cors_middleware( // CORS spec: cannot use wildcard with credentials // If credentials enabled but origin is wildcard, disable credentials for this response - auto use_credentials = allow_credentials && origin_value != "*"s; + auto use_credentials = allow_credentials and origin_value != "*"s; auto preflight_headers = headers{}; preflight_headers.set("access-control-allow-origin"s, origin_value); // Build allowed methods using ranges - pre-calculate size for efficiency - if(!allowed_methods.empty()) + if(not allowed_methods.empty()) { auto methods_view = allowed_methods | std::views::transform([](const auto& m) { return std::string_view{m}; }); auto total_size = std::accumulate(methods_view.begin(), methods_view.end(), std::size_t{0}, @@ -367,7 +367,7 @@ inline auto cors_middleware( methods_str.reserve(total_size); auto first = true; std::ranges::for_each(methods_view, [&](auto method) { - if(!first) methods_str += ", "s; + if(not first) methods_str += ", "s; methods_str += method; first = false; }); @@ -375,7 +375,7 @@ inline auto cors_middleware( } // Build allowed headers using ranges - pre-calculate size for efficiency - if(!allowed_headers.empty()) + if(not allowed_headers.empty()) { auto headers_view = allowed_headers | std::views::transform([](const auto& h) { return std::string_view{h}; }); auto total_size = std::accumulate(headers_view.begin(), headers_view.end(), std::size_t{0}, @@ -384,7 +384,7 @@ inline auto cors_middleware( headers_str.reserve(total_size); auto first = true; std::ranges::for_each(headers_view, [&](auto header) { - if(!first) headers_str += ", "s; + if(not first) headers_str += ", "s; headers_str += header; first = false; }); @@ -417,7 +417,7 @@ inline auto cors_middleware( cors_headers.set("access-control-allow-origin"s, origin_value); // Build allowed methods using ranges - pre-calculate size for efficiency - if(!allowed_methods.empty()) + if(not allowed_methods.empty()) { auto methods_view = allowed_methods | std::views::transform([](const auto& m) { return std::string_view{m}; }); auto total_size = std::accumulate(methods_view.begin(), methods_view.end(), std::size_t{0}, @@ -426,7 +426,7 @@ inline auto cors_middleware( methods_str.reserve(total_size); auto first = true; std::ranges::for_each(methods_view, [&](auto method) { - if(!first) methods_str += ", "s; + if(not first) methods_str += ", "s; methods_str += method; first = false; }); @@ -434,7 +434,7 @@ inline auto cors_middleware( } // Build allowed headers using ranges - pre-calculate size for efficiency - if(!allowed_headers.empty()) + if(not allowed_headers.empty()) { auto headers_view = allowed_headers | std::views::transform([](const auto& h) { return std::string_view{h}; }); auto total_size = std::accumulate(headers_view.begin(), headers_view.end(), std::size_t{0}, @@ -443,7 +443,7 @@ inline auto cors_middleware( headers_str.reserve(total_size); auto first = true; std::ranges::for_each(headers_view, [&](auto header) { - if(!first) headers_str += ", "s; + if(not first) headers_str += ", "s; headers_str += header; first = false; }); @@ -452,7 +452,7 @@ inline auto cors_middleware( // CORS spec: cannot use wildcard with credentials // If credentials enabled but origin is wildcard, disable credentials for this response - if(allow_credentials && origin_value != "*"s) + if(allow_credentials and origin_value != "*"s) cors_headers.set("access-control-allow-credentials"s, "true"s); if(max_age.has_value()) @@ -588,7 +588,7 @@ inline std::string_view metrics_status_code(std::string_view status_line) inline std::pair metrics_method_and_target(std::string_view request_line) { auto rest = request_line; - while(not rest.empty() && rest.front() == ' ') + while(not rest.empty() and rest.front() == ' ') rest.remove_prefix(1); if(rest.empty()) @@ -606,7 +606,7 @@ inline std::pair metrics_method_and_target(s const auto method = rest.substr(0, method_end); auto target = rest.substr(method_end + 1); - while(not target.empty() && target.front() == ' ') + while(not target.empty() and target.front() == ' ') target.remove_prefix(1); const auto target_end = target.find(' '); if(target_end != std::string_view::npos) @@ -616,7 +616,7 @@ inline std::pair metrics_method_and_target(s inline bool is_metrics_scrape_request(std::string_view method, std::string_view target) { - if(method != "GET"sv && method != "get"sv) + if(method != "GET"sv and method != "get"sv) return false; auto path = target; diff --git a/net/net-http_server_middlewares.test.c++ b/net/net-http_server_middlewares.test.c++ index 26a4103..9a1feed 100644 --- a/net/net-http_server_middlewares.test.c++ +++ b/net/net-http_server_middlewares.test.c++ @@ -241,7 +241,7 @@ auto register_middleware_tests() tester::bdd::scenario("authentication_middleware - allows public paths, [net]") = [] { tester::bdd::given("A middleware with public paths") = [] { auto is_public = [](std::string_view path) -> bool { - return path == "/public"sv || path == "/health"sv; + return path == "/public"sv or path == "/health"sv; }; auto validate_token = [](std::string_view) -> bool { return false; }; diff --git a/net/net-posix.c++m b/net/net-posix.c++m index d21fe1e..573796e 100644 --- a/net/net-posix.c++m +++ b/net/net-posix.c++m @@ -225,7 +225,7 @@ int connect_with_timeout(int fd, const sockaddr* address, socklen_t address_len, return -1; } - if (!fd_isset(fd, &writefds)) { + if (not fd_isset(fd, &writefds)) { errno = ETIMEDOUT; return -1; } diff --git a/net/net-posix.test.c++ b/net/net-posix.test.c++ index 25e8b52..9558222 100644 --- a/net/net-posix.test.c++ +++ b/net/net-posix.test.c++ @@ -20,7 +20,7 @@ inline bool network_tests_enabled() auto register_posix_tests() { - if(!network_tests_enabled()) return false; + if(not network_tests_enabled()) return false; tester::bdd::scenario("connect_with_timeout success, [net]") = [] { struct State { @@ -68,7 +68,7 @@ auto register_posix_tests() auto status = posix::connect_with_timeout(client_fd, (posix::sockaddr*)addr.get(), sizeof(*addr), std::chrono::milliseconds{500}); check_eq(status, -1); - check_true(posix::get_errno() == posix::econnrefused || posix::get_errno() == posix::etimedout); + check_true(posix::get_errno() == posix::econnrefused or posix::get_errno() == posix::etimedout); posix::close(client_fd); }; diff --git a/net/net-readme_examples.test.c++ b/net/net-readme_examples.test.c++ index a5d5356..1fa40b7 100644 --- a/net/net-readme_examples.test.c++ +++ b/net/net-readme_examples.test.c++ @@ -39,7 +39,7 @@ auto register_readme_examples_tests() // Define public paths (no authentication required) auto is_public = [](std::string_view path) { - return path == "/"sv || path == "/health"sv || path.starts_with("/public/"sv); + return path == "/"sv or path == "/health"sv or path.starts_with("/public/"sv); }; // Define token validation @@ -150,7 +150,7 @@ auto register_readme_examples_tests() // JWT token validation example auto validate_jwt = [](std::string_view token) { // Extract Bearer token - if(!token.starts_with("Bearer "sv)) + if(not token.starts_with("Bearer "sv)) return false; auto jwt_token = token.substr(7); // Skip "Bearer " diff --git a/net/net-receiver.c++m b/net/net-receiver.c++m index cecf24c..7e4af3e 100644 --- a/net/net-receiver.c++m +++ b/net/net-receiver.c++m @@ -43,7 +43,7 @@ iendpointstream join(std::string_view group, std::string_view service, bool loop for(const auto& address : local_address) { net::socket s{address.ai_family, address.ai_socktype, address.ai_protocol}; - if(!s) continue; + if(not s) continue; auto reuse = 1; if(posix::setsockopt(s, posix::sol_socket, posix::so_reuseport, &reuse, sizeof reuse) < 0) continue; diff --git a/net/net-receiver.test.c++ b/net/net-receiver.test.c++ index 655b5d6..e36f9df 100644 --- a/net/net-receiver.test.c++ +++ b/net/net-receiver.test.c++ @@ -19,7 +19,7 @@ inline bool network_tests_enabled() auto register_receiver_tests() { - if(!network_tests_enabled()) return false; + if(not network_tests_enabled()) return false; tester::bdd::scenario("Basic construction, [net]") = [] { tester::bdd::given("A receiver for group 228.0.0.4 and service test") = [] { @@ -33,7 +33,7 @@ tester::bdd::scenario("Join multicast group, [net]") = [] { tester::bdd::given("Joining group 228.0.0.4 on port 54321") = [] { check_nothrow([] { auto s = net::join("228.0.0.4", "54321"); - check_true(!(!s)); + check_true(not(not s)); }); }; }; diff --git a/net/net-receiver_sender.test.c++ b/net/net-receiver_sender.test.c++ index 3fb16d0..f340ac0 100644 --- a/net/net-receiver_sender.test.c++ +++ b/net/net-receiver_sender.test.c++ @@ -18,7 +18,7 @@ inline bool network_tests_enabled() auto register_receiver_sender_tests() { - if(!network_tests_enabled()) return false; + if(not network_tests_enabled()) return false; std::array data; for (int i = 0; i < 100; ++i) data[i] = i + 1; @@ -60,7 +60,7 @@ auto register_receiver_sender_tests() // Wait for receiver to be ready auto start_ready = std::chrono::steady_clock::now(); - while (!receiver_ready && (std::chrono::steady_clock::now() - start_ready) < 5s) { + while (not receiver_ready and (std::chrono::steady_clock::now() - start_ready) < 5s) { std::this_thread::sleep_for(10ms); } @@ -81,11 +81,11 @@ auto register_receiver_sender_tests() // Join with timeout logic auto start = std::chrono::steady_clock::now(); - while (!done && (std::chrono::steady_clock::now() - start) < 15s) { + while (not done and (std::chrono::steady_clock::now() - start) < 15s) { std::this_thread::sleep_for(100ms); } - if (!done) { + if (not done) { receiver_timed_out = true; } diff --git a/net/net-sender.c++m b/net/net-sender.c++m index 7c5fcd4..af8bbc3 100644 --- a/net/net-sender.c++m +++ b/net/net-sender.c++m @@ -37,7 +37,7 @@ oendpointstream distribute(std::string_view group, std::string_view service_or_p for(const auto& address : distribution_address) { net::socket s{address.ai_family, address.ai_socktype, address.ai_protocol}; - if(!s) continue; + if(not s) continue; auto t2l = ttl; if(posix::setsockopt(s, posix::ipproto_ip, posix::ip_multicast_ttl, &t2l, sizeof t2l) < 0) continue; diff --git a/net/net-sender.test.c++ b/net/net-sender.test.c++ index a6f9c53..2bc5d55 100644 --- a/net/net-sender.test.c++ +++ b/net/net-sender.test.c++ @@ -19,7 +19,7 @@ inline bool network_tests_enabled() auto register_sender_tests() { - if(!network_tests_enabled()) return false; + if(not network_tests_enabled()) return false; tester::bdd::scenario("Basic construction, [net]") = [] { tester::bdd::given("A sender for group 228.0.0.4 and service test") = [] { @@ -33,7 +33,7 @@ tester::bdd::scenario("Distribute multicast, [net]") = [] { tester::bdd::given("Distributing to group 228.0.0.4 on port 54321") = [] { check_nothrow([] { auto s = net::distribute("228.0.0.4", "54321", 3); - check_true(!(!s)); + check_true(not(not s)); }); }; }; @@ -42,7 +42,7 @@ tester::bdd::scenario("UDP Distribute, [net]") = [] { tester::bdd::given("Distributing to localhost:syslog") = [] { check_nothrow([] { auto s = net::distribute("localhost", "syslog"); - check_true(!(!s)); + check_true(not(not s)); }); }; }; diff --git a/net/net-socket.test.c++ b/net/net-socket.test.c++ index 1712632..ffeac6d 100644 --- a/net/net-socket.test.c++ +++ b/net/net-socket.test.c++ @@ -20,12 +20,12 @@ inline bool network_tests_enabled() auto register_socket_tests() { - if(!network_tests_enabled()) return false; + if(not network_tests_enabled()) return false; tester::bdd::scenario("Basic construction, [net]") = [] { tester::bdd::given("An IPv4 TCP socket") = [] { const net::socket s{posix::af_inet, posix::sock_stream}; - check_true(!(!s)); + check_true(not(not s)); int fd = s; check_true(fd > 0); @@ -36,7 +36,7 @@ auto register_socket_tests() tester::bdd::given("A socket constructed from a file descriptor") = [] { const auto s = net::socket{2112}; - check_true(!(!s)); + check_true(not(not s)); int fd = s; check_eq(fd, 2112); @@ -48,13 +48,13 @@ auto register_socket_tests() tester::bdd::given("A socket being moved") = [] { auto s1 = net::socket{posix::af_inet, posix::sock_dgram}; - check_true(!(!s1)); + check_true(not(not s1)); int fd1 = s1; check_true(fd1 > 0); const auto s2 = net::socket{std::move(s1)}; - check_true(!s1); - check_true(!(!s2)); + check_true(not s1); + check_true(not(not s2)); int fd2 = s2; check_eq(fd2, fd1); @@ -68,7 +68,7 @@ auto register_socket_tests() const auto s = net::socket{posix::af_inet, posix::sock_stream}; using namespace std::chrono_literals; auto b = s.wait_for(1ms); - check_true(!b); + check_true(not b); }; }; diff --git a/net/net-structured_log_stream.c++m b/net/net-structured_log_stream.c++m index ee9eed7..e394cda 100644 --- a/net/net-structured_log_stream.c++m +++ b/net/net-structured_log_stream.c++m @@ -78,57 +78,57 @@ enum class log_format { syslog, jsonl }; // Concepts for type categorization in convert_to_value template -concept exact_value_type = std::same_as, std::nullptr_t> || - std::same_as, bool> || - std::same_as, int> || - std::same_as, unsigned int> || - std::same_as, long> || - std::same_as, unsigned long> || - std::same_as, long long> || - std::same_as, unsigned long long> || - std::same_as, double> || +concept exact_value_type = std::same_as, std::nullptr_t> or + std::same_as, bool> or + std::same_as, int> or + std::same_as, unsigned int> or + std::same_as, long> or + std::same_as, unsigned long> or + std::same_as, long long> or + std::same_as, unsigned long long> or + std::same_as, double> or std::same_as, std::string>; template -concept c_string_type = std::same_as, const char*> || +concept c_string_type = std::same_as, const char*> or std::same_as, char*>; template -concept string_view_convertible = !exact_value_type && - !c_string_type && +concept string_view_convertible = not exact_value_type and + not c_string_type and std::convertible_to; template -concept integral_convertible = !exact_value_type && - !c_string_type && - !string_view_convertible && +concept integral_convertible = not exact_value_type and + not c_string_type and + not string_view_convertible and std::integral>; template -concept floating_convertible = !exact_value_type && - !c_string_type && - !string_view_convertible && - !integral_convertible && +concept floating_convertible = not exact_value_type and + not c_string_type and + not string_view_convertible and + not integral_convertible and std::floating_point>; template -concept string_convertible = !exact_value_type && - !c_string_type && - !string_view_convertible && - !integral_convertible && - !floating_convertible && +concept string_convertible = not exact_value_type and + not c_string_type and + not string_view_convertible and + not integral_convertible and + not floating_convertible and std::convertible_to; // Generic concept for types with operator<< - must be last fallback // Note: operator<< returns std::basic_ostream& (not stringstream&), // so we check that it returns something convertible to std::ostream& template -concept streamable = !exact_value_type && - !c_string_type && - !string_view_convertible && - !integral_convertible && - !floating_convertible && - !string_convertible && +concept streamable = not exact_value_type and + not c_string_type and + not string_view_convertible and + not integral_convertible and + not floating_convertible and + not string_convertible and requires(std::stringstream& ss, const T& v) { { ss << v } -> std::convertible_to; }; @@ -200,7 +200,7 @@ private: std::string esc; esc.reserve(s.size()); for (char c : s) { - if (c == '"' || c == '\\' || c == ']') esc += '\\'; + if (c == '"' or c == '\\' or c == ']') esc += '\\'; esc += c; } return esc; @@ -227,14 +227,14 @@ private: os << "null"; } else if constexpr (std::is_same_v) { os << (arg ? "true" : "false"); - } else if constexpr (std::is_integral_v || std::is_floating_point_v) { + } else if constexpr (std::is_integral_v or std::is_floating_point_v) { os << arg; } }, v); } void ensure_metadata_cached() { - if (!m_metadata_cached) { + if (not m_metadata_cached) { char host[posix::ni_maxhost]; if (posix::gethostname(host, posix::ni_maxhost) == 0) { m_hostname = host; @@ -313,7 +313,7 @@ private: } void output() { - if (!entry_enabled) return; + if (not entry_enabled) return; // Note: m_log_mutex must be held by caller (already locked in operator<<) ensure_metadata_cached(); @@ -330,7 +330,7 @@ private: << "\"level\":\"" << get_severity_str() << "\"," << "\"source\":\"" << json_escape(m_sd_id) << "\""; - if (!entry_msg_id.empty()) { + if (not entry_msg_id.empty()) { full_line << ",\"msg_id\":\"" << json_escape(entry_msg_id) << "\""; } @@ -469,7 +469,7 @@ public: entry_enabled = static_cast(manip.sev) <= static_cast(m_log_level); // Early exit: skip expensive buffer clearing if disabled - if (!entry_enabled) { + if (not entry_enabled) { return *this; } diff --git a/net/net-structured_log_stream.test.c++ b/net/net-structured_log_stream.test.c++ index 517b46b..e6281c7 100644 --- a/net/net-structured_log_stream.test.c++ +++ b/net/net-structured_log_stream.test.c++ @@ -583,9 +583,9 @@ auto register_structured_log_stream_tests() check_contains(output, "1970"); // year values // Month may be formatted as name or number depending on operator<< // Check for any month representation (03, 12, Mar, Dec, March, December) - check_true(output.find("03") != std::string::npos || - output.find("Mar") != std::string::npos || - output.find("12") != std::string::npos || + check_true(output.find("03") != std::string::npos or + output.find("Mar") != std::string::npos or + output.find("12") != std::string::npos or output.find("Dec") != std::string::npos); slog.redirect(std::clog); }; @@ -658,8 +658,8 @@ auto register_structured_log_stream_tests() check_contains(output, "5"); // seconds check_contains(output, "2"); // hours // Duration might be formatted with units (ms, s, h) or just numbers - check_true(output.find("ms") != std::string::npos || - output.find("milliseconds") != std::string::npos || + check_true(output.find("ms") != std::string::npos or + output.find("milliseconds") != std::string::npos or output.find("123") != std::string::npos); slog.redirect(std::clog); diff --git a/net/net-uri.c++m b/net/net-uri.c++m index 5503217..0c65797 100644 --- a/net/net-uri.c++m +++ b/net/net-uri.c++m @@ -48,7 +48,7 @@ public: { absolute = false; auto position = string.find_first_of(":@[]/?#"); - if(position != std::string_view::npos && string.at(position) == ':') + if(position != std::string_view::npos and string.at(position) == ':') { absolute = true; scheme = string.substr(0, position); @@ -84,7 +84,7 @@ public: path = string.substr(0, position); string.remove_prefix(position); - if(!string.empty() && string.front() == '?') + if(not string.empty() and string.front() == '?') { string.remove_prefix(1); position = string.find_first_of("#"); @@ -92,7 +92,7 @@ public: string.remove_prefix(position); } - if(!string.empty() && string.front() == '#') + if(not string.empty() and string.front() == '#') { string.remove_prefix(1); fragment = string.substr(); @@ -124,13 +124,13 @@ inline auto url_decode(std::string_view encoded) for(std::size_t i = 0; i < encoded.size(); ++i) { - if(encoded[i] == '%' && i + 2 < encoded.size()) + if(encoded[i] == '%' and i + 2 < encoded.size()) { // Try to decode hex pair auto hex_str = encoded.substr(i + 1, 2); auto value = 0; auto [ptr, ec] = std::from_chars(hex_str.data(), hex_str.data() + hex_str.size(), value, 16); - if(ec == std::errc{} && ptr == hex_str.data() + hex_str.size()) + if(ec == std::errc{} and ptr == hex_str.data() + hex_str.size()) { decoded += static_cast(value); i += 2; // Skip the two hex digits diff --git a/net/net-utils.c++m b/net/net-utils.c++m index 9db6ea9..36a0340 100644 --- a/net/net-utils.c++m +++ b/net/net-utils.c++m @@ -22,7 +22,7 @@ struct lockable : public Class, public std::mutex lockable(lockable&& lc) : Class{std::move(lc)} { - if(!lc.try_lock()) std::terminate(); // Do not move locked objects! + if(not lc.try_lock()) std::terminate(); // Do not move locked objects! lc.unlock(); } @@ -94,7 +94,7 @@ inline auto parse_rfc1123_date(std::string_view sv) // Skip weekday (e.g., "Tue, ") auto pos = sv.find(','); - if(pos == std::string_view::npos || pos + 2 >= sv.size()) + if(pos == std::string_view::npos or pos + 2 >= sv.size()) throw std::invalid_argument{"Invalid RFC 1123 date format"}; sv.remove_prefix(pos + 2); // Skip ", " @@ -110,7 +110,7 @@ inline auto parse_rfc1123_date(std::string_view sv) // Parse month abbreviation (Jan, Feb, etc.) auto month_end = sv.find(' '); - if(month_end == std::string_view::npos || month_end != 3) + if(month_end == std::string_view::npos or month_end != 3) throw std::invalid_argument{"Invalid RFC 1123 date format"}; auto month_str = sv.substr(0, 3); unsigned MM = 0u; @@ -131,7 +131,7 @@ inline auto parse_rfc1123_date(std::string_view sv) // Parse year (4 digits) auto year_end = sv.find(' '); - if(year_end == std::string_view::npos || year_end != 4) + if(year_end == std::string_view::npos or year_end != 4) throw std::invalid_argument{"Invalid RFC 1123 date format"}; int YYYY = 0; res = std::from_chars(sv.data(), sv.data() + 4, YYYY); @@ -142,10 +142,10 @@ inline auto parse_rfc1123_date(std::string_view sv) // Parse time (HH:MM:SS) unsigned hh = 0u, mm = 0u, ss = 0u; res = std::from_chars(sv.data(), sv.data() + 2, hh); - if(res.ec != std::errc{} || sv[2] != ':') + if(res.ec != std::errc{} or sv[2] != ':') throw std::invalid_argument{"Invalid time in RFC 1123 date"}; res = std::from_chars(sv.data() + 3, sv.data() + 5, mm); - if(res.ec != std::errc{} || sv[5] != ':') + if(res.ec != std::errc{} or sv[5] != ':') throw std::invalid_argument{"Invalid time in RFC 1123 date"}; res = std::from_chars(sv.data() + 6, sv.data() + 8, ss); if(res.ec != std::errc{}) @@ -176,7 +176,7 @@ inline void ascii_to_upper(std::string& str) noexcept for (auto& ch : str) { const auto c = static_cast(ch); - if (c >= static_cast('a') && c <= static_cast('z')) + if (c >= static_cast('a') and c <= static_cast('z')) ch = static_cast(c - static_cast('a' - 'A')); } } @@ -186,7 +186,7 @@ inline void ascii_to_lower(std::string& str) noexcept for (auto& ch : str) { const auto c = static_cast(ch); - if (c >= static_cast('A') && c <= static_cast('Z')) + if (c >= static_cast('A') and c <= static_cast('Z')) ch = static_cast(c + static_cast('a' - 'A')); } } @@ -226,7 +226,7 @@ inline auto stoll(std::string_view sv) auto [ptr, ec] = std::from_chars(sv.begin(), sv.end(), ll); if(ec == std::errc::result_out_of_range) throw std::invalid_argument{std::string{"Number out of range: "} + std::string{sv}}; - if(ec != std::errc() || ptr != sv.end()) + if(ec != std::errc() or ptr != sv.end()) throw std::invalid_argument{std::string{"Invalid number format: "} + std::string{sv}}; return ll; } diff --git a/net/net-uuid.test.c++ b/net/net-uuid.test.c++ index 082a660..e365f93 100644 --- a/net/net-uuid.test.c++ +++ b/net/net-uuid.test.c++ @@ -27,19 +27,19 @@ auto register_uuid_tests() // Check variant indicator: position 19 (index 18) should be 8, 9, a, or b auto variant_char = uuid[19]; - check_true(variant_char == '8' || variant_char == '9' || - variant_char == 'a' || variant_char == 'b' || - variant_char == 'A' || variant_char == 'B'); + check_true(variant_char == '8' or variant_char == '9' or + variant_char == 'a' or variant_char == 'b' or + variant_char == 'A' or variant_char == 'B'); // Check all characters are valid hex or dashes for (auto i = 0uz; i < uuid.size(); ++i) { auto c = uuid[i]; - if (i == 8 || i == 13 || i == 18 || i == 23) { + if (i == 8 or i == 13 or i == 18 or i == 23) { check_eq(c, '-'); } else { - check_true((c >= '0' && c <= '9') || - (c >= 'a' && c <= 'f') || - (c >= 'A' && c <= 'F')); + check_true((c >= '0' and c <= '9') or + (c >= 'a' and c <= 'f') or + (c >= 'A' and c <= 'F')); } } };