Document RateLimit's RemoteAddr-by-default keying and WithTrustedProxies, and
that WithMaxResponseBody returns ErrResponseTooLarge rather than truncating.
BearerAuth, BasicAuth and DefaultHeaders mutated the caller's request, which
violates the RoundTripper contract and risks races on shared/retried requests;
clone before writing headers (matching RequestID). Validate the incoming
X-Request-Id (length and character set) before propagating it to logs and the
response header, preventing log forging and header splitting from a
client-controlled value.
A malformed endpoint URL panicked inside Transport, crashing the host app
(often at startup from external config). Capture the parse error and surface
it from the transport on first use instead. Add the previously untested
HealthChecker coverage (initial probe, recovery, Stop termination, unknown
endpoint), raising balancer coverage from ~41% to ~87%. Default the health
probe path to /healthz to match this library's own server.
The Open->HalfOpen promotion used time.Now/time.Since directly, forcing tests
to use real time.Sleep and diverging from the project's clock convention. Add
an unexported withClock option (default clock.System) and replace the real
sleeps in tests with mock-clock Advance, making the transitions deterministic
and the package faster.
Gate the retry decision on body rewindability: an idempotent request whose
body cannot be replayed (no GetBody) is now returned as-is instead of looping
with an empty body or surfacing a stale, already-drained response. Guard
ExponentialBackoff against rand.Int64N panicking when delay/2 rounds to zero.
Use internal/clock for inter-attempt delays so retry timing is consistent with
the rest of the codebase and testable without real sleeps.
WithMaxResponseBody wrapped the body in io.LimitedReader, which returns EOF
at the cap, so Bytes/JSON/XML silently returned a truncated body with a nil
error despite the documented contract. Read one byte past the limit and
return the new ErrResponseTooLarge sentinel when exceeded; bodies exactly at
the limit still succeed.
Key on RemoteAddr by default; honor X-Forwarded-For only when the peer is
a configured trusted proxy (WithTrustedProxies), walking right-to-left to
the first untrusted hop. This closes a trivial rate-limit bypass and the
matching unbounded-bucket DoS via spoofed headers. Add WithMaxKeys with
opportunistic eviction of idle (fully-refilled) buckets to bound memory.
Drop the hand-rolled indexOf in favor of stdlib.
golang.org/x/mod/zip is a library, not a CLI tool. Use git archive
with --prefix to create the module zip in the format Gitea expects.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Publishes the module to Gitea Package Registry on tag push (v*).
Runs vet and tests before publishing to prevent broken releases.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
README: add PATCH, NewFormRequest, CORS, RateLimit, MaxBodySize,
Timeout, WriteJSON/WriteError, request ID propagation, response body
limit, and custom 404 handler examples. CLAUDE.md: document new
architecture details for all added components.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wraps response body with io.LimitedReader when configured, preventing
unbounded reads from io.ReadAll in Response.Bytes(). Protects against
upstream services returning unexpectedly large responses.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces internal/requestid package with shared context key to avoid
circular imports between server and middleware packages. Server's
RequestID middleware now uses the shared key. Client middleware picks up
the ID from context and sets X-Request-Id on outgoing requests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Protects against abuse with configurable rate/burst per client IP.
Supports custom key functions, X-Forwarded-For extraction, and
Retry-After headers on 429 responses. Uses internal/clock for
testability.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wraps http.TimeoutHandler to return 503 when handlers exceed the
configured duration. Unlike http.Server.WriteTimeout, this allows
handlers to complete gracefully via context cancellation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wraps request body with http.MaxBytesReader to limit incoming payload
size. Without this, any endpoint accepting a body is vulnerable to
large uploads consuming all available memory.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Creates requests with application/x-www-form-urlencoded body from
url.Values. Supports GetBody for retry compatibility, following the
same pattern as NewJSONRequest.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Follows the same pattern as Put/Post, accepting context, URL, and body.
Closes an obvious gap in the REST client API.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add server package description, component table, and usage example to
README. Document server architecture, middleware chain, and test
conventions in CLAUDE.md.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cover edge cases: statusWriter multi-call/default/unwrap, UUID v4 format
and uniqueness, non-string panics, recovery body and log attributes,
4xx log level, default status in logging, request ID propagation,
server defaults/options/listen-error/multiple-hooks/logger, router
groups with empty prefix/inherited middleware/ordering/path params/
isolation, mount trailing slash, health content-type and POST rejection.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces server/ sub-package as the server-side companion to the existing Client.
Includes Router (over http.ServeMux with groups and mounting), graceful shutdown with
signal handling, health endpoints (/healthz, /readyz), and built-in middlewares
(RequestID, Recovery, Logging). Zero external dependencies.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Deduplicate sentinel errors: httpx.ErrNoHealthy, ErrCircuitOpen, and
ErrRetryExhausted are now aliases to the canonical sub-package values
so errors.Is works across package boundaries
- Retry transport returns ErrRetryExhausted only when all attempts are
actually exhausted, not on early policy exit
- Balancer: pre-parse endpoint URLs at construction, replace req.Clone
with cheap shallow struct copy to avoid per-request allocations
- Circuit breaker: Load before LoadOrStore to avoid allocating a Breaker
on every request for known hosts
- Health checker: drain response body before close for connection reuse,
probe endpoints concurrently, run initial probe synchronously in Start
- Client: add Close() to shut down health checker goroutine, propagate
URL resolution errors instead of silently discarding them
- MockClock: fix lock ordering in Reset (clock.mu before t.mu), fix
timer slice compaction to avoid backing-array aliasing, extract
fireExpired to deduplicate Advance/Set
Implements the top-level httpx.Client that composes the full chain:
Logging → User Middlewares → Retry → Circuit Breaker → Balancer → Transport
- Response wrapper with JSON/XML/Bytes decoding and body caching
- NewJSONRequest helper with Content-Type and GetBody support
- Functional options: WithBaseURL, WithTimeout, WithRetry, WithEndpoints, etc.
- Integration tests covering retry, balancing, error mapping, and JSON round-trips
Implements balancer middleware with URL rewriting per-request:
- RoundRobin, Failover, and WeightedRandom endpoint selection strategies
- Background HealthChecker with configurable probe interval and path
- Thread-safe health state tracking with sync.RWMutex
Implements circuit breaker as a RoundTripper middleware:
- Closed → Open after consecutive failure threshold
- Open → HalfOpen after configurable duration
- HalfOpen → Closed on success, back to Open on failure
- Per-host tracking via sync.Map for independent endpoint isolation
Implements retry middleware as a RoundTripper wrapper:
- Exponential and constant backoff strategies with jitter
- RFC 7231 Retry-After header parsing (seconds and HTTP-date)
- Default policy retries idempotent methods on 429/5xx and network errors
- Body restoration via GetBody, context cancellation, response body cleanup
Introduce the core building blocks for the httpx library:
- middleware.Middleware type and Chain() composer
- Error struct with sentinel errors (ErrRetryExhausted, ErrCircuitOpen, ErrNoHealthy)
- internal/clock package with Clock interface and MockClock for deterministic testing