mirror of
https://github.com/cloudflare/cloudflared.git
synced 2026-08-07 07:14:57 +00:00
chore: Bump go-chi to version 5.3.1
This commit is contained in:
@@ -10,7 +10,7 @@ require (
|
||||
github.com/fortytw2/leaktest v1.3.0
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/getsentry/sentry-go v0.43.0
|
||||
github.com/go-chi/chi/v5 v5.2.2
|
||||
github.com/go-chi/chi/v5 v5.3.1
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-jose/go-jose/v4 v4.1.4
|
||||
github.com/gobwas/ws v1.2.1
|
||||
|
||||
@@ -54,8 +54,8 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
|
||||
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-chi/chi/v5 v5.3.1 h1:3j4HZLGZQ3JpMCrPJF/Jl3mYJfWLKBfNJ6quurUGCf8=
|
||||
github.com/go-chi/chi/v5 v5.3.1/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
|
||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
|
||||
+69
-2
@@ -87,7 +87,7 @@ func main() {
|
||||
|
||||
// A good base middleware stack
|
||||
r.Use(middleware.RequestID)
|
||||
r.Use(middleware.RealIP)
|
||||
r.Use(middleware.ClientIPFromRemoteAddr) // pick one ClientIPFrom* based on your infra, see below
|
||||
r.Use(middleware.Logger)
|
||||
r.Use(middleware.Recoverer)
|
||||
|
||||
@@ -221,6 +221,7 @@ type Router interface {
|
||||
Patch(pattern string, h http.HandlerFunc)
|
||||
Post(pattern string, h http.HandlerFunc)
|
||||
Put(pattern string, h http.HandlerFunc)
|
||||
Query(pattern string, h http.HandlerFunc)
|
||||
Trace(pattern string, h http.HandlerFunc)
|
||||
|
||||
// NotFound defines a handler to respond whenever a route could
|
||||
@@ -349,7 +350,11 @@ with `net/http` can be used with chi's mux.
|
||||
| [Logger] | Logs the start and end of each request with the elapsed processing time |
|
||||
| [NoCache] | Sets response headers to prevent clients from caching |
|
||||
| [Profiler] | Easily attach net/http/pprof to your routers |
|
||||
| [RealIP] | Sets a http.Request's RemoteAddr to either X-Real-IP or X-Forwarded-For |
|
||||
| [ClientIPFromHeader] | Capture client IP from a trusted single-IP header (X-Real-IP, CF-Connecting-IP, ...) |
|
||||
| [ClientIPFromXFF] | Capture client IP from X-Forwarded-For, skipping listed trusted CIDR prefixes |
|
||||
| [ClientIPFromXFFTrustedProxies] | Capture client IP from X-Forwarded-For given a fixed number of trusted proxies |
|
||||
| [ClientIPFromRemoteAddr] | Capture client IP from the TCP RemoteAddr (server directly on the public internet) |
|
||||
| [RealIP] | Deprecated — vulnerable to IP spoofing; use [ClientIPFromXFF] or another ClientIPFrom\* middleware |
|
||||
| [Recoverer] | Gracefully absorb panics and prints the stack trace |
|
||||
| [RequestID] | Injects a request ID into the context of each request |
|
||||
| [RedirectSlashes] | Redirect slashes on routing paths |
|
||||
@@ -375,6 +380,12 @@ with `net/http` can be used with chi's mux.
|
||||
[Logger]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Logger
|
||||
[NoCache]: https://pkg.go.dev/github.com/go-chi/chi/middleware#NoCache
|
||||
[Profiler]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Profiler
|
||||
[ClientIPFromHeader]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ClientIPFromHeader
|
||||
[ClientIPFromXFF]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ClientIPFromXFF
|
||||
[ClientIPFromXFFTrustedProxies]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ClientIPFromXFFTrustedProxies
|
||||
[ClientIPFromRemoteAddr]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ClientIPFromRemoteAddr
|
||||
[GetClientIP]: https://pkg.go.dev/github.com/go-chi/chi/middleware#GetClientIP
|
||||
[GetClientIPAddr]: https://pkg.go.dev/github.com/go-chi/chi/middleware#GetClientIPAddr
|
||||
[RealIP]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RealIP
|
||||
[Recoverer]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Recoverer
|
||||
[RedirectSlashes]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RedirectSlashes
|
||||
@@ -402,6 +413,62 @@ with `net/http` can be used with chi's mux.
|
||||
[ThrottleOpts]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ThrottleOpts
|
||||
[WrapResponseWriter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#WrapResponseWriter
|
||||
|
||||
### Choosing a ClientIP middleware
|
||||
|
||||
The legacy [RealIP] middleware is deprecated — it is vulnerable to IP spoofing
|
||||
(GHSA-3fxj-6jh8-hvhx, GHSA-rjr7-jggh-pgcp, GHSA-9g5q-2w5x-hmxf) and mutates
|
||||
`r.RemoteAddr`. Use one of the four `ClientIPFrom*` middlewares instead — pick
|
||||
exactly one based on your network setup — and read the resulting IP with
|
||||
[GetClientIP] (string) or [GetClientIPAddr] (`netip.Addr`):
|
||||
|
||||
| Your setup | Use |
|
||||
|---|---|
|
||||
| Directly on the public internet, no proxy | `middleware.ClientIPFromRemoteAddr` |
|
||||
| Behind nginx (`X-Real-IP`), Cloudflare (`CF-Connecting-IP`), Apache (`X-Client-IP`) | `middleware.ClientIPFromHeader("<your-trusted-header>")` |
|
||||
| Behind one or more proxies whose IP ranges you can list | `middleware.ClientIPFromXFF("10.0.0.0/8", ...)` |
|
||||
| Behind a known, fixed number of proxies with dynamic IPs | `middleware.ClientIPFromXFFTrustedProxies(2)` |
|
||||
|
||||
```go
|
||||
r := chi.NewRouter()
|
||||
r.Use(middleware.RequestID)
|
||||
|
||||
// Pick exactly one. Examples for common deployments:
|
||||
|
||||
// Direct internet exposure (no proxy):
|
||||
// r.Use(middleware.ClientIPFromRemoteAddr)
|
||||
|
||||
// Behind Cloudflare:
|
||||
// r.Use(middleware.ClientIPFromHeader("CF-Connecting-IP"))
|
||||
|
||||
// Behind AWS CloudFront (or any proxy fleet with known CIDRs):
|
||||
r.Use(middleware.ClientIPFromXFF(
|
||||
"13.32.0.0/15", // CloudFront IPv4
|
||||
"52.46.0.0/18", // CloudFront IPv4
|
||||
"2600:9000::/28", // CloudFront IPv6
|
||||
))
|
||||
|
||||
// Behind a known number of proxies with dynamic IPs:
|
||||
// r.Use(middleware.ClientIPFromXFFTrustedProxies(2))
|
||||
|
||||
r.Use(middleware.Logger)
|
||||
r.Use(middleware.Recoverer)
|
||||
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
clientIP := middleware.GetClientIP(r.Context()) // for logs, rate-limit keys, etc.
|
||||
_ = clientIP
|
||||
})
|
||||
```
|
||||
|
||||
These middlewares never mutate `r.RemoteAddr`. They store a normalized
|
||||
`netip.Addr` in the request context — IPv4-mapped IPv6 (`::ffff:a.b.c.d`)
|
||||
is folded to plain IPv4, and IPv6 zone identifiers carried in headers are
|
||||
stripped, so one logical client maps to a single canonical key for logs,
|
||||
rate limits, and ACLs.
|
||||
|
||||
See the per-function godoc for the full semantics of each middleware, and
|
||||
[adam-p's "The perils of the 'real' client IP"](https://adam-p.ca/blog/2022/03/x-forwarded-for/)
|
||||
for the underlying threat model.
|
||||
|
||||
### Extra middlewares & packages
|
||||
|
||||
Please see https://github.com/go-chi for additional packages.
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
// Package chi is a small, idiomatic and composable router for building HTTP services.
|
||||
//
|
||||
// chi requires Go 1.14 or newer.
|
||||
// chi supports the four most recent major versions of Go.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
@@ -77,7 +77,7 @@ type Router interface {
|
||||
// path, with a fresh middleware stack for the inline-Router.
|
||||
Group(fn func(r Router)) Router
|
||||
|
||||
// Route mounts a sub-Router along a `pattern`` string.
|
||||
// Route mounts a sub-Router along a `pattern` string.
|
||||
Route(pattern string, fn func(r Router)) Router
|
||||
|
||||
// Mount attaches another http.Handler along ./pattern/*
|
||||
@@ -102,6 +102,7 @@ type Router interface {
|
||||
Patch(pattern string, h http.HandlerFunc)
|
||||
Post(pattern string, h http.HandlerFunc)
|
||||
Put(pattern string, h http.HandlerFunc)
|
||||
Query(pattern string, h http.HandlerFunc)
|
||||
Trace(pattern string, h http.HandlerFunc)
|
||||
|
||||
// NotFound defines a handler to respond whenever a route could
|
||||
|
||||
+5
-4
@@ -133,11 +133,12 @@ func (x *Context) RoutePattern() string {
|
||||
return routePattern
|
||||
}
|
||||
|
||||
// replaceWildcards takes a route pattern and recursively replaces all
|
||||
// occurrences of "/*/" to "/".
|
||||
// replaceWildcards takes a route pattern and replaces all occurrences of
|
||||
// "/*/" with "/". It iteratively runs until no wildcards remain to
|
||||
// correctly handle consecutive wildcards.
|
||||
func replaceWildcards(p string) string {
|
||||
if strings.Contains(p, "/*/") {
|
||||
return replaceWildcards(strings.Replace(p, "/*/", "/", -1))
|
||||
for strings.Contains(p, "/*/") {
|
||||
p = strings.ReplaceAll(p, "/*/", "/")
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
+14
-9
@@ -107,7 +107,8 @@ func (mx *Mux) Use(middlewares ...func(http.Handler) http.Handler) {
|
||||
// Handle adds the route `pattern` that matches any http method to
|
||||
// execute the `handler` http.Handler.
|
||||
func (mx *Mux) Handle(pattern string, handler http.Handler) {
|
||||
if method, rest, found := strings.Cut(pattern, " "); found {
|
||||
if i := strings.IndexAny(pattern, " \t"); i >= 0 {
|
||||
method, rest := pattern[:i], strings.TrimLeft(pattern[i+1:], " \t")
|
||||
mx.Method(method, rest, handler)
|
||||
return
|
||||
}
|
||||
@@ -118,12 +119,7 @@ func (mx *Mux) Handle(pattern string, handler http.Handler) {
|
||||
// HandleFunc adds the route `pattern` that matches any http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) HandleFunc(pattern string, handlerFn http.HandlerFunc) {
|
||||
if method, rest, found := strings.Cut(pattern, " "); found {
|
||||
mx.Method(method, rest, handlerFn)
|
||||
return
|
||||
}
|
||||
|
||||
mx.handle(mALL, pattern, handlerFn)
|
||||
mx.Handle(pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Method adds the route `pattern` that matches `method` http method to
|
||||
@@ -190,6 +186,12 @@ func (mx *Mux) Put(pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.handle(mPUT, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Query adds the route `pattern` that matches a QUERY http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) Query(pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.handle(mQUERY, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Trace adds the route `pattern` that matches a TRACE http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) Trace(pattern string, handlerFn http.HandlerFunc) {
|
||||
@@ -471,9 +473,12 @@ func (mx *Mux) routeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Find the route
|
||||
if _, _, h := mx.tree.FindRoute(rctx, method, routePath); h != nil {
|
||||
if supportsPathValue {
|
||||
setPathValue(rctx, r)
|
||||
// Set http.Request path values from our request context
|
||||
for i, key := range rctx.URLParams.Keys {
|
||||
value := rctx.URLParams.Values[i]
|
||||
r.SetPathValue(key, value)
|
||||
}
|
||||
r.Pattern = rctx.RoutePattern()
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
return
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
//go:build go1.22 && !tinygo
|
||||
// +build go1.22,!tinygo
|
||||
|
||||
|
||||
package chi
|
||||
|
||||
import "net/http"
|
||||
|
||||
// supportsPathValue is true if the Go version is 1.22 and above.
|
||||
//
|
||||
// If this is true, `net/http.Request` has methods `SetPathValue` and `PathValue`.
|
||||
const supportsPathValue = true
|
||||
|
||||
// setPathValue sets the path values in the Request value
|
||||
// based on the provided request context.
|
||||
func setPathValue(rctx *Context, r *http.Request) {
|
||||
for i, key := range rctx.URLParams.Keys {
|
||||
value := rctx.URLParams.Values[i]
|
||||
r.SetPathValue(key, value)
|
||||
}
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
//go:build !go1.22 || tinygo
|
||||
// +build !go1.22 tinygo
|
||||
|
||||
package chi
|
||||
|
||||
import "net/http"
|
||||
|
||||
// supportsPathValue is true if the Go version is 1.22 and above.
|
||||
//
|
||||
// If this is true, `net/http.Request` has methods `SetPathValue` and `PathValue`.
|
||||
const supportsPathValue = false
|
||||
|
||||
// setPathValue sets the path values in the Request value
|
||||
// based on the provided request context.
|
||||
//
|
||||
// setPathValue is only supported in Go 1.22 and above so
|
||||
// this is just a blank function so that it compiles.
|
||||
func setPathValue(rctx *Context, r *http.Request) {
|
||||
}
|
||||
+27
-32
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -25,11 +26,17 @@ const (
|
||||
mPATCH
|
||||
mPOST
|
||||
mPUT
|
||||
mQUERY
|
||||
mTRACE
|
||||
)
|
||||
|
||||
var mALL = mCONNECT | mDELETE | mGET | mHEAD |
|
||||
mOPTIONS | mPATCH | mPOST | mPUT | mTRACE
|
||||
mOPTIONS | mPATCH | mPOST | mPUT | mQUERY | mTRACE
|
||||
|
||||
// methodQuery is the HTTP QUERY method (RFC 10008), a safe, idempotent
|
||||
// method that conveys a request body. It is defined here until net/http
|
||||
// provides an equivalent constant, at which point this is a 1-1 swap.
|
||||
const methodQuery = "QUERY"
|
||||
|
||||
var methodMap = map[string]methodTyp{
|
||||
http.MethodConnect: mCONNECT,
|
||||
@@ -40,6 +47,7 @@ var methodMap = map[string]methodTyp{
|
||||
http.MethodPatch: mPATCH,
|
||||
http.MethodPost: mPOST,
|
||||
http.MethodPut: mPUT,
|
||||
methodQuery: mQUERY,
|
||||
http.MethodTrace: mTRACE,
|
||||
}
|
||||
|
||||
@@ -52,6 +60,7 @@ var reverseMethodMap = map[methodTyp]string{
|
||||
mPATCH: http.MethodPatch,
|
||||
mPOST: http.MethodPost,
|
||||
mPUT: http.MethodPut,
|
||||
mQUERY: methodQuery,
|
||||
mTRACE: http.MethodTrace,
|
||||
}
|
||||
|
||||
@@ -71,6 +80,7 @@ func RegisterMethod(method string) {
|
||||
}
|
||||
mt := methodTyp(2 << n)
|
||||
methodMap[method] = mt
|
||||
reverseMethodMap[mt] = method
|
||||
mALL |= mt
|
||||
}
|
||||
|
||||
@@ -328,7 +338,7 @@ func (n *node) replaceChild(label, tail byte, child *node) {
|
||||
|
||||
func (n *node) getEdge(ntyp nodeTyp, label, tail byte, prefix string) *node {
|
||||
nds := n.children[ntyp]
|
||||
for i := 0; i < len(nds); i++ {
|
||||
for i := range nds {
|
||||
if nds[i].label == label && nds[i].tail == tail {
|
||||
if ntyp == ntRegexp && nds[i].prefix != prefix {
|
||||
continue
|
||||
@@ -429,9 +439,7 @@ func (n *node) findRoute(rctx *Context, method methodTyp, path string) *node {
|
||||
}
|
||||
|
||||
// serially loop through each node grouped by the tail delimiter
|
||||
for idx := 0; idx < len(nds); idx++ {
|
||||
xn = nds[idx]
|
||||
|
||||
for _, xn = range nds {
|
||||
// label for param nodes is the delimiter byte
|
||||
p := strings.IndexByte(xsearch, xn.tail)
|
||||
|
||||
@@ -650,11 +658,9 @@ func (n *node) routes() []Route {
|
||||
if h.handler == nil {
|
||||
continue
|
||||
}
|
||||
m := methodTypString(mt)
|
||||
if m == "" {
|
||||
continue
|
||||
if m, ok := reverseMethodMap[mt]; ok {
|
||||
hs[m] = h.handler
|
||||
}
|
||||
hs[m] = h.handler
|
||||
}
|
||||
|
||||
rt := Route{subroutes, hs, p}
|
||||
@@ -772,29 +778,14 @@ func patParamKeys(pattern string) []string {
|
||||
}
|
||||
}
|
||||
|
||||
// longestPrefix finds the length of the shared prefix
|
||||
// of two strings
|
||||
func longestPrefix(k1, k2 string) int {
|
||||
max := len(k1)
|
||||
if l := len(k2); l < max {
|
||||
max = l
|
||||
}
|
||||
var i int
|
||||
for i = 0; i < max; i++ {
|
||||
// longestPrefix finds the length of the shared prefix of two strings
|
||||
func longestPrefix(k1, k2 string) (i int) {
|
||||
for i = 0; i < min(len(k1), len(k2)); i++ {
|
||||
if k1[i] != k2[i] {
|
||||
break
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func methodTypString(method methodTyp) string {
|
||||
for s, t := range methodMap {
|
||||
if method == t {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
return
|
||||
}
|
||||
|
||||
type nodes []*node
|
||||
@@ -854,11 +845,15 @@ func Walk(r Routes, walkFn WalkFunc) error {
|
||||
|
||||
func walk(r Routes, walkFn WalkFunc, parentRoute string, parentMw ...func(http.Handler) http.Handler) error {
|
||||
for _, route := range r.Routes() {
|
||||
mws := make([]func(http.Handler) http.Handler, len(parentMw))
|
||||
copy(mws, parentMw)
|
||||
mws = append(mws, r.Middlewares()...)
|
||||
mws := slices.Concat(parentMw, r.Middlewares())
|
||||
|
||||
if route.SubRoutes != nil {
|
||||
if handler, ok := route.Handlers["*"]; ok {
|
||||
if chain, ok := handler.(*ChainHandler); ok {
|
||||
mws = append(mws, chain.Middlewares...)
|
||||
}
|
||||
}
|
||||
|
||||
if err := walk(route.SubRoutes, walkFn, parentRoute+route.Pattern, mws...); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -872,7 +867,7 @@ func walk(r Routes, walkFn WalkFunc, parentRoute string, parentMw ...func(http.H
|
||||
}
|
||||
|
||||
fullRoute := parentRoute + route.Pattern
|
||||
fullRoute = strings.Replace(fullRoute, "/*/", "/", -1)
|
||||
fullRoute = strings.ReplaceAll(fullRoute, "/*/", "/")
|
||||
|
||||
if chain, ok := handler.(*ChainHandler); ok {
|
||||
if err := walkFn(method, fullRoute, chain.Endpoint, append(mws, chain.Middlewares...)...); err != nil {
|
||||
|
||||
Vendored
+2
-2
@@ -64,8 +64,8 @@ github.com/getsentry/sentry-go/internal/telemetry
|
||||
github.com/getsentry/sentry-go/internal/util
|
||||
# github.com/gin-gonic/gin v1.9.1
|
||||
## explicit; go 1.20
|
||||
# github.com/go-chi/chi/v5 v5.2.2
|
||||
## explicit; go 1.20
|
||||
# github.com/go-chi/chi/v5 v5.3.1
|
||||
## explicit; go 1.23
|
||||
github.com/go-chi/chi/v5
|
||||
# github.com/go-chi/cors v1.2.1
|
||||
## explicit; go 1.14
|
||||
|
||||
Reference in New Issue
Block a user