Skip to content

fix: throttle before auth, plugin request fields, bounded metrics label, host parsing - #271

Merged
umputun merged 3 commits into
masterfrom
fix-plugin-throttle-metrics
Oct 31, 2026
Merged

umputun merged 3 commits into
masterfrom
fix-plugin-throttle-metrics

Conversation

@umputun

@umputun umputun commented Oct 31, 2026

Copy link
Copy Markdown
Owner

the rest of the sweep after #270: request handling where reproxy layers read the same request differently, each reproduced on a live build before the fix.

  • throttle before auth: rate limits ran after global and per-route basic auth, so requests with wrong credentials never counted. With --throttle.user=2, six rapid bad-password requests got six 401s; now the third one gets 429
  • plugin request: plugins got the client's path spelling, an empty Host for ordinary requests and X-Real-IP as the client sent it. A plugin rejecting /fail let /%66ail through, and the request reached the upstream despite the plugin restriction. Plugins now get the canonical path, the request host, and X-Real-IP resolved through --trusted-proxy. RemoteAddr stays the TCP peer
  • metrics label: with --mgmt.low-cardinality the server label of http_requests_total still took the raw Host, so each new Host value added a series. It is now the matched route's server, or [unmatched]
  • host parsing: the port was cut with a split on :, so [::1]:8080 became [ and missed a ::1 rule. All server name lookups now go through discovery.HostName(r.Host), which unwraps bracketed IPv6 and otherwise cuts at the first colon. That also closes an absolute-form bypass on master: GET foo://a.wild.example:1:2/x kept a.wild.example:1, missed its wildcard server and reached the catch-all route without its auth

README notes cover the plugin request fields, limits counting failed logins, and the low-cardinality server label.

…trics server label

rate limits ran after global and per-route basic auth, so requests with
wrong credentials never counted and password guessing was unlimited. The
limiters now run right after the IP allowlist.

plugins got the client's raw path spelling, an empty Host for ordinary
origin-form requests and the X-Real-IP header as the client sent it. A plugin rejecting /fail let
/%66ail through to the upstream as /fail, and could be fed any client
address. Plugins now get the canonical path, the request host, and
X-Real-IP resolved through --trusted-proxy.

with --mgmt.low-cardinality the server label still took the raw Host, so
each new Host value added a series. It now uses the matched route's
server, or [unmatched].

the host port was cut with a split on ":", which turned [::1]:8080 into
"[" in route matching and metrics. It is now parsed with url.URL.
url.URL.Hostname strips a port only when it is all digits, so a Host like
ADMIN.example.com:x or a.example.com:x kept the suffix and missed its exact
and wildcard servers. The request fell through to a catch-all route and
skipped the narrower rule's auth and allowlist. Route matching, the plugin
Host field and the metrics server label now share discovery.HostName,
which cuts at the first colon as before and only unwraps bracketed IPv6.

the README plugin intro no longer calls the plugin URL the original one.
route matching preferred r.URL.Hostname for absolute-form targets. For a
non-http scheme Go splits that host at the last colon, so
GET foo://a.wild.example:1:2/x gave "a.wild.example:1", missed its
wildcard server and reached the catch-all without that rule's auth. Go's
server already copies the target's host into r.Host, so route matching,
the health-check forwarding lookup, the plugin Host and the metrics server
label now all use discovery.HostName(r.Host). The health-check lookup also
stops turning [::1] into "[".
Copilot AI balanced review requested due to automatic review settings October 31, 2026 08:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@umputun
umputun merged commit b8bf877 into master Oct 31, 2026
4 checks passed
@umputun
umputun deleted the fix-plugin-throttle-metrics branch October 31, 2026 08:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants