API — ICoreEssentials/Network
The public contract of 4 header(s) under src/ICoreEssentials/Network — 6 class/struct definition(s), 65 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.
| Header | Defines | Declarations | Bases |
|---|---|---|---|
ICoreHttpClient.h | ICoreHttpRequest, ICoreHttpReply, ICoreHttpClient | 30 | — |
ICoreTcpServer.h | ICoreTcpServer | 9 | — |
ICoreTcpSocket.h | ICoreTcpSocket | 15 | — |
ICoreUrl.h | ICoreUrl | 11 | — |
ICoreHttpClient.h#
src/ICoreEssentials/Network/ICoreHttpClient.h
Only <QByteArray> and <QNetworkReply> are still needed by what is declared here (QByteArray out of readAll()/rawHeader(), QNetworkReply for qt()'s pointee). The other three follow ICoreProcess.h's rule and STAY: this header is in the umbrella too, ICoreUrl.h uses QNetworkRequest and QUrl without including either, and a surface row is not the place to find that out. See that header's note.
ICoreHttpRequest#
ICoreHttpClient.h:106 · class · pImpl · 13 declaration(s)
the request ------------------------------------------------------------
class ICoreHttpRequest {
public:
ICoreHttpRequest();
~ICoreHttpRequest();
// A request is a small value and WAS implicitly copyable (it held a
// QNetworkRequest, which is); a unique_ptr member deletes that, so the four
// are written out in the .cpp rather than silently narrowing the contract.
ICoreHttpRequest(const ICoreHttpRequest& other);
ICoreHttpRequest& operator=(const ICoreHttpRequest& other);
ICoreHttpRequest(ICoreHttpRequest&& other) noexcept;
ICoreHttpRequest& operator=(ICoreHttpRequest&& other) noexcept;
// ICoreUrl went Qt-free, so the parse happens in this wrapper now rather
// than being carried in. It is the layer's only remaining claimant of
// <QUrl>, and it is the right place for it: a QNetworkRequest is the one
// thing in the project that genuinely needs a parsed URL, and it is one
// line away -- a line that now sits in the .cpp.
// Was url.text(), a private by-reference accessor reached through
// friendship. H2.17 put ICoreUrl's text behind an Impl and deleted both;
// toString() is the same value, one ICoreString copy dearer.
void setUrl(const ICoreUrl& url);
// The text of the URL. See the design note on why this is not an ICoreUrl.
ICoreString url() const;
// Content-Type. Named rather than enumerated -- see the narrowing note.
void setContentType(const ICoreString& type);
ICoreString contentType() const;
void setRawHeader(const ICoreByteArray& name, const ICoreByteArray& value);
// Returns QByteArray still: return-position Qt is row X7's catalog, not
// Q4.2's. The PARAMETER is what stopped teaching callers to name Qt.
QByteArray rawHeader(const ICoreByteArray& name) const;
// INACTIVITY timeout, not a total-request cap: Qt restarts it whenever
// bytes arrive. The one caller depends on that distinction -- a long
// agentic turn streams for minutes and a total cap would kill it mid-answer.
void setTransferTimeout(int msecs);
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreHttpReply#
ICoreHttpClient.h:158 · class · pImpl · 13 declaration(s)
the reply --------------------------------------------------------------
class ICoreHttpReply {
public:
// Deletes the reply unless deleteLater() already released it -- B7's
// ICoreProcess destructor, for the same reason.
~ICoreHttpReply();
// Owns an in-flight request; copying one is meaningless and nothing moves
// one, so both are deleted rather than defined.
ICoreHttpReply(const ICoreHttpReply&) = delete;
ICoreHttpReply& operator=(const ICoreHttpReply&) = delete;
QByteArray readAll();
// Drives finished(). Cancellation goes through here rather than through
// destruction, because the caller wants the settle handler to run.
void abort();
// See the narrowing note: the code itself is never read, only its presence
// and the message.
bool hasError() const;
ICoreString errorString() const;
// 0 when the response never got far enough to have one.
int httpStatus() const;
// Step one of the two-step -- see the ownership note. Releases the reply to
// the event loop and drops this wrapper's pointer, which is what makes
// destroying the wrapper from inside a signal handler safe.
void deleteLater();
// For connect() and disconnect() ONLY. See the first design note.
QNetworkReply* qt() const noexcept;
// --- asynchronous results (PHASE 2) -------------------------------------
//
// The same addition ICoreProcess just took, for the same reason: without
// it a caller cannot learn that bytes arrived except through qt(), and so
// has to keep a QObject base purely to be a connect context. Read that
// header's phase-2 note for the delivery argument -- it applies verbatim,
// with the reply as its own context object, so handlers still run
// synchronously inside the emission on the reply's own thread.
//
// Registering twice replaces rather than adds; these are callbacks.
// Bytes are available. Streaming callers read them with readAll() and may
// be called many times before onFinished.
void onReadyRead(std::function<void()> fn);
// The exchange is over -- successfully, in error, or because abort() was
// called. Ask hasError()/httpStatus() which of those it was.
void onFinished(std::function<void()> fn);
// Stop delivering, permanently. This is what a caller's old
// `qt()->disconnect(this)` meant, and it is safe to call from inside a
// handler -- which is exactly where the settle path calls it.
void clearCallbacks();
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreHttpClient#
ICoreHttpClient.h:230 · class · pImpl · 4 declaration(s)
the client -------------------------------------------------------------
class ICoreHttpClient {
public:
ICoreHttpClient();
~ICoreHttpClient();
// Holds an event-loop object; copying one is meaningless.
ICoreHttpClient(const ICoreHttpClient&) = delete;
ICoreHttpClient& operator=(const ICoreHttpClient&) = delete;
// The only verb the project uses. GET exists on QNetworkAccessManager and
// is deliberately absent here until something asks for it (Rule 3).
std::unique_ptr<ICoreHttpReply> post(const ICoreHttpRequest& request,
const ICoreByteArray& body);
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreTcpServer.h#
src/ICoreEssentials/Network/ICoreTcpServer.h
ICoreTcpServer -- the loopback listener. Task B15, 2026-08-07.
Wraps QTcpServer (and, by narrowing it away, QHostAddress) Call sites RunnerHttp.cpp (the G0 target), and nothing else Phase 3 POSIX sockets
DESIGN NOTES
- listenOnLoopback() DELETES ICoreHostAddress, and that is the row's headline
rather than a shortcut. QHostAddress appears exactly once in this project:
server_->listen(QHostAddress::LocalHost, port). So the wrapper the board asked for would have had one reachable value, and B4's QDate rule applies in its strongest form -- narrow to what the call site actually asks and a PLANNED wrapper is deleted rather than deferred. The placeholder
ICoreTcpServer#
ICoreTcpServer.h:63 · class · pImpl · 9 declaration(s)
class ICoreTcpServer {
public:
ICoreTcpServer();
// Takes every socket it accepted with it -- see the ownership note.
~ICoreTcpServer();
ICoreTcpServer(const ICoreTcpServer&) = delete;
ICoreTcpServer& operator=(const ICoreTcpServer&) = delete;
// Binds 127.0.0.1 on `port` (0 = let the OS choose). There is deliberately
// no way to bind anything else -- see the design note. `error` may be null.
bool listenOnLoopback(quint16 port, ICoreString* error);
// The bound port, valid after a successful listenOnLoopback().
[[nodiscard]] quint16 port() const;
[[nodiscard]] bool hasPendingConnections() const;
// A null handle when nothing is pending. The returned socket is owned by
// this server, not by the caller.
[[nodiscard]] ICoreTcpSocket nextPendingConnection();
// For connect() and disconnect() ONLY -- newConnection.
[[nodiscard]] QTcpServer* qt() const noexcept;
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreTcpSocket.h#
src/ICoreEssentials/Network/ICoreTcpSocket.h
ICoreTcpSocket -- one accepted connection. Task B15, 2026-08-07.
Wraps QTcpSocket, QAbstractSocket Call sites RunnerHttp.h/.cpp (the G0 target), and nothing else Phase 3 POSIX sockets
DESIGN NOTES
- A NON-OWNING VALUE HANDLE, deliberately, and this is the row's one real
decision. Every other QObject wrapper on this board (ICoreProcess B7, ICoreHttpReply B14) owns its object and is held by unique_ptr, because at those call sites the C++ owner and the Qt owner were the same object. Here they are not: RunnerHttp's sockets are owned by the QTcpServer through Qt parenting, and
delete server_is what takes the whole tree down. Its
ICoreTcpSocket#
ICoreTcpSocket.h:75 · class · pImpl · 15 declaration(s)
class ICoreTcpSocket {
public:
// A null handle. Exists because QList<ICoreTcpSocket> wants one and because
// nextPendingConnection() has to be able to say "nothing pending".
ICoreTcpSocket();
~ICoreTcpSocket();
// A HANDLE, copied by value into lambdas -- copying one aliases the same
// socket, it does not duplicate it. Written out because a unique_ptr<Impl>
// member deletes the implicit copy this type used to have.
ICoreTcpSocket(const ICoreTcpSocket& other);
ICoreTcpSocket& operator=(const ICoreTcpSocket& other);
[[nodiscard]] bool isNull() const noexcept;
// --- reading and writing -------------------------------------------------
QByteArray readAll();
qint64 write(const ICoreByteArray& data);
// Pushes what is buffered onto the wire now. The SSE stream depends on this:
// an event the page never sees until the next one arrives is a stalled UI.
void flush();
// --- state and teardown --------------------------------------------------
// See the narrowing note -- the full state machine is never inspected.
[[nodiscard]] bool isConnected() const;
void disconnectFromHost();
// Releases the socket to the event loop and nulls this handle. B7's
// two-step: the one call site does this from inside the socket's own
// disconnected() handler, where deleting it outright would be a crash.
void deleteLater();
// --- the parked request buffer -------------------------------------------
// Storage lives on the socket object, not in this handle, and must: the
// handle is a value that gets copied into lambdas, while the buffer has to
// survive between two readyRead deliveries on the same connection.
[[nodiscard]] QByteArray buffer() const;
void setBuffer(const ICoreByteArray& data);
void clearBuffer();
// --- the connect seam ----------------------------------------------------
// For connect() and disconnect() ONLY -- readyRead and disconnected.
[[nodiscard]] QTcpSocket* qt() const noexcept;
// Hidden friends: declared here so ADL finds them, DEFINED in the .cpp
// because a body in a header is a body wherever it sits.
friend bool operator==(const ICoreTcpSocket& a, const ICoreTcpSocket& b) noexcept;
friend bool operator!=(const ICoreTcpSocket& a, const ICoreTcpSocket& b) noexcept;
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreUrl.h#
src/ICoreEssentials/Network/ICoreUrl.h
ICoreUrl -- the address of a thing to fetch.
QT-FREE (phase 3). The member is the URL's text and this header names no Qt type; <QUrl> moves to ICoreHttpClient.h, which is where the QNetworkRequest that actually needs a parsed URL lives. It leaves the umbrella's prerequisite block either way.
B13 refused an
operator QUrland gave this wrapper only a NAMED toQUrl(), which is what made the swap possible: nothing outside the layer ever held the QUrl, so no call site could notice it leaving. toQUrl() had exactly one reader -- ICoreHttpRequest::setUrl -- and it now takes the text and parses it itself, one line away from the QNetworkRequest it was always feeding.⚠ WHAT THE CALL SITES ACTUALLY USE, measured before writing any of this, is
ICoreUrl#
ICoreUrl.h:65 · class · pImpl · 11 declaration(s)
class ICoreUrl {
public:
ICoreUrl();
~ICoreUrl();
// Explicit, as B13 made it: an implicit ICoreString -> ICoreUrl conversion
// would put this type into overload sets that take strings.
explicit ICoreUrl(const ICoreString& url);
// Copyable, as it always was -- a URL is a value. Written out because a
// unique_ptr<Impl> member deletes the implicit copy.
ICoreUrl(const ICoreUrl& other);
ICoreUrl& operator=(const ICoreUrl& other);
// Decodes %XX escapes and '+' is NOT treated as a space, matching
// QUrl::fromPercentEncoding. The runner's form parser splits on '&' and '='
// first and hands each half here, so a literal '+' in a value stays a '+'
// exactly as it did before.
//
// MALFORMED INPUT DIVERGES FROM Qt, deliberately, and this is the one
// place in the row where the two disagree on purpose.
//
// * A TRUNCATED tail -- "%", "%A", "x%", "%2" -- is copied through
// verbatim. This IS Qt's behaviour; verified.
// * A three-character escape with NON-HEX digits is also copied through
// verbatim here. Qt does something else: its decoder runs the hex
// conversion anyway and emits whatever byte falls out, so "%GG" decodes
// to 'w' and "%ZZ" to U+FFFD. That is undocumented garbage-in,
// garbage-out, not a contract, and reproducing it would mean copying an
// internal quirk on purpose.
//
// Safe for the one caller: the runner's query parser reads percent-encoding
// a browser generated, which is always well formed. On input that is not,
// the old code produced mojibake and this produces the text as typed.
[[nodiscard]] static ICoreString fromPercentEncoding(const ICoreByteArray& encoded);
// See the header note: this is a shape check, not QUrl::isValid.
[[nodiscard]] bool isValid() const;
[[nodiscard]] bool isEmpty() const;
[[nodiscard]] ICoreString toString() const;
[[nodiscard]] ICoreString scheme() const;
// The authority's host, with any userinfo and port stripped. IPv6 literals
// keep their brackets, as QUrl::host does not -- one of several places this
// is a simplification rather than a reimplementation. See the header note.
[[nodiscard]] ICoreString host() const;
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};