Reconcile close reason tracking: feature branch's MarkClosed() and
ShouldSkipFlush/FlushAndCloseAsync now use main's ClientClosedReason
enum. ClosedState enum retained for forward compatibility.
Reject connections that send no_responders:true without headers:true,
since the 503 HMSG response requires header support. Add three tests:
connection rejection, acceptance with headers, and 503 delivery flow.
When a client sends CONNECT {"verbose":true}, the server now responds
with +OK\r\n after successfully processing CONNECT, PING, SUB, UNSUB,
and PUB/HPUB commands, matching the Go NATS server behavior.
Verify channel-based write loop behavior: QueueOutbound writes data
to client socket, PendingBytes tracking, slow consumer detection
when MaxPending is exceeded, close reason propagation, and server
stats incrementation on slow consumer events.
- Make ConnectReceived thread-safe with Volatile.Read/Write (accessed from auth timeout task and command pipeline)
- Include authTimeoutTask in Task.WhenAny to propagate exceptions
- Clear nonce after authentication with CryptographicOperations.ZeroMemory
- Avoid closure allocation on publish permission cache hot path (method group)
- Update AuthTimeout default to 2s to match Go server
Fix NKey nonce verification: the NATS client signs the nonce string
(ASCII bytes of the base64url-encoded nonce), not the raw nonce bytes.
Pass the encoded nonce string bytes to the authenticator for verification.
Subscriptions and message routing now go through account-specific SubLists
instead of a single global SubList. Clients in different accounts cannot
see each other's messages. When no account is specified (or auth is not
configured), all clients share the global $G account.
Wire AuthService into NatsServer and NatsClient to enforce authentication
on incoming connections. The server builds an AuthService from NatsOptions,
sets auth_required in ServerInfo, and generates per-client nonces when
NKey auth is configured. NatsClient validates credentials in ProcessConnect,
enforces publish/subscribe permissions, and implements an auth timeout that
closes connections that don't send CONNECT in time. Existing tests without
auth continue to work since AuthService.IsAuthRequired is false by default.
Add TlsMixedModeTests verifying that a server with AllowNonTls=true
accepts both plaintext and TLS clients on the same port. Add
MonitorTlsTests verifying that /connz reports TlsVersion and
TlsCipherSuite for TLS-connected clients.
Integrate TLS support into the server's connection accept path:
- Add SslServerAuthenticationOptions and TlsRateLimiter fields to NatsServer
- Extract AcceptClientAsync method for TLS negotiation, rate limiting, and
TLS state extraction (protocol version, cipher suite, peer certificate)
- Add InfoAlreadySent flag to NatsClient to skip redundant INFO when
TlsConnectionWrapper already sent it during negotiation
- Add TlsServerTests verifying TLS connect+INFO and TLS pub/sub
Move max payload validation from the parser to ProcessPubAsync so the
server sends -ERR 'Maximum Payload Violation' and closes the connection
(matching Go reference client.go:2442). In pedantic mode, reject PUB
with wildcard subjects via -ERR 'Invalid Publish Subject' (client.go:2869).
Add disposed guard to SubList.Remove to prevent crash during shutdown.
Replace empty catch blocks with meaningful log statements in NatsServer,
NatsClient, and Program. Add WaitForReadyAsync() to NatsServer for
deterministic server startup. Replace Task.Delay/Thread.Sleep in tests
with PING/PONG protocol flush and SubscribeCoreAsync for reliable
subscription synchronization.
Remove template UnitTest1.cs placeholder. Add actual project structure,
run commands for the NATS server host, and update test command examples
to reference the real project paths.
Validates the server against the official NATS .NET client library with
tests for basic pub/sub, wildcard (* and >) matching, fan-out to
multiple subscribers, and PING/PONG keepalive. All 5 tests pass without
requiring any server changes.
Add NatsParser that reads NATS protocol commands from
ReadOnlySequence<byte>. Identifies commands by first 2 bytes using
case-insensitive bit masking. Handles PUB/HPUB payload reading with
stateful _awaitingPayload for split-packet scenarios. Uses Span<Range>
for zero-allocation argument splitting and ParseSize for ASCII decimal
parsing. Includes CommandType enum, ParsedCommand struct, and
ProtocolViolationException.
14 tests covering PING, PONG, CONNECT, INFO, SUB (with/without queue),
UNSUB (with/without max), PUB (with/without reply, zero payload),
HPUB, multiple commands, and case insensitivity.