Bump github.com/go-chi/chi/v5 from 5.1.0 to 5.2.0
Bumps [github.com/go-chi/chi/v5](https://github.com/go-chi/chi) from 5.1.0 to 5.2.0. - [Release notes](https://github.com/go-chi/chi/releases) - [Changelog](https://github.com/go-chi/chi/blob/master/CHANGELOG.md) - [Commits](https://github.com/go-chi/chi/compare/v5.1.0...v5.2.0) --- updated-dependencies: - dependency-name: github.com/go-chi/chi/v5 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
+3
-2
@@ -65,7 +65,7 @@ func main() {
|
||||
|
||||
**REST Preview:**
|
||||
|
||||
Here is a little preview of how routing looks like with chi. Also take a look at the generated routing docs
|
||||
Here is a little preview of what routing looks like with chi. Also take a look at the generated routing docs
|
||||
in JSON ([routes.json](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.json)) and in
|
||||
Markdown ([routes.md](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.md)).
|
||||
|
||||
@@ -469,7 +469,8 @@ how setting context on a request in Go works.
|
||||
|
||||
* Carl Jackson for https://github.com/zenazn/goji
|
||||
* Parts of chi's thinking comes from goji, and chi's middleware package
|
||||
sources from goji.
|
||||
sources from [goji](https://github.com/zenazn/goji/tree/master/web/middleware).
|
||||
* Please see goji's [LICENSE](https://github.com/zenazn/goji/blob/master/LICENSE) (MIT)
|
||||
* Armon Dadgar for https://github.com/armon/go-radix
|
||||
* Contributions: [@VojtechVitek](https://github.com/VojtechVitek)
|
||||
|
||||
|
||||
+5
-1
@@ -51,7 +51,7 @@
|
||||
// "/user/{name}" matches "/user/jsmith" but not "/user/jsmith/info" or "/user/jsmith/"
|
||||
// "/user/{name}/info" matches "/user/jsmith/info"
|
||||
// "/page/*" matches "/page/intro/latest"
|
||||
// "/page/{other}/index" also matches "/page/intro/latest"
|
||||
// "/page/{other}/latest" also matches "/page/intro/latest"
|
||||
// "/date/{yyyy:\\d\\d\\d\\d}/{mm:\\d\\d}/{dd:\\d\\d}" matches "/date/2017/04/01"
|
||||
package chi
|
||||
|
||||
@@ -127,6 +127,10 @@ type Routes interface {
|
||||
// the method/path - similar to routing a http request, but without
|
||||
// executing the handler thereafter.
|
||||
Match(rctx *Context, method, path string) bool
|
||||
|
||||
// Find searches the routing tree for the pattern that matches
|
||||
// the method/path.
|
||||
Find(rctx *Context, method, path string) string
|
||||
}
|
||||
|
||||
// Middlewares type is a slice of standard middleware handlers with methods
|
||||
|
||||
+4
-1
@@ -109,7 +109,7 @@ func (x *Context) URLParam(key string) string {
|
||||
// RoutePattern builds the routing pattern string for the particular
|
||||
// request, at the particular point during routing. This means, the value
|
||||
// will change throughout the execution of a request in a router. That is
|
||||
// why its advised to only use this value after calling the next handler.
|
||||
// why it's advised to only use this value after calling the next handler.
|
||||
//
|
||||
// For example,
|
||||
//
|
||||
@@ -121,6 +121,9 @@ func (x *Context) URLParam(key string) string {
|
||||
// })
|
||||
// }
|
||||
func (x *Context) RoutePattern() string {
|
||||
if x == nil {
|
||||
return ""
|
||||
}
|
||||
routePattern := strings.Join(x.RoutePatterns, "")
|
||||
routePattern = replaceWildcards(routePattern)
|
||||
if routePattern != "/" {
|
||||
|
||||
+9
-13
@@ -6,36 +6,32 @@ import (
|
||||
)
|
||||
|
||||
// SetHeader is a convenience handler to set a response header key/value
|
||||
func SetHeader(key, value string) func(next http.Handler) http.Handler {
|
||||
func SetHeader(key, value string) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set(key, value)
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// AllowContentType enforces a whitelist of request Content-Types otherwise responds
|
||||
// with a 415 Unsupported Media Type status.
|
||||
func AllowContentType(contentTypes ...string) func(next http.Handler) http.Handler {
|
||||
func AllowContentType(contentTypes ...string) func(http.Handler) http.Handler {
|
||||
allowedContentTypes := make(map[string]struct{}, len(contentTypes))
|
||||
for _, ctype := range contentTypes {
|
||||
allowedContentTypes[strings.TrimSpace(strings.ToLower(ctype))] = struct{}{}
|
||||
}
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.ContentLength == 0 {
|
||||
// skip check for empty content body
|
||||
// Skip check for empty content body
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
s := strings.ToLower(strings.TrimSpace(r.Header.Get("Content-Type")))
|
||||
if i := strings.Index(s, ";"); i > -1 {
|
||||
s = s[0:i]
|
||||
}
|
||||
s := strings.ToLower(strings.TrimSpace(strings.Split(r.Header.Get("Content-Type"), ";")[0]))
|
||||
|
||||
if _, ok := allowedContentTypes[s]; ok {
|
||||
next.ServeHTTP(w, r)
|
||||
@@ -43,7 +39,7 @@ func AllowContentType(contentTypes ...string) func(next http.Handler) http.Handl
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusUnsupportedMediaType)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -60,3 +60,11 @@ func RedirectSlashes(next http.Handler) http.Handler {
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
// StripPrefix is a middleware that will strip the provided prefix from the
|
||||
// request path before handing the request over to the next handler.
|
||||
func StripPrefix(prefix string) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.StripPrefix(prefix, next)
|
||||
}
|
||||
}
|
||||
|
||||
+14
-6
@@ -22,11 +22,12 @@ type ThrottleOpts struct {
|
||||
Limit int
|
||||
BacklogLimit int
|
||||
BacklogTimeout time.Duration
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
// Throttle is a middleware that limits number of currently processed requests
|
||||
// at a time across all users. Note: Throttle is not a rate-limiter per user,
|
||||
// instead it just puts a ceiling on the number of currently in-flight requests
|
||||
// instead it just puts a ceiling on the number of current in-flight requests
|
||||
// being processed from the point from where the Throttle middleware is mounted.
|
||||
func Throttle(limit int) func(http.Handler) http.Handler {
|
||||
return ThrottleWithOpts(ThrottleOpts{Limit: limit, BacklogTimeout: defaultBacklogTimeout})
|
||||
@@ -49,10 +50,16 @@ func ThrottleWithOpts(opts ThrottleOpts) func(http.Handler) http.Handler {
|
||||
panic("chi/middleware: Throttle expects backlogLimit to be positive")
|
||||
}
|
||||
|
||||
statusCode := opts.StatusCode
|
||||
if statusCode == 0 {
|
||||
statusCode = http.StatusTooManyRequests
|
||||
}
|
||||
|
||||
t := throttler{
|
||||
tokens: make(chan token, opts.Limit),
|
||||
backlogTokens: make(chan token, opts.Limit+opts.BacklogLimit),
|
||||
backlogTimeout: opts.BacklogTimeout,
|
||||
statusCode: statusCode,
|
||||
retryAfterFn: opts.RetryAfterFn,
|
||||
}
|
||||
|
||||
@@ -72,7 +79,7 @@ func ThrottleWithOpts(opts ThrottleOpts) func(http.Handler) http.Handler {
|
||||
|
||||
case <-ctx.Done():
|
||||
t.setRetryAfterHeaderIfNeeded(w, true)
|
||||
http.Error(w, errContextCanceled, http.StatusTooManyRequests)
|
||||
http.Error(w, errContextCanceled, t.statusCode)
|
||||
return
|
||||
|
||||
case btok := <-t.backlogTokens:
|
||||
@@ -85,12 +92,12 @@ func ThrottleWithOpts(opts ThrottleOpts) func(http.Handler) http.Handler {
|
||||
select {
|
||||
case <-timer.C:
|
||||
t.setRetryAfterHeaderIfNeeded(w, false)
|
||||
http.Error(w, errTimedOut, http.StatusTooManyRequests)
|
||||
http.Error(w, errTimedOut, t.statusCode)
|
||||
return
|
||||
case <-ctx.Done():
|
||||
timer.Stop()
|
||||
t.setRetryAfterHeaderIfNeeded(w, true)
|
||||
http.Error(w, errContextCanceled, http.StatusTooManyRequests)
|
||||
http.Error(w, errContextCanceled, t.statusCode)
|
||||
return
|
||||
case tok := <-t.tokens:
|
||||
defer func() {
|
||||
@@ -103,7 +110,7 @@ func ThrottleWithOpts(opts ThrottleOpts) func(http.Handler) http.Handler {
|
||||
|
||||
default:
|
||||
t.setRetryAfterHeaderIfNeeded(w, false)
|
||||
http.Error(w, errCapacityExceeded, http.StatusTooManyRequests)
|
||||
http.Error(w, errCapacityExceeded, t.statusCode)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -119,8 +126,9 @@ type token struct{}
|
||||
type throttler struct {
|
||||
tokens chan token
|
||||
backlogTokens chan token
|
||||
retryAfterFn func(ctxDone bool) time.Duration
|
||||
backlogTimeout time.Duration
|
||||
statusCode int
|
||||
retryAfterFn func(ctxDone bool) time.Duration
|
||||
}
|
||||
|
||||
// setRetryAfterHeaderIfNeeded sets Retry-After HTTP header if corresponding retryAfterFn option of throttler is initialized.
|
||||
|
||||
+5
-1
@@ -81,7 +81,11 @@ type basicWriter struct {
|
||||
}
|
||||
|
||||
func (b *basicWriter) WriteHeader(code int) {
|
||||
if !b.wroteHeader {
|
||||
if code >= 100 && code <= 199 && code != http.StatusSwitchingProtocols {
|
||||
if !b.discard {
|
||||
b.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
} else if !b.wroteHeader {
|
||||
b.code = code
|
||||
b.wroteHeader = true
|
||||
if !b.discard {
|
||||
|
||||
+26
-5
@@ -363,19 +363,40 @@ func (mx *Mux) Middlewares() Middlewares {
|
||||
// Note: the *Context state is updated during execution, so manage
|
||||
// the state carefully or make a NewRouteContext().
|
||||
func (mx *Mux) Match(rctx *Context, method, path string) bool {
|
||||
return mx.Find(rctx, method, path) != ""
|
||||
}
|
||||
|
||||
// Find searches the routing tree for the pattern that matches
|
||||
// the method/path.
|
||||
//
|
||||
// Note: the *Context state is updated during execution, so manage
|
||||
// the state carefully or make a NewRouteContext().
|
||||
func (mx *Mux) Find(rctx *Context, method, path string) string {
|
||||
m, ok := methodMap[method]
|
||||
if !ok {
|
||||
return false
|
||||
return ""
|
||||
}
|
||||
|
||||
node, _, h := mx.tree.FindRoute(rctx, m, path)
|
||||
node, _, _ := mx.tree.FindRoute(rctx, m, path)
|
||||
pattern := rctx.routePattern
|
||||
|
||||
if node != nil {
|
||||
if node.subroutes == nil {
|
||||
e := node.endpoints[m]
|
||||
return e.pattern
|
||||
}
|
||||
|
||||
if node != nil && node.subroutes != nil {
|
||||
rctx.RoutePath = mx.nextRoutePath(rctx)
|
||||
return node.subroutes.Match(rctx, method, rctx.RoutePath)
|
||||
subPattern := node.subroutes.Find(rctx, method, rctx.RoutePath)
|
||||
if subPattern == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
pattern = strings.TrimSuffix(pattern, "/*")
|
||||
pattern += subPattern
|
||||
}
|
||||
|
||||
return h != nil
|
||||
return pattern
|
||||
}
|
||||
|
||||
// NotFoundHandler returns the default Mux 404 responder whenever a route
|
||||
|
||||
Reference in New Issue
Block a user