The README and the consumer notes say that a reply sent on a stream let
go just before deleting the connection still arrives, and the agent
notes add the gotcha with the test that guards it, and count 39 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README's QUIC section gains receiving by callback: a server
answering one request per stream with a size cap enforced by Abort,
the threads the callbacks run on, what they may call, and the
std::stop_callback rule for destroying the wrapper; its follower
example now drops a lagging peer with Abort rather than a graceful
Stop. The consumer notes give the full contract, the weak_ptr idiom for
reaching a stream from its own callbacks, and list the callbacks among
what runs on msquic's workers; the agent notes count the new test,
describe the per-stream delivery in the partition list, and add the
callbacks to the worker-thread gotcha.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README's QUIC section shows sending without a thread: what onSent's
true and false mean, the thread it runs on and what that forbids, and
BytesInFlight as the way to drop a follower that cannot keep up. The
consumer notes give the full contract, take SendAsync out of the list
of what goes through the pool (but for a send msquic never took) and
into what runs on msquic's workers; the agent notes count the new test
and add onSent to the callbacks that really do run on the worker.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README's QUIC section gains how to own accepted connections: the
OnClosed callback, the thread it runs on, what not to do in it and the
std::stop_callback rule that makes deleting a connection under a lock
its callback takes a deadlock. The consumer notes give the same
contract with the map-under-a-mutex pattern for a server that also
deletes on shutdown, list OnClosed among what runs on msquic's workers
rather than the pool, say that ~ClientQUIC now waits up to 1 s so the
peer hears the close, and that SendSync throws only for its own send.
The agent notes count the three new tests, add OnClosed's thread and
the destructor's new wait to the gotchas, and the forking tests and
their alarm() watchdog to the testing conventions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README's self-signed section, its dependency list, the consumer
notes and the agent notes described the openssl CLI and the shared
/tmp/crafter-network-quic-cert/. They now give the per-user location
and its fallbacks, the day-before-expiry rollover (which is when a
pinned hash changes), what keeps processes that start together on one
pair, and that nothing has to be installed. The agent notes' dev
environment says where the Flatpak keeps the certificate between runs,
drops the two gotchas the move resolved (the CLI, and the comments in
-ListenerQUIC.cpp and ClientQUIC.cppm that disagreed with the code),
and notes the module-internal functions :TLS declares for the listener.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README's QUIC section and the consumer notes show the new
constructor and say what binding an address means under msquic: the UDP
port is bound on every address anyway, and a connection sent to another
one is refused during its first flight (0x5c, in milliseconds), so a
client of a 127.0.0.1 listener dials 127.0.0.1, not `localhost`. The
agent notes' family gotcha says the same and counts the new test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README gains a QUIC section, which it never had: plain QUIC under an
ALPN of your own, starting with a listener on port 0 and Port(). The
consumer notes describe Port() and point tests at port 0 rather than at
binding a socket by hand; the agent notes count the new test and make
port 0 the default for a new one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One request to an http(s) URL with redirects followed by RFC 9110 §15.4:
301, 302, 303, 307 and 308 for every method; a 303 makes the request a
GET without its body and content headers, a 301 or 302 does so for a POST
alone, a 307 or 308 keeps the method and the body. The Location is
resolved against the sending URL by RFC 3986, a hop between http and
https is allowed, Authorization, Proxy-Authorization and Cookie are
dropped on a change of origin, and each hop is a client of its own, since
one ClientHTTP1 is one origin. A redirect without a usable Location, to
another scheme, back to a URL already visited or past maxRedirects comes
back as the response, with `stop` saying why.
The new :URL partition is the URL type behind it, exported: Parse,
Resolve (RFC 3986 §5.2; its §5.4 examples are the test), ToString, and
the pieces a request is built from.
This replaces the FetchHTTP1 free function, which followed redirects the
way Python's urllib did (its repeat limit, its quoting of the Location, a
POST turned back on a 307) for a port that no longer needs the fidelity.
Breaking: FetchHTTP1, FetchOptionsHTTP1 and FetchResultHTTP1 are gone;
use ClientHTTP1::Fetch, FetchOptions and FetchResult, whose `url` is a
URL and whose `limited` became `stop`.
SocketErrorException is now a std::system_error: code() carries the errno
under std::generic_category(), or getaddrinfo's result under the new
ResolverCategory(), whose message() is gai_strerror's text; `phase` says
which step failed (resolve, open, connect, send, receive). It is still a
std::runtime_error with the message ClientTCP always threw, the code's
text after it, so existing handlers keep working.
Before, the exception carried a `kind` and an int, and a caller that had
to print the cause its own way still had to match the message prefix to
learn where the failure happened. The standard type ends both: the
category knows how to print the number, and the phase is a field. A
caller writes "[Errno {}] {}" from code().value() and code().message(),
or compares code() with std::errc::connection_refused.
Breaking: SocketErrorException's `kind` and `code` members are gone;
read code().category() and code().value().
AGENTS.template.md holds the notes for working on Crafter.Network itself.
crafter-build 4.0.0 writes AGENTS.md from it on every build and test run,
with the notes of each dependency that ships some merged in, so AGENTS.md
is build output and gitignored. AGENTS.consumer.md holds the notes for
agents working in a project that depends on this library; crafter-build
merges it into that project's AGENTS.md, as the Crafter.Build README's
"Dependency notes for agents" describes.
Both were written from the interfaces, implementations, tests and
project.cpp rather than from the README. Where a comment in the sources
disagrees with the code (the HTTP3 header, the -fno-exceptions remarks,
"on the msquic worker", OpenStream(true) "throws", the QUIC certificate's
location and validity), the notes follow the code and list the comment
as a gotcha.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>