You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fixed
Retries never fired for an upstream without an explicit method: - retry_on_statuses/timeout retries were
silently a no-op for the common case of relying on the flow's own method. shouldRetry judged idempotency against
the raw (often empty) config value instead of the effective method used for the actual request. (The 0.9.0 entry
below describing this as fixed was itself wrong: the switch cases changed, but the call site never did.)
The TE response header was never stripped despite being listed in the hop-by-hop set - the map key was the literal
string "TE", but net/http always stores and iterates response headers in net/textproto canonical form, which
for TE is Te (no hyphen to separate words, so only the first letter is capitalized). The lookup silently missed
every time, leaking the header to the client. Every other entry in that set was already canonical.
policy.header_blacklist entries were matched by exact string, not canonicalized - header_blacklist: ["x-secret"]
silently never blocked a response header that net/http (correctly) stores as X-Secret. Same root cause as the TE fix above: HTTP header names are case-insensitive, but the code was comparing them as case-sensitive strings.
Changed
Breaking: flow option passthrough renamed to streaming (config field, OpenAPI x-aastro extension, and aastroctl openapi import --mode). Existing configs and specs must rename passthrough: true to streaming: true
before upgrading.
Breaking: a flow with exactly one upstream is no longer wrapped in the JSON response envelope. Its upstream's
status, headers, and body are now forwarded to the client as-is - on success, and on a client error or redirect
(2xx/3xx/4xx), including bodies that aren't valid JSON, which previously got swallowed into an UPSTREAM_CLIENT_ERROR/UPSTREAM_REDIRECT envelope. Only a genuine gateway-side failure (upstream unavailable,
5xx, timeout, policy violation) still returns a gateway-authored error body - see the envelope removal entry
below for its current shape, which by the end of this release also covers multi-upstream flows. Single-upstream
flows are now handled by their own dispatch path, bypassing the scatter/aggregate machinery entirely - see Router.dispatch/Router.buildProxyResponse.
aggregation is no longer required for a single-upstream flow, since it's never read for one - only a flow with
more than one upstream must declare it (config validation enforces this in place of the old struct-tag check).
aastroctl openapi import --mode envelope renamed to --mode proxy, matching the response shape above; scaffolded
(single-upstream) flows no longer get a meaningless aggregation: {strategy: array} block.
Internal: the several independent switch statements over the upstream error classification (retry eligibility,
circuit breaker signal, policy applicability, client error code) were consolidated into one table
(kindTable in upstream_error.go), checked exhaustive at startup. Not user-facing, but worth knowing if you're
extending upstream error handling: add the new kind's row there rather than hunting down every switch.
Breaking: the {"data": ..., "errors": ..., "meta": ...} envelope is gone entirely, including for
multi-upstream (aggregating) flows - a client no longer unwraps a gateway-specific shape to get at the payload:
A full or partial (206, bestEffort) success returns the aggregated data itself as the body - exactly the merge/array/namespace result, nothing wrapping it. Which upstreams failed on a partial success moves to
the X-Partial-Errors response header (one value per failure, e.g. UPSTREAM_UNAVAILABLE) instead of an errors body field.
A response with no data at all - every upstream failed, or the request was rejected before reaching one
(rate limit, payload too large, plugin failure, single-upstream gateway failure) - is now an RFC 9457 Problem Details document (application/problem+json): {"type": "about:blank", "title", "status", "detail"?, "errors": [...]}. type is always the literal "about:blank" - RFC 9457's own placeholder for "no further-specific type" - never a real URI, deliberately:
a dereferencable type link is reconnaissance, since it names the gateway software fronting the request and
invites probing for what that implies about the backend. errors is the machine-readable discriminator instead
(always present, one entry per distinct underlying ClientError - more than one only for a multi-upstream
failure with several different causes); title is a human summary of the highest-priority one and may change
wording over time. ClientResponse/ResponseMeta are removed from the Go API; WriteError and the
OpenAPI-generated schemas both moved to ProblemDetails.
Request correlation is unaffected by this - it was already carried solely by the X-Request-ID response
header, never duplicated into a body field.
Breaking / security fix:builtin/middlewares/auth's default realm - sent in the WWW-Authenticate header on
every 401 the gateway itself returns - changed from "aastro" to "restricted". Scope note: this is about the
gateway's own runtime response to a client. OpenAPI export output and anything that only affects tracing/metrics
(e.g. gateway.service.name) are a separate concern, owned by whoever runs and publishes them - not touched here.