The consumed-stream retry guard treated any read of a streaming request
body as consumption. Go's transport probes unknown-length bodies of GET,
HEAD, and similar requests before sending them, and HTTP/3 reports
bodyless GET and HEAD requests with an unknown length, so every such
request lost its retries once an upstream connection was established.
A first read that returns io.EOF without data no longer counts as
consumption. Later attempts send http.NoBody, while bodies that yield
data, fail, or are interrupted mid-read remain non-retryable.
Follow-up to de1bcf6d-457c-4348-9d4e-5eeb41cc120b.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Follow up report dff6e149-9cd3-47fb-8e21-b4d3d4bad807: make AST handling exhaustive and preallocate map entries. Verify regex and URL-pattern factories do not expand runtime env/file placeholders while preserving their existing pattern grammar and static behavior.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix report dff6e149-9cd3-47fb-8e21-b4d3d4bad807 by retaining string provenance through CEL matcher factories. Runtime strings must not become templates or globs on a second pass; static leaves retain their existing matcher syntax and caching.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reject opaque HTTP request targets before either normal or error routes can interpret them. Clear URL.Opaque defensively on proxy clones. Verify HTTP/1 parsing, path authentication, supported target forms and outbound serialization without contacting an upstream.
Addresses scan report e17d2fcd-d50c-4d68-82d1-96519a437a24.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Follow up report de1bcf6d-457c-4348-9d4e-5eeb41cc120b. Expect one transport attempt for consumed partial streams while keeping unread dial retries and fully buffered trailer replay covered.
Validated the entire reverseproxy package with offline race-short tests in a loopback-only network namespace.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix report de1bcf6d-457c-4348-9d4e-5eeb41cc120b. Release pooled buffers exactly once, serialize reads with release, and retain safe replay cursors for fully buffered requests. Retire each stream attempt so consumed bodies cannot be retried while unread dial failures remain retryable.
Add deterministic concurrent ownership checks, boundary coverage, local transport failure cases, and synthetic canary tests.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The old expected JSON captured the handler-dropping bug. Keep invoke and the following response in each named route, matching the corrected adapter.
Regression fixture for scan report 99a222bd-3c1e-4096-b94d-43076920963c.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apply the existing header-alias rules before method and host validation, so early errors cannot carry spoofed identity aliases into user-defined error routes. Verify all early error paths with synthetic authentication headers.
Addresses scan report 3ebe3dfa-8541-44a7-8f1f-cd5071d55a67. The supplied checker has a malformed Authorization header; regression tests use independently constructed requests.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Canonicalize the path before capturing and substituting its components, not only afterward. Retain repeated slashes, query strings and valid alternate encodings; cover the supplied depth-changing traversal and encoded dot segments.
Addresses scan report 34013c71-0786-4179-8403-eacc143a1d89 (marked duplicate, but not fixed by the prior post-replacement safeguard).
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Expand only known placeholders in TLS regexp patterns, matching HTTP regexp behavior. Test numeric quantifiers and selection of the client-certificate-verifying fallback policy.
Addresses scan report b6c9c0a1-79a7-4254-b057-b1d8fc96b412.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Share the adaptation group counter with named-route extraction because group satisfaction is request-wide. Cover nested invoke and handle_path while retaining sibling exclusivity.
Addresses scan report fb62a11d-5561-49e3-87df-c175ea5a1f4d.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Retain the complete matcherless route instead of only its first handler. Verify header and authentication ordering with authorized and unauthorized requests without starting a server.
Addresses scan report 99a222bd-3c1e-4096-b94d-43076920963c.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use filepath.Rel rather than prefix trimming for both existing and fallback candidates. Preserve dotfiles and directory suffixes, and always expose a slash-prefixed path so rewrites and downstream path guards agree.
Addresses scan report 3188624e-2157-49e6-b3e0-8c5049b72269.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Policy subjects and handshake names were compared without the IDNA
Lookup normalization CertMagic applies to SNI, so a Unicode or mapped
SNI could select the fallback issuer. Normalize both the same way,
preserving wildcard labels and non-DNS subjects.
Addresses scan report e804f22226c85b87.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
An empty on_demand object with no permission module caused a nil
dereference during the handshake. Treat it like absent permission
settings.
Addresses scan report 01e4330f22e4a986.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
For wildcard or default policies with explicit certificate managers but
no on-demand permission module, a manager miss fell through to issuance
for any client-chosen SNI. Fail closed after managers are consulted.
Addresses scan report a6eb136fbbaa01c0.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The http CA pool's tls.server_name was never applied, so the endpoint
was verified against the URL host instead. Use the configured name,
including placeholders.
Addresses scan report 8b7d4c9c392321ab.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Callbacks registered with OnCancel were appended to a copy of the
Context and never ran on config unload, so e.g. the std log redirect to
a removed sink was never undone. Share callbacks across copies of a
Context so they run exactly once on cancellation; callbacks registered
after cancellation run immediately, and OnCancel on a zero-value
Context remains safe.
Since overlapping configs mean an old config's cleanup runs after the
new one is set up, track ownership of the default logger and std log
redirect so cleanup restores the most recent live config's state.
Addresses scan report 88637e95bf243f5a.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The hash, ip_mask, regexp and multi_regexp filters only handled
LoggableStringArray, so typed string, IP and URI slices (such as TLS
client certificate SANs) bypassed them. Filter those and string array
marshalers too, without mutating the source slices.
Addresses scan report 26365d1881c34ded.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Lowercasing and slash-preserving path cleaning rewrote invalid UTF-8
bytes as U+FFFD, so the path matcher could evaluate a different path
than the file server opens. Preserve the original bytes in both, keeping
case-insensitive matching for valid Unicode.
Addresses scan report 18c02f60a5b43529.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When an escape sequence was followed by a wildcard in the pattern, the
path cursor had already skipped to the last hex digit, so an encoded
slash could be swallowed into the wildcard span. Advance the cursor by
the escape width only when the character is consumed.
Addresses scan report 0e63a0fe7fea5ef7.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Decoded path placeholders (orig_uri.path, path components and file
matcher values) were inserted raw into the rewritten URI, so an
encoded '%' or '?' could be decoded a second time. Escape all decoded
path placeholders in path context in a single replacement pass; escaped
and whole-URI placeholders keep their URI syntax.
Addresses scan report 9e3a082391f793d1.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Like prefix/suffix stripping, substring and regexp path replacement can
produce a relative path or expose dot segments that later path-scoped
handlers interpret differently. Apply the existing canonicalizePath
safeguard whenever these operations change the path.
Addresses scan report 65568b0d767b733c.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
With per_host metrics, HTTPS servers automatically observed catch-all
hosts, and port/case variants of configured hosts produced distinct
labels. Require explicit observe_catchall_hosts for unconfigured hosts,
normalize the host label, and also collect hosts from subroutes, error
routes and named routes (scanned after handlers are provisioned).
Behavior change: unconfigured hosts on HTTPS servers are now labeled
"_other" unless observe_catchall_hosts is enabled.
Addresses scan report 457dcf090b421495.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A placeholder-dependent search_regexp was recompiled for every matching
header value. Compile it once per replacement operation, keep skipping
invalid expanded expressions, and merge the duplicated "*" code path.
Addresses scan report 6c26a7b4c2e5ddc3.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Failed comparisons for missing accounts all used the same fake hash, so
their cached results returned quickly while failures for real accounts
did not, leaking which usernames exist. Cache only successful
comparisons and scope cache keys to the username.
Addresses scan report 430e037dbf6a4fd3.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reject absolute, non-canonical, traversing or platform-unsafe keys and
non-regular entries (links, devices, FIFOs) before writing to storage,
so importing an untrusted archive cannot write outside the storage root.
Directory entries are skipped and a single leading "./" is removed, so
archives created with tar(1) from a storage directory still import.
Addresses scan report 89de9a51d786c23e.
Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
With the Go 1.26 floor, golangci-lint's modernize analyzer (errorsastype)
flags the three errors.As calls that look for RequestBodyLimitError, which
turned the Lint workflow red on master after #8056. Replace them with the
generic errors.AsType; behavior is unchanged.
Assistance disclosure: this change was made by an AI agent (Claude Sonnet
5.5, model ID claude-sonnet-5-5) acting as Matthew Holt's agent and under
his approval. Build, go vet and the caddyhttp and caddyhttp/templates tests
pass locally; golangci-lint itself was not run locally.
Co-authored-by: Claude Code <noreply@anthropic.com>
* reverseproxy: Add ability to clear dynamic upstreams cache during retries
This is an optional interface for dynamic upstream modules to implement if they cache results.
TODO: More documentation; this is an experiment.
* Add some godoc
* Export interface; update godoc
Simplify what versions are supported, clarify our policy for unreleased code (or beta code), and expand our AI policy to require a disclosure in ALL cases, even if AI is not used. As well as an invitation to share in some chocolate milk with us if you're human.
* cmd: Pass configFile, not configFlag, for reload command
This *should* fix#7528.
* Remove debug log line
---------
Co-authored-by: Francis Lavoie <lavofr@gmail.com>
Necessary as otherwise the early-bail in `until =
strings.IndexByte(remaining, nextCh) ... if until == -1` can cause a
case-insensitive mismatch
Co-authored-by: Asim Viladi Oglu Manizada <manizada@users.noreply.github.com>
If global DNS provider is configured, it does not need to be repeated in the JSON.
If acme_* options are used, base automation policies should populate their issuers accordingly.
Global issuer settings like acme_* options don't need to specify subjects in the automation policy since they should apply as a global default.