69 lines
2.7 KiB
Text
69 lines
2.7 KiB
Text
|
|
//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<void(HTTPResponse)> onSuccess,
|
||
|
|
std::function<void(std::string)> 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;
|
||
|
|
|
||
|
|
private:
|
||
|
|
struct Impl;
|
||
|
|
std::unique_ptr<Impl> impl;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
#endif
|