summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/labstack/echo
diff options
context:
space:
mode:
authorWim <wim@42.be>2021-05-30 00:25:30 +0200
committerGitHub <noreply@github.com>2021-05-30 00:25:30 +0200
commit4091b6f6b4fe01876f8720332675f9c69be39541 (patch)
tree07a1f2b2eeba6fb680b5edc19d2d38ec81243c0a /vendor/github.com/labstack/echo
parent766f35554e16ee5462370be714ef29b71745d478 (diff)
downloadmatterbridge-msglm-4091b6f6b4fe01876f8720332675f9c69be39541.tar.gz
matterbridge-msglm-4091b6f6b4fe01876f8720332675f9c69be39541.tar.bz2
matterbridge-msglm-4091b6f6b4fe01876f8720332675f9c69be39541.zip
Update vendor (#1498)
Diffstat (limited to 'vendor/github.com/labstack/echo')
-rw-r--r--vendor/github.com/labstack/echo/v4/CHANGELOG.md30
-rw-r--r--vendor/github.com/labstack/echo/v4/LICENSE2
-rw-r--r--vendor/github.com/labstack/echo/v4/bind.go9
-rw-r--r--vendor/github.com/labstack/echo/v4/echo.go2
-rw-r--r--vendor/github.com/labstack/echo/v4/go.mod10
-rw-r--r--vendor/github.com/labstack/echo/v4/go.sum36
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/csrf.go2
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/csrf_samesite.go12
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/csrf_samesite_1.12.go12
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/jwt.go108
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/key_auth.go13
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/proxy.go37
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/proxy_1_11.go47
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/proxy_1_11_n.go14
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/static.go80
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/timeout.go11
-rw-r--r--vendor/github.com/labstack/echo/v4/router.go113
17 files changed, 339 insertions, 199 deletions
diff --git a/vendor/github.com/labstack/echo/v4/CHANGELOG.md b/vendor/github.com/labstack/echo/v4/CHANGELOG.md
index c1be77a9..f4a74760 100644
--- a/vendor/github.com/labstack/echo/v4/CHANGELOG.md
+++ b/vendor/github.com/labstack/echo/v4/CHANGELOG.md
@@ -1,6 +1,30 @@
# Changelog
-## v4.2.2 - 2020-04-07
+## v4.3.0 - 2021-05-08
+
+**Important notes**
+
+* Route matching has improvements for following cases:
+ 1. Correctly match routes with parameter part as last part of route (with trailing backslash)
+ 2. Considering handlers when resolving routes and search for matching http method handler
+* Echo minimal Go version is now 1.13.
+
+**Fixes**
+
+* When url ends with slash first param route is the match [#1804](https://github.com/labstack/echo/pull/1812)
+* Router should check if node is suitable as matching route by path+method and if not then continue search in tree [#1808](https://github.com/labstack/echo/issues/1808)
+* Fix timeout middleware not writing response correctly when handler panics [#1864](https://github.com/labstack/echo/pull/1864)
+* Fix binder not working with embedded pointer structs [#1861](https://github.com/labstack/echo/pull/1861)
+* Add Go 1.16 to CI and drop 1.12 specific code [#1850](https://github.com/labstack/echo/pull/1850)
+
+**Enhancements**
+
+* Make KeyFunc public in JWT middleware [#1756](https://github.com/labstack/echo/pull/1756)
+* Add support for optional filesystem to the static middleware [#1797](https://github.com/labstack/echo/pull/1797)
+* Add a custom error handler to key-auth middleware [#1847](https://github.com/labstack/echo/pull/1847)
+* Allow JWT token to be looked up from multiple sources [#1845](https://github.com/labstack/echo/pull/1845)
+
+## v4.2.2 - 2021-04-07
**Fixes**
@@ -10,7 +34,7 @@
* Fix panic in redirect middleware on short host name (#1813)
* Fix timeout middleware docs (#1836)
-## v4.2.1 - 2020-03-08
+## v4.2.1 - 2021-03-08
**Important notes**
@@ -32,7 +56,7 @@ A performance regression has been fixed, even bringing better performance than b
This release was made possible by our **contributors**:
aldas, clwluvw, lammel, Le0tk0k, maciej-jezierski, rkilingr, stffabi, withshubh
-## v4.2.0 - 2020-02-11
+## v4.2.0 - 2021-02-11
**Important notes**
diff --git a/vendor/github.com/labstack/echo/v4/LICENSE b/vendor/github.com/labstack/echo/v4/LICENSE
index b5b006b4..c46d0105 100644
--- a/vendor/github.com/labstack/echo/v4/LICENSE
+++ b/vendor/github.com/labstack/echo/v4/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2017 LabStack
+Copyright (c) 2021 LabStack
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/vendor/github.com/labstack/echo/v4/bind.go b/vendor/github.com/labstack/echo/v4/bind.go
index 08d39891..dfdf82d0 100644
--- a/vendor/github.com/labstack/echo/v4/bind.go
+++ b/vendor/github.com/labstack/echo/v4/bind.go
@@ -144,11 +144,20 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
for i := 0; i < typ.NumField(); i++ {
typeField := typ.Field(i)
structField := val.Field(i)
+ if typeField.Anonymous {
+ if structField.Kind() == reflect.Ptr {
+ structField = structField.Elem()
+ }
+ }
if !structField.CanSet() {
continue
}
structFieldKind := structField.Kind()
inputFieldName := typeField.Tag.Get(tag)
+ if typeField.Anonymous && structField.Kind() == reflect.Struct && inputFieldName != "" {
+ // if anonymous struct with query/param/form tags, report an error
+ return errors.New("query/param/form tags are not allowed with anonymous struct field")
+ }
if inputFieldName == "" {
// If tag is nil, we inspect if the field is a not BindUnmarshaler struct and try to bind data into it (might contains fields with tags).
diff --git a/vendor/github.com/labstack/echo/v4/echo.go b/vendor/github.com/labstack/echo/v4/echo.go
index a24e3977..dd0cbf35 100644
--- a/vendor/github.com/labstack/echo/v4/echo.go
+++ b/vendor/github.com/labstack/echo/v4/echo.go
@@ -234,7 +234,7 @@ const (
const (
// Version of Echo
- Version = "4.2.2"
+ Version = "4.3.0"
website = "https://echo.labstack.com"
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
banner = `
diff --git a/vendor/github.com/labstack/echo/v4/go.mod b/vendor/github.com/labstack/echo/v4/go.mod
index 87711707..2510d10c 100644
--- a/vendor/github.com/labstack/echo/v4/go.mod
+++ b/vendor/github.com/labstack/echo/v4/go.mod
@@ -5,12 +5,12 @@ go 1.15
require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/labstack/gommon v0.3.0
- github.com/mattn/go-colorable v0.1.7 // indirect
+ github.com/mattn/go-colorable v0.1.8 // indirect
github.com/stretchr/testify v1.4.0
github.com/valyala/fasttemplate v1.2.1
- golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
- golang.org/x/net v0.0.0-20200822124328-c89045814202
- golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 // indirect
- golang.org/x/text v0.3.3 // indirect
+ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
+ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4
+ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
+ golang.org/x/text v0.3.6 // indirect
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324
)
diff --git a/vendor/github.com/labstack/echo/v4/go.sum b/vendor/github.com/labstack/echo/v4/go.sum
index 54ba24e6..d18f10fb 100644
--- a/vendor/github.com/labstack/echo/v4/go.sum
+++ b/vendor/github.com/labstack/echo/v4/go.sum
@@ -4,12 +4,10 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
-github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
-github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
-github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
@@ -20,32 +18,26 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
-golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8=
-golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/vendor/github.com/labstack/echo/v4/middleware/csrf.go b/vendor/github.com/labstack/echo/v4/middleware/csrf.go
index 60f809a0..7804997d 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/csrf.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/csrf.go
@@ -110,7 +110,7 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
if config.CookieMaxAge == 0 {
config.CookieMaxAge = DefaultCSRFConfig.CookieMaxAge
}
- if config.CookieSameSite == SameSiteNoneMode {
+ if config.CookieSameSite == http.SameSiteNoneMode {
config.CookieSecure = true
}
diff --git a/vendor/github.com/labstack/echo/v4/middleware/csrf_samesite.go b/vendor/github.com/labstack/echo/v4/middleware/csrf_samesite.go
deleted file mode 100644
index 9a27dc43..00000000
--- a/vendor/github.com/labstack/echo/v4/middleware/csrf_samesite.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build go1.13
-
-package middleware
-
-import (
- "net/http"
-)
-
-const (
- // SameSiteNoneMode required to be redefined for Go 1.12 support (see #1524)
- SameSiteNoneMode http.SameSite = http.SameSiteNoneMode
-)
diff --git a/vendor/github.com/labstack/echo/v4/middleware/csrf_samesite_1.12.go b/vendor/github.com/labstack/echo/v4/middleware/csrf_samesite_1.12.go
deleted file mode 100644
index 22076dd6..00000000
--- a/vendor/github.com/labstack/echo/v4/middleware/csrf_samesite_1.12.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build !go1.13
-
-package middleware
-
-import (
- "net/http"
-)
-
-const (
- // SameSiteNoneMode required to be redefined for Go 1.12 support (see #1524)
- SameSiteNoneMode http.SameSite = 4
-)
diff --git a/vendor/github.com/labstack/echo/v4/middleware/jwt.go b/vendor/github.com/labstack/echo/v4/middleware/jwt.go
index da00ea56..cd35b621 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/jwt.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/jwt.go
@@ -29,15 +29,19 @@ type (
// ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context.
ErrorHandlerWithContext JWTErrorHandlerWithContext
- // Signing key to validate token. Used as fallback if SigningKeys has length 0.
- // Required. This or SigningKeys.
+ // Signing key to validate token.
+ // This is one of the three options to provide a token validation key.
+ // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
+ // Required if neither user-defined KeyFunc nor SigningKeys is provided.
SigningKey interface{}
// Map of signing keys to validate token with kid field usage.
- // Required. This or SigningKey.
+ // This is one of the three options to provide a token validation key.
+ // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
+ // Required if neither user-defined KeyFunc nor SigningKey is provided.
SigningKeys map[string]interface{}
- // Signing method, used to check token signing method.
+ // Signing method used to check the token's signing algorithm.
// Optional. Default value HS256.
SigningMethod string
@@ -64,7 +68,16 @@ type (
// Optional. Default value "Bearer".
AuthScheme string
- keyFunc jwt.Keyfunc
+ // KeyFunc defines a user-defined function that supplies the public key for a token validation.
+ // The function shall take care of verifying the signing algorithm and selecting the proper key.
+ // A user-defined KeyFunc can be useful if tokens are issued by an external party.
+ //
+ // When a user-defined KeyFunc is provided, SigningKey, SigningKeys, and SigningMethod are ignored.
+ // This is one of the three options to provide a token validation key.
+ // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
+ // Required if neither SigningKeys nor SigningKey is provided.
+ // Default to an internal implementation verifying the signing algorithm and selecting the proper key.
+ KeyFunc jwt.Keyfunc
}
// JWTSuccessHandler defines a function which is executed for a valid token.
@@ -99,6 +112,7 @@ var (
TokenLookup: "header:" + echo.HeaderAuthorization,
AuthScheme: "Bearer",
Claims: jwt.MapClaims{},
+ KeyFunc: nil,
}
)
@@ -123,7 +137,7 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
if config.Skipper == nil {
config.Skipper = DefaultJWTConfig.Skipper
}
- if config.SigningKey == nil && len(config.SigningKeys) == 0 {
+ if config.SigningKey == nil && len(config.SigningKeys) == 0 && config.KeyFunc == nil {
panic("echo: jwt middleware requires signing key")
}
if config.SigningMethod == "" {
@@ -141,35 +155,29 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
if config.AuthScheme == "" {
config.AuthScheme = DefaultJWTConfig.AuthScheme
}
- config.keyFunc = func(t *jwt.Token) (interface{}, error) {
- // Check the signing method
- if t.Method.Alg() != config.SigningMethod {
- return nil, fmt.Errorf("unexpected jwt signing method=%v", t.Header["alg"])
- }
- if len(config.SigningKeys) > 0 {
- if kid, ok := t.Header["kid"].(string); ok {
- if key, ok := config.SigningKeys[kid]; ok {
- return key, nil
- }
- }
- return nil, fmt.Errorf("unexpected jwt key id=%v", t.Header["kid"])
- }
-
- return config.SigningKey, nil
+ if config.KeyFunc == nil {
+ config.KeyFunc = config.defaultKeyFunc
}
// Initialize
- parts := strings.Split(config.TokenLookup, ":")
- extractor := jwtFromHeader(parts[1], config.AuthScheme)
- switch parts[0] {
- case "query":
- extractor = jwtFromQuery(parts[1])
- case "param":
- extractor = jwtFromParam(parts[1])
- case "cookie":
- extractor = jwtFromCookie(parts[1])
- case "form":
- extractor = jwtFromForm(parts[1])
+ // Split sources
+ sources := strings.Split(config.TokenLookup, ",")
+ var extractors []jwtExtractor
+ for _, source := range sources {
+ parts := strings.Split(source, ":")
+
+ switch parts[0] {
+ case "query":
+ extractors = append(extractors, jwtFromQuery(parts[1]))
+ case "param":
+ extractors = append(extractors, jwtFromParam(parts[1]))
+ case "cookie":
+ extractors = append(extractors, jwtFromCookie(parts[1]))
+ case "form":
+ extractors = append(extractors, jwtFromForm(parts[1]))
+ case "header":
+ extractors = append(extractors, jwtFromHeader(parts[1], config.AuthScheme))
+ }
}
return func(next echo.HandlerFunc) echo.HandlerFunc {
@@ -181,8 +189,17 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
if config.BeforeFunc != nil {
config.BeforeFunc(c)
}
-
- auth, err := extractor(c)
+ var auth string
+ var err error
+ for _, extractor := range extractors {
+ // Extract token from extractor, if it's not fail break the loop and
+ // set auth
+ auth, err = extractor(c)
+ if err == nil {
+ break
+ }
+ }
+ // If none of extractor has a token, handle error
if err != nil {
if config.ErrorHandler != nil {
return config.ErrorHandler(err)
@@ -193,14 +210,15 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
}
return err
}
+
token := new(jwt.Token)
// Issue #647, #656
if _, ok := config.Claims.(jwt.MapClaims); ok {
- token, err = jwt.Parse(auth, config.keyFunc)
+ token, err = jwt.Parse(auth, config.KeyFunc)
} else {
t := reflect.ValueOf(config.Claims).Type().Elem()
claims := reflect.New(t).Interface().(jwt.Claims)
- token, err = jwt.ParseWithClaims(auth, claims, config.keyFunc)
+ token, err = jwt.ParseWithClaims(auth, claims, config.KeyFunc)
}
if err == nil && token.Valid {
// Store user information from token into context.
@@ -225,6 +243,24 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
}
}
+// defaultKeyFunc returns a signing key of the given token.
+func (config *JWTConfig) defaultKeyFunc(t *jwt.Token) (interface{}, error) {
+ // Check the signing method
+ if t.Method.Alg() != config.SigningMethod {
+ return nil, fmt.Errorf("unexpected jwt signing method=%v", t.Header["alg"])
+ }
+ if len(config.SigningKeys) > 0 {
+ if kid, ok := t.Header["kid"].(string); ok {
+ if key, ok := config.SigningKeys[kid]; ok {
+ return key, nil
+ }
+ }
+ return nil, fmt.Errorf("unexpected jwt key id=%v", t.Header["kid"])
+ }
+
+ return config.SigningKey, nil
+}
+
// jwtFromHeader returns a `jwtExtractor` that extracts token from the request header.
func jwtFromHeader(header string, authScheme string) jwtExtractor {
return func(c echo.Context) (string, error) {
diff --git a/vendor/github.com/labstack/echo/v4/middleware/key_auth.go b/vendor/github.com/labstack/echo/v4/middleware/key_auth.go
index 94cfd142..fd169aa2 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/key_auth.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/key_auth.go
@@ -30,12 +30,19 @@ type (
// Validator is a function to validate key.
// Required.
Validator KeyAuthValidator
+
+ // ErrorHandler defines a function which is executed for an invalid key.
+ // It may be used to define a custom error.
+ ErrorHandler KeyAuthErrorHandler
}
// KeyAuthValidator defines a function to validate KeyAuth credentials.
KeyAuthValidator func(string, echo.Context) (bool, error)
keyExtractor func(echo.Context) (string, error)
+
+ // KeyAuthErrorHandler defines a function which is executed for an invalid key.
+ KeyAuthErrorHandler func(error, echo.Context) error
)
var (
@@ -95,10 +102,16 @@ func KeyAuthWithConfig(config KeyAuthConfig) echo.MiddlewareFunc {
// Extract and verify key
key, err := extractor(c)
if err != nil {
+ if config.ErrorHandler != nil {
+ return config.ErrorHandler(err, c)
+ }
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
valid, err := config.Validator(key, c)
if err != nil {
+ if config.ErrorHandler != nil {
+ return config.ErrorHandler(err, c)
+ }
return &echo.HTTPError{
Code: http.StatusUnauthorized,
Message: "invalid key",
diff --git a/vendor/github.com/labstack/echo/v4/middleware/proxy.go b/vendor/github.com/labstack/echo/v4/middleware/proxy.go
index 6f01f3a7..6cfd6731 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/proxy.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/proxy.go
@@ -1,13 +1,16 @@
package middleware
import (
+ "context"
"fmt"
"io"
"math/rand"
"net"
"net/http"
+ "net/http/httputil"
"net/url"
"regexp"
+ "strings"
"sync"
"sync/atomic"
"time"
@@ -264,3 +267,37 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
}
}
}
+
+// StatusCodeContextCanceled is a custom HTTP status code for situations
+// where a client unexpectedly closed the connection to the server.
+// As there is no standard error code for "client closed connection", but
+// various well-known HTTP clients and server implement this HTTP code we use
+// 499 too instead of the more problematic 5xx, which does not allow to detect this situation
+const StatusCodeContextCanceled = 499
+
+func proxyHTTP(tgt *ProxyTarget, c echo.Context, config ProxyConfig) http.Handler {
+ proxy := httputil.NewSingleHostReverseProxy(tgt.URL)
+ proxy.ErrorHandler = func(resp http.ResponseWriter, req *http.Request, err error) {
+ desc := tgt.URL.String()
+ if tgt.Name != "" {
+ desc = fmt.Sprintf("%s(%s)", tgt.Name, tgt.URL.String())
+ }
+ // If the client canceled the request (usually by closing the connection), we can report a
+ // client error (4xx) instead of a server error (5xx) to correctly identify the situation.
+ // The Go standard library (at of late 2020) wraps the exported, standard
+ // context.Canceled error with unexported garbage value requiring a substring check, see
+ // https://github.com/golang/go/blob/6965b01ea248cabb70c3749fd218b36089a21efb/src/net/net.go#L416-L430
+ if err == context.Canceled || strings.Contains(err.Error(), "operation was canceled") {
+ httpError := echo.NewHTTPError(StatusCodeContextCanceled, fmt.Sprintf("client closed connection: %v", err))
+ httpError.Internal = err
+ c.Set("_error", httpError)
+ } else {
+ httpError := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("remote %s unreachable, could not forward: %v", desc, err))
+ httpError.Internal = err
+ c.Set("_error", httpError)
+ }
+ }
+ proxy.Transport = config.Transport
+ proxy.ModifyResponse = config.ModifyResponse
+ return proxy
+}
diff --git a/vendor/github.com/labstack/echo/v4/middleware/proxy_1_11.go b/vendor/github.com/labstack/echo/v4/middleware/proxy_1_11.go
deleted file mode 100644
index 17d142d8..00000000
--- a/vendor/github.com/labstack/echo/v4/middleware/proxy_1_11.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// +build go1.11
-
-package middleware
-
-import (
- "context"
- "fmt"
- "net/http"
- "net/http/httputil"
- "strings"
-
- "github.com/labstack/echo/v4"
-)
-
-// StatusCodeContextCanceled is a custom HTTP status code for situations
-// where a client unexpectedly closed the connection to the server.
-// As there is no standard error code for "client closed connection", but
-// various well-known HTTP clients and server implement this HTTP code we use
-// 499 too instead of the more problematic 5xx, which does not allow to detect this situation
-const StatusCodeContextCanceled = 499
-
-func proxyHTTP(tgt *ProxyTarget, c echo.Context, config ProxyConfig) http.Handler {
- proxy := httputil.NewSingleHostReverseProxy(tgt.URL)
- proxy.ErrorHandler = func(resp http.ResponseWriter, req *http.Request, err error) {
- desc := tgt.URL.String()
- if tgt.Name != "" {
- desc = fmt.Sprintf("%s(%s)", tgt.Name, tgt.URL.String())
- }
- // If the client canceled the request (usually by closing the connection), we can report a
- // client error (4xx) instead of a server error (5xx) to correctly identify the situation.
- // The Go standard library (at of late 2020) wraps the exported, standard
- // context.Canceled error with unexported garbage value requiring a substring check, see
- // https://github.com/golang/go/blob/6965b01ea248cabb70c3749fd218b36089a21efb/src/net/net.go#L416-L430
- if err == context.Canceled || strings.Contains(err.Error(), "operation was canceled") {
- httpError := echo.NewHTTPError(StatusCodeContextCanceled, fmt.Sprintf("client closed connection: %v", err))
- httpError.Internal = err
- c.Set("_error", httpError)
- } else {
- httpError := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("remote %s unreachable, could not forward: %v", desc, err))
- httpError.Internal = err
- c.Set("_error", httpError)
- }
- }
- proxy.Transport = config.Transport
- proxy.ModifyResponse = config.ModifyResponse
- return proxy
-}
diff --git a/vendor/github.com/labstack/echo/v4/middleware/proxy_1_11_n.go b/vendor/github.com/labstack/echo/v4/middleware/proxy_1_11_n.go
deleted file mode 100644
index 9a78929f..00000000
--- a/vendor/github.com/labstack/echo/v4/middleware/proxy_1_11_n.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// +build !go1.11
-
-package middleware
-
-import (
- "net/http"
- "net/http/httputil"
-
- "github.com/labstack/echo/v4"
-)
-
-func proxyHTTP(t *ProxyTarget, c echo.Context, config ProxyConfig) http.Handler {
- return httputil.NewSingleHostReverseProxy(t.URL)
-}
diff --git a/vendor/github.com/labstack/echo/v4/middleware/static.go b/vendor/github.com/labstack/echo/v4/middleware/static.go
index ae79cb5f..0106f7ce 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/static.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/static.go
@@ -42,6 +42,10 @@ type (
// the filesystem path is not doubled
// Optional. Default value false.
IgnoreBase bool `yaml:"ignoreBase"`
+
+ // Filesystem provides access to the static content.
+ // Optional. Defaults to http.Dir(config.Root)
+ Filesystem http.FileSystem `yaml:"-"`
}
)
@@ -146,6 +150,10 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
if config.Index == "" {
config.Index = DefaultStaticConfig.Index
}
+ if config.Filesystem == nil {
+ config.Filesystem = http.Dir(config.Root)
+ config.Root = "."
+ }
// Index template
t, err := template.New("index").Parse(html)
@@ -178,49 +186,73 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
}
}
- fi, err := os.Stat(name)
+ file, err := openFile(config.Filesystem, name)
if err != nil {
- if os.IsNotExist(err) {
- if err = next(c); err != nil {
- if he, ok := err.(*echo.HTTPError); ok {
- if config.HTML5 && he.Code == http.StatusNotFound {
- return c.File(filepath.Join(config.Root, config.Index))
- }
- }
- return
- }
+ if !os.IsNotExist(err) {
+ return err
+ }
+
+ if err = next(c); err == nil {
+ return err
+ }
+
+ he, ok := err.(*echo.HTTPError)
+ if !(ok && config.HTML5 && he.Code == http.StatusNotFound) {
+ return err
+ }
+
+ file, err = openFile(config.Filesystem, filepath.Join(config.Root, config.Index))
+ if err != nil {
+ return err
}
- return
}
- if fi.IsDir() {
- index := filepath.Join(name, config.Index)
- fi, err = os.Stat(index)
+ defer file.Close()
+
+ info, err := file.Stat()
+ if err != nil {
+ return err
+ }
+ if info.IsDir() {
+ index, err := openFile(config.Filesystem, filepath.Join(name, config.Index))
if err != nil {
if config.Browse {
- return listDir(t, name, c.Response())
+ return listDir(t, name, file, c.Response())
}
+
if os.IsNotExist(err) {
return next(c)
}
- return
}
- return c.File(index)
+ defer index.Close()
+
+ info, err = index.Stat()
+ if err != nil {
+ return err
+ }
+
+ return serveFile(c, index, info)
}
- return c.File(name)
+ return serveFile(c, file, info)
}
}
}
-func listDir(t *template.Template, name string, res *echo.Response) (err error) {
- file, err := os.Open(name)
- if err != nil {
- return
- }
- files, err := file.Readdir(-1)
+func openFile(fs http.FileSystem, name string) (http.File, error) {
+ pathWithSlashes := filepath.ToSlash(name)
+ return fs.Open(pathWithSlashes)
+}
+
+func serveFile(c echo.Context, file http.File, info os.FileInfo) error {
+ http.ServeContent(c.Response(), c.Request(), info.Name(), info.ModTime(), file)
+ return nil
+}
+
+func listDir(t *template.Template, name string, dir http.File, res *echo.Response) (err error) {
+ files, err := dir.Readdir(-1)
if err != nil {
return
}
diff --git a/vendor/github.com/labstack/echo/v4/middleware/timeout.go b/vendor/github.com/labstack/echo/v4/middleware/timeout.go
index 5d23ff45..fb8ae421 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/timeout.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/timeout.go
@@ -1,5 +1,3 @@
-// +build go1.13
-
package middleware
import (
@@ -94,6 +92,15 @@ func (t echoHandlerFuncWrapper) ServeHTTP(rw http.ResponseWriter, r *http.Reques
originalWriter := t.ctx.Response().Writer
t.ctx.Response().Writer = rw
+ // in case of panic we restore original writer and call panic again
+ // so it could be handled with global middleware Recover()
+ defer func() {
+ if err := recover(); err != nil {
+ t.ctx.Response().Writer = originalWriter
+ panic(err)
+ }
+ }()
+
err := t.handler(t.ctx)
if ctxErr := r.Context().Err(); ctxErr == context.DeadlineExceeded {
if err != nil && t.errHandler != nil {
diff --git a/vendor/github.com/labstack/echo/v4/router.go b/vendor/github.com/labstack/echo/v4/router.go
index 2dd09fae..5b2474b3 100644
--- a/vendor/github.com/labstack/echo/v4/router.go
+++ b/vendor/github.com/labstack/echo/v4/router.go
@@ -23,6 +23,10 @@ type (
methodHandler *methodHandler
paramChild *node
anyChild *node
+ // isLeaf indicates that node does not have child routes
+ isLeaf bool
+ // isHandler indicates that node has at least one handler registered to it
+ isHandler bool
}
kind uint8
children []*node
@@ -50,6 +54,20 @@ const (
anyLabel = byte('*')
)
+func (m *methodHandler) isHandler() bool {
+ return m.connect != nil ||
+ m.delete != nil ||
+ m.get != nil ||
+ m.head != nil ||
+ m.options != nil ||
+ m.patch != nil ||
+ m.post != nil ||
+ m.propfind != nil ||
+ m.put != nil ||
+ m.trace != nil ||
+ m.report != nil
+}
+
// NewRouter returns a new Router instance.
func NewRouter(e *Echo) *Router {
return &Router{
@@ -73,6 +91,11 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
pnames := []string{} // Param names
ppath := path // Pristine path
+ if h == nil && r.echo.Logger != nil {
+ // FIXME: in future we should return error
+ r.echo.Logger.Errorf("Adding route without handler function: %v:%v", method, path)
+ }
+
for i, lcpIndex := 0, len(path); i < lcpIndex; i++ {
if path[i] == ':' {
j := i + 1
@@ -86,6 +109,7 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
i, lcpIndex = j, len(path)
if i == lcpIndex {
+ // path node is last fragment of route path. ie. `/users/:id`
r.insert(method, path[:i], h, paramKind, ppath, pnames)
} else {
r.insert(method, path[:i], nil, paramKind, "", nil)
@@ -136,6 +160,7 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
currentNode.ppath = ppath
currentNode.pnames = pnames
}
+ currentNode.isLeaf = currentNode.staticChildren == nil && currentNode.paramChild == nil && currentNode.anyChild == nil
} else if lcpLen < prefixLen {
// Split node
n := newNode(
@@ -149,7 +174,6 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
currentNode.paramChild,
currentNode.anyChild,
)
-
// Update parent path for all children to new node
for _, child := range currentNode.staticChildren {
child.parent = n
@@ -171,6 +195,8 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
currentNode.pnames = nil
currentNode.paramChild = nil
currentNode.anyChild = nil
+ currentNode.isLeaf = false
+ currentNode.isHandler = false
// Only Static children could reach here
currentNode.addStaticChild(n)
@@ -188,6 +214,7 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
// Only Static children could reach here
currentNode.addStaticChild(n)
}
+ currentNode.isLeaf = currentNode.staticChildren == nil && currentNode.paramChild == nil && currentNode.anyChild == nil
} else if lcpLen < searchLen {
search = search[lcpLen:]
c := currentNode.findChildWithLabel(search[0])
@@ -207,6 +234,7 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
case anyKind:
currentNode.anyChild = n
}
+ currentNode.isLeaf = currentNode.staticChildren == nil && currentNode.paramChild == nil && currentNode.anyChild == nil
} else {
// Node already exists
if h != nil {
@@ -233,6 +261,8 @@ func newNode(t kind, pre string, p *node, sc children, mh *methodHandler, ppath
methodHandler: mh,
paramChild: paramChildren,
anyChild: anyChildren,
+ isLeaf: sc == nil && paramChildren == nil && anyChildren == nil,
+ isHandler: mh.isHandler(),
}
}
@@ -289,6 +319,12 @@ func (n *node) addHandler(method string, h HandlerFunc) {
case REPORT:
n.methodHandler.report = h
}
+
+ if h != nil {
+ n.isHandler = true
+ } else {
+ n.isHandler = n.methodHandler.isHandler()
+ }
}
func (n *node) findHandler(method string) HandlerFunc {
@@ -343,6 +379,8 @@ func (r *Router) Find(method, path string, c Context) {
currentNode := r.tree // Current node as root
var (
+ previousBestMatchNode *node
+ matchedHandler HandlerFunc
// search stores the remaining path to check for match. By each iteration we move from start of path to end of the path
// and search value gets shorter and shorter.
search = path
@@ -362,10 +400,11 @@ func (r *Router) Find(method, path string, c Context) {
valid = currentNode != nil
// Next node type by priority
- // NOTE: With the current implementation we never backtrack from an `any` route, so `previous.kind` is
- // always `static` or `any`
- // If this is changed then for any route next kind would be `static` and this statement should be changed
- nextNodeKind = previous.kind + 1
+ if previous.kind == anyKind {
+ nextNodeKind = staticKind
+ } else {
+ nextNodeKind = previous.kind + 1
+ }
if fromKind == staticKind {
// when backtracking is done from static kind block we did not change search so nothing to restore
@@ -380,6 +419,7 @@ func (r *Router) Find(method, path string, c Context) {
// for param/any node.prefix value is always `:` so we can not deduce searchIndex from that and must use pValue
// for that index as it would also contain part of path we cut off before moving into node we are backtracking from
searchIndex -= len(paramValues[paramIndex])
+ paramValues[paramIndex] = ""
}
search = path[searchIndex:]
return
@@ -421,7 +461,7 @@ func (r *Router) Find(method, path string, c Context) {
// goto Any
} else {
// Not found (this should never be possible for static node we are looking currently)
- return
+ break
}
}
@@ -429,9 +469,17 @@ func (r *Router) Find(method, path string, c Context) {
search = search[lcpLen:]
searchIndex = searchIndex + lcpLen
- // Finish routing if no remaining search and we are on an leaf node
- if search == "" && currentNode.ppath != "" {
- break
+ // Finish routing if no remaining search and we are on a node with handler and matching method type
+ if search == "" && currentNode.isHandler {
+ // check if current node has handler registered for http method we are looking for. we store currentNode as
+ // best matching in case we do no find no more routes matching this path+method
+ if previousBestMatchNode == nil {
+ previousBestMatchNode = currentNode
+ }
+ if h := currentNode.findHandler(method); h != nil {
+ matchedHandler = h
+ break
+ }
}
// Static node
@@ -446,10 +494,16 @@ func (r *Router) Find(method, path string, c Context) {
// Param node
if child := currentNode.paramChild; search != "" && child != nil {
currentNode = child
- // FIXME: when param node does not have any children then param node should act similarly to any node - consider all remaining search as match
- i, l := 0, len(search)
- for ; i < l && search[i] != '/'; i++ {
+ i := 0
+ l := len(search)
+ if currentNode.isLeaf {
+ // when param node does not have any children then param node should act similarly to any node - consider all remaining search as match
+ i = l
+ } else {
+ for ; i < l && search[i] != '/'; i++ {
+ }
}
+
paramValues[paramIndex] = search[:i]
paramIndex++
search = search[i:]
@@ -463,29 +517,50 @@ func (r *Router) Find(method, path string, c Context) {
// If any node is found, use remaining path for paramValues
currentNode = child
paramValues[len(currentNode.pnames)-1] = search
- break
+ // update indexes/search in case we need to backtrack when no handler match is found
+ paramIndex++
+ searchIndex += +len(search)
+ search = ""
+
+ // check if current node has handler registered for http method we are looking for. we store currentNode as
+ // best matching in case we do no find no more routes matching this path+method
+ if previousBestMatchNode == nil {
+ previousBestMatchNode = currentNode
+ }
+ if h := currentNode.findHandler(method); h != nil {
+ matchedHandler = h
+ break
+ }
}
// Let's backtrack to the first possible alternative node of the decision path
nk, ok := backtrackToNextNodeKind(anyKind)
if !ok {
- return // No other possibilities on the decision path
+ break // No other possibilities on the decision path
} else if nk == paramKind {
goto Param
} else if nk == anyKind {
goto Any
} else {
// Not found
- return
+ break
}
}
- ctx.handler = currentNode.findHandler(method)
- ctx.path = currentNode.ppath
- ctx.pnames = currentNode.pnames
+ if currentNode == nil && previousBestMatchNode == nil {
+ return // nothing matched at all
+ }
- if ctx.handler == nil {
+ if matchedHandler != nil {
+ ctx.handler = matchedHandler
+ } else {
+ // use previous match as basis. although we have no matching handler we have path match.
+ // so we can send http.StatusMethodNotAllowed (405) instead of http.StatusNotFound (404)
+ currentNode = previousBestMatchNode
ctx.handler = currentNode.checkMethodNotAllowed()
}
+ ctx.path = currentNode.ppath
+ ctx.pnames = currentNode.pnames
+
return
}