//SPDX-License-Identifier: LGPL-3.0-only //SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® export module Crafter.Network:ClientHTTP1; import std; import :HTTP; import :HTTP1; #ifndef CRAFTER_NETWORK_BROWSER namespace Crafter { // HTTP/1.1 client over plain TCP, for peers that cannot speak HTTP/3. // The request/response types are the ones the HTTP/3 client uses, so // swapping ClientHTTP for ClientHTTP1 is a one-line change at the call // site. // // The connection is persistent: the first Send() dials, and later calls // reuse the socket unless the peer asked for it to be closed // (`Connection: close`, or an HTTP/1.0 response without // `Connection: keep-alive`). A reused connection that turns out to have // been closed by the peer in the meantime — the unavoidable race in // HTTP/1.1 keep-alive — is redialled once and the request replayed; // a freshly dialled connection is never replayed on, so a genuinely // broken server surfaces as an exception rather than a retry loop. // // Thread-affinity matches ClientHTTP: one ClientHTTP1 serves one caller // at a time; distinct instances are independent. // // No TLS. This talks `http://`; for an encrypted transport use // ClientHTTP (HTTP/3 over QUIC), or put a TLS-terminating proxy in // front of the HTTP/1.1 endpoint. export class ClientHTTP1 { public: std::string host; std::uint16_t port; ClientHTTP1(const char* host, std::uint16_t port); ClientHTTP1(std::string host, std::uint16_t port); ~ClientHTTP1(); ClientHTTP1(const ClientHTTP1&) = delete; ClientHTTP1(ClientHTTP1&&) noexcept; // Send a request and read the full response. `authority` defaults to // the host:port this client was constructed with; `scheme` is // ignored (the transport is plaintext). HTTPResponse Send(const HTTPRequest& request); // Send a request and deliver the response (or the error text) via // callback, on Crafter.Thread's ThreadPool. void SendAsync(const HTTPRequest& request, std::function onSuccess, std::function onError); // Whether a pooled connection is currently open. Mostly useful for // tests asserting that keep-alive actually kept the socket. bool Connected() const noexcept; // Drop the pooled connection; the next Send() dials again. void Disconnect(); // Limits applied to responses. Set before the first Send(). HTTP1::MessageLimits limits; // How long to wait for the next piece of a response before giving // up on a server that accepted the connection and then went quiet. std::chrono::milliseconds timeout{30000}; private: struct Impl; std::unique_ptr impl; }; } #endif