mirror of
https://github.com/kataras/iris.git
synced 2026-01-10 21:45:57 +00:00
reorganization of _examples and add some new examples such as iris+groupcache+mysql+docker
Former-commit-id: ed635ee95de7160cde11eaabc0c1dcb0e460a620
This commit is contained in:
@@ -3,15 +3,15 @@ Builtin Handlers
|
||||
|
||||
| Middleware | Example |
|
||||
| -----------|-------------|
|
||||
| [basic authentication](basicauth) | [iris/_examples/authentication/basicauth](https://github.com/kataras/iris/tree/master/_examples/authentication/basicauth) |
|
||||
| [request logger](logger) | [iris/_examples/http_request/request-logger](https://github.com/kataras/iris/tree/master/_examples/http_request/request-logger) |
|
||||
| [basic authentication](basicauth) | [iris/_examples/auth/basicauth](https://github.com/kataras/iris/tree/master/_examples/auth/basicauth) |
|
||||
| [request logger](logger) | [iris/_examples/logging/request-logger](https://github.com/kataras/iris/tree/master/_examples/logging/request-logger) |
|
||||
| [HTTP method override](methodoverride) | [iris/middleware/methodoverride/methodoverride_test.go](https://github.com/kataras/iris/blob/master/middleware/methodoverride/methodoverride_test.go) |
|
||||
| [profiling (pprof)](pprof) | [iris/_examples/miscellaneous/pprof](https://github.com/kataras/iris/tree/master/_examples/miscellaneous/pprof) |
|
||||
| [Google reCAPTCHA](recaptcha) | [iris/_examples/miscellaneous/recaptcha](https://github.com/kataras/iris/tree/master/_examples/miscellaneous/recaptcha) |
|
||||
| [hCaptcha](hcaptcha) | [iris/_examples/miscellaneous/recaptcha](https://github.com/kataras/iris/tree/master/_examples/miscellaneous/hcaptcha) |
|
||||
| [recovery](recover) | [iris/_examples/miscellaneous/recover](https://github.com/kataras/iris/tree/master/_examples/miscellaneous/recover) |
|
||||
| [rate](rate) | [iris/_examples/miscellaneous/ratelimit](https://github.com/kataras/iris/tree/master/_examples/miscellaneous/ratelimit) |
|
||||
| [jwt](jwt) | [iris/_examples/miscellaneous/jwt](https://github.com/kataras/iris/tree/master/_examples/miscellaneous/jwt) |
|
||||
| [profiling (pprof)](pprof) | [iris/_examples/pprof](https://github.com/kataras/iris/tree/master/_examples/pprof) |
|
||||
| [Google reCAPTCHA](recaptcha) | [iris/_examples/auth/recaptcha](https://github.com/kataras/iris/tree/master/_examples/auth/recaptcha) |
|
||||
| [hCaptcha](hcaptcha) | [iris/_examples/auth/recaptcha](https://github.com/kataras/iris/tree/master/_examples/auth/hcaptcha) |
|
||||
| [recovery](recover) | [iris/_examples/recover](https://github.com/kataras/iris/tree/master/_examples/recover) |
|
||||
| [rate](rate) | [iris/_examples/request-ratelimit](https://github.com/kataras/iris/tree/master/_examples/request-ratelimit) |
|
||||
| [jwt](jwt) | [iris/_examples/auth/jwt](https://github.com/kataras/iris/tree/master/_examples/auth/jwt) |
|
||||
| [requestid](requestid) | [iris/middleware/requestid/requestid_test.go](https://github.com/kataras/iris/blob/master/_examples/middleware/requestid/requestid_test.go) |
|
||||
|
||||
Community made
|
||||
@@ -32,7 +32,7 @@ Most of the experimental handlers are ported to work with _iris_'s handler form,
|
||||
| [raven](https://github.com/iris-contrib/middleware/tree/master/raven)| Sentry client in Go | [iris-contrib/middleware/raven/_example](https://github.com/iris-contrib/middleware/blob/master/raven/_example/main.go) |
|
||||
| [csrf](https://github.com/iris-contrib/middleware/tree/master/csrf)| Cross-Site Request Forgery Protection | [iris-contrib/middleware/csrf/_example](https://github.com/iris-contrib/middleware/blob/master/csrf/_example/main.go) |
|
||||
| [go-i18n](https://github.com/iris-contrib/middleware/tree/master/go-i18n)| i18n Iris Loader for nicksnyder/go-i18n | [iris-contrib/middleware/go-i18n/_example](https://github.com/iris-contrib/middleware/blob/master/go-i18n/_example/main.go) |
|
||||
| [throttler](https://github.com/iris-contrib/middleware/tree/master/throttler)| Rate limiting access to HTTP endpoints | [iris-contrib/middleware/throttler/_example](https://github.com/iris-contrib/middleware/blob/master/throttler/_example/main.go) **NEW** |
|
||||
| [throttler](https://github.com/iris-contrib/middleware/tree/master/throttler)| Rate limiting access to HTTP endpoints | [iris-contrib/middleware/throttler/_example](https://github.com/iris-contrib/middleware/blob/master/throttler/_example/main.go) |
|
||||
|
||||
Third-Party Handlers
|
||||
------------
|
||||
@@ -43,15 +43,14 @@ Here's a small list of useful third-party handlers:
|
||||
|
||||
| Middleware | Description |
|
||||
| -----------|-------------|
|
||||
| [goth](https://github.com/markbates/goth) | OAuth, OAuth2 authentication. [Example](https://github.com/kataras/iris/tree/master/_examples/authentication/oauth2) |
|
||||
| [goth](https://github.com/markbates/goth) | OAuth, OAuth2 authentication. [Example](https://github.com/kataras/iris/tree/master/_examples/auth/goth) |
|
||||
| [permissions2](https://github.com/xyproto/permissions2) | Cookies, users and permissions. [Example](https://github.com/kataras/iris/tree/master/_examples/auth/permissions) |
|
||||
| [csp](https://github.com/awakenetworks/csp) | [Content Security Policy](https://www.w3.org/TR/CSP2/) (CSP) support |
|
||||
| [delay](https://github.com/jeffbmartinez/delay) | Add delays/latency to endpoints. Useful when testing effects of high latency |
|
||||
| [onthefly](https://github.com/xyproto/onthefly) | Generate TinySVG, HTML and CSS on the fly |
|
||||
| [permissions2](https://github.com/xyproto/permissions2) | Cookies, users and permissions |
|
||||
| [RestGate](https://github.com/pjebs/restgate) | Secure authentication for REST API endpoints |
|
||||
| [stats](https://github.com/thoas/stats) | Store information about your web application (response time, etc.) |
|
||||
| [VanGoH](https://github.com/auroratechnologies/vangoh) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC authentication middleware |
|
||||
| [xrequestid](https://github.com/pilu/xrequestid) | Middleware that assigns a random X-Request-Id header to each request |
|
||||
| [digits](https://github.com/bamarni/digits) | Middleware that handles [Twitter Digits](https://get.digits.com/) authentication |
|
||||
|
||||
> Feel free to put up your own middleware in this list!
|
||||
@@ -1,7 +1,7 @@
|
||||
// Package basicauth provides http basic authentication via middleware. See _examples/authentication/basicauth
|
||||
// Package basicauth provides http basic authentication via middleware. See _examples/auth/basicauth
|
||||
package basicauth
|
||||
|
||||
// test file: ../../_examples/authentication/basicauth/main_test.go
|
||||
// test file: ../../_examples/auth/basicauth/main_test.go
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
@@ -160,7 +160,7 @@ func ParseForm(dataSiteKey, postActionRelativePath string) string {
|
||||
}
|
||||
|
||||
// RenderForm writes the `HTMLForm` to "w" response writer.
|
||||
// See `_examples/basic/register_form.html` example for a custom form instead.
|
||||
// See `_examples/auth/hcaptcha/templates/register_form.html` example for a custom form instead.
|
||||
func RenderForm(ctx context.Context, dataSiteKey, postActionRelativePath string) (int, error) {
|
||||
return ctx.HTML(ParseForm(dataSiteKey, postActionRelativePath))
|
||||
}
|
||||
|
||||
@@ -10,6 +10,15 @@ type (
|
||||
Claims = jwt.Claims
|
||||
// Audience represents the recipients that the token is intended for.
|
||||
Audience = jwt.Audience
|
||||
// NumericDate represents date and time as the number of seconds since the
|
||||
// epoch, including leap seconds. Non-integer values can be represented
|
||||
// in the serialized format, but we round to the nearest second.
|
||||
NumericDate = jwt.NumericDate
|
||||
)
|
||||
|
||||
var (
|
||||
// NewNumericDate constructs NumericDate from time.Time value.
|
||||
NewNumericDate = jwt.NewNumericDate
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -155,26 +155,38 @@ func New(maxAge time.Duration, alg SignatureAlgorithm, key interface{}) (*JWT, e
|
||||
return j, nil
|
||||
}
|
||||
|
||||
// RSA filenames for `DefaultRSA`.
|
||||
// Default key filenames for `RSA`.
|
||||
const (
|
||||
SignFilename = "jwt_sign.key"
|
||||
EncFilename = "jwt_enc.key"
|
||||
DefaultSignFilename = "jwt_sign.key"
|
||||
DefaultEncFilename = "jwt_enc.key"
|
||||
)
|
||||
|
||||
// DefaultRSA returns a new `JWT` instance.
|
||||
// It tries to parse RSA256 keys from "jwt_sign.key" and (optionally) "jwt_enc.key" files
|
||||
// in the current working directory, and if not found, it generates and exports the keys.
|
||||
// RSA returns a new `JWT` instance.
|
||||
// It tries to parse RSA256 keys from "filenames[0]" (defaults to "jwt_sign.key") and
|
||||
// "filenames[1]" (defaults to "jwt_enc.key") files or generates and exports new random keys.
|
||||
//
|
||||
// It panics on errors.
|
||||
// Use the `New` package-level function instead for more options.
|
||||
func DefaultRSA(maxAge time.Duration) *JWT {
|
||||
// Do not try to create or load enc key if only sign key already exists.
|
||||
withEncryption := true
|
||||
if fileExists(SignFilename) {
|
||||
withEncryption = fileExists(EncFilename)
|
||||
func RSA(maxAge time.Duration, filenames ...string) *JWT {
|
||||
var (
|
||||
signFilename = DefaultSignFilename
|
||||
encFilename = DefaultEncFilename
|
||||
)
|
||||
|
||||
switch len(filenames) {
|
||||
case 1:
|
||||
signFilename = filenames[0]
|
||||
case 2:
|
||||
encFilename = filenames[1]
|
||||
}
|
||||
|
||||
sigKey, err := LoadRSA(SignFilename, 2048)
|
||||
// Do not try to create or load enc key if only sign key already exists.
|
||||
withEncryption := true
|
||||
if fileExists(signFilename) {
|
||||
withEncryption = fileExists(encFilename)
|
||||
}
|
||||
|
||||
sigKey, err := LoadRSA(signFilename, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -185,7 +197,7 @@ func DefaultRSA(maxAge time.Duration) *JWT {
|
||||
}
|
||||
|
||||
if withEncryption {
|
||||
encKey, err := LoadRSA(EncFilename, 2048)
|
||||
encKey, err := LoadRSA(encFilename, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -212,7 +224,7 @@ func getenv(key string, def string) string {
|
||||
return v
|
||||
}
|
||||
|
||||
// DefaultHMAC returns a new `JWT` instance.
|
||||
// HMAC returns a new `JWT` instance.
|
||||
// It tries to read hmac256 secret keys from system environment variables:
|
||||
// * JWT_SECRET for signing and verification key and
|
||||
// * JWT_SECRET_ENC for encryption and decryption key
|
||||
@@ -220,7 +232,7 @@ func getenv(key string, def string) string {
|
||||
//
|
||||
// It panics on errors.
|
||||
// Use the `New` package-level function instead for more options.
|
||||
func DefaultHMAC(maxAge time.Duration, keys ...string) *JWT {
|
||||
func HMAC(maxAge time.Duration, keys ...string) *JWT {
|
||||
var defaultSignSecret, defaultEncSecret string
|
||||
|
||||
switch len(keys) {
|
||||
@@ -279,8 +291,8 @@ func (j *JWT) WithEncryption(contentEncryption ContentEncryption, alg KeyAlgorit
|
||||
// See the `JWT.Expiry` method too.
|
||||
func Expiry(maxAge time.Duration, claims Claims) Claims {
|
||||
now := time.Now()
|
||||
claims.Expiry = jwt.NewNumericDate(now.Add(maxAge))
|
||||
claims.IssuedAt = jwt.NewNumericDate(now)
|
||||
claims.Expiry = NewNumericDate(now.Add(maxAge))
|
||||
claims.IssuedAt = NewNumericDate(now)
|
||||
return claims
|
||||
}
|
||||
|
||||
@@ -308,6 +320,14 @@ func (j *JWT) Expiry(claims Claims) Claims {
|
||||
// Token generates and returns a new token string.
|
||||
// See `VerifyToken` too.
|
||||
func (j *JWT) Token(claims interface{}) (string, error) {
|
||||
// switch c := claims.(type) {
|
||||
// case Claims:
|
||||
// claims = Expiry(j.MaxAge, c)
|
||||
// case map[string]interface{}: let's not support map.
|
||||
// now := time.Now()
|
||||
// c["iat"] = now.Unix()
|
||||
// c["exp"] = now.Add(j.MaxAge).Unix()
|
||||
// }
|
||||
if c, ok := claims.(Claims); ok {
|
||||
claims = Expiry(j.MaxAge, c)
|
||||
}
|
||||
@@ -331,6 +351,39 @@ func (j *JWT) Token(claims interface{}) (string, error) {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
/* Let's no support maps, typed claim is the way to go.
|
||||
// validateMapClaims validates claims of map type.
|
||||
func validateMapClaims(m map[string]interface{}, e jwt.Expected, leeway time.Duration) error {
|
||||
if !e.Time.IsZero() {
|
||||
if v, ok := m["nbf"]; ok {
|
||||
if notBefore, ok := v.(NumericDate); ok {
|
||||
if e.Time.Add(leeway).Before(notBefore.Time()) {
|
||||
return ErrNotValidYet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := m["exp"]; ok {
|
||||
if exp, ok := v.(int64); ok {
|
||||
if e.Time.Add(-leeway).Before(time.Unix(exp, 0)) {
|
||||
return ErrExpired
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := m["iat"]; ok {
|
||||
if issuedAt, ok := v.(int64); ok {
|
||||
if e.Time.Add(leeway).Before(time.Unix(issuedAt, 0)) {
|
||||
return ErrIssuedInTheFuture
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
// WriteToken is a helper which just generates(calls the `Token` method) and writes
|
||||
// a new token to the client in plain text format.
|
||||
//
|
||||
@@ -347,21 +400,26 @@ func (j *JWT) WriteToken(ctx context.Context, claims interface{}) error {
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrTokenMissing when token cannot be extracted from the request.
|
||||
ErrTokenMissing = errors.New("token is missing")
|
||||
// ErrTokenInvalid when incoming token is invalid.
|
||||
ErrTokenInvalid = errors.New("token is invalid")
|
||||
// ErrTokenExpired when incoming token has expired.
|
||||
ErrTokenExpired = errors.New("token has expired")
|
||||
// ErrMissing when token cannot be extracted from the request.
|
||||
ErrMissing = errors.New("token is missing")
|
||||
// ErrExpired indicates that token is used after expiry time indicated in exp claim.
|
||||
ErrExpired = errors.New("token is expired (exp)")
|
||||
// ErrNotValidYet indicates that token is used before time indicated in nbf claim.
|
||||
ErrNotValidYet = errors.New("token not valid yet (nbf)")
|
||||
// ErrIssuedInTheFuture indicates that the iat field is in the future.
|
||||
ErrIssuedInTheFuture = errors.New("token issued in the future (iat)")
|
||||
)
|
||||
|
||||
type (
|
||||
claimsValidator interface {
|
||||
ValidateWithLeeway(e jwt.Expected, leeway time.Duration) error
|
||||
}
|
||||
claimsAlternativeValidator interface {
|
||||
claimsAlternativeValidator interface { // to keep iris-contrib/jwt MapClaims compatible.
|
||||
Validate() error
|
||||
}
|
||||
claimsContextValidator interface {
|
||||
Validate(ctx context.Context) error
|
||||
}
|
||||
)
|
||||
|
||||
// IsValidated reports whether a token is already validated through
|
||||
@@ -372,18 +430,34 @@ func IsValidated(ctx context.Context) bool { // see the `ReadClaims`.
|
||||
}
|
||||
|
||||
func validateClaims(ctx context.Context, claims interface{}) (err error) {
|
||||
switch claims := claims.(type) {
|
||||
switch c := claims.(type) {
|
||||
case claimsValidator:
|
||||
err = claims.ValidateWithLeeway(jwt.Expected{Time: time.Now()}, 0)
|
||||
err = c.ValidateWithLeeway(jwt.Expected{Time: time.Now()}, 0)
|
||||
case claimsAlternativeValidator:
|
||||
err = claims.Validate()
|
||||
err = c.Validate()
|
||||
case claimsContextValidator:
|
||||
err = c.Validate(ctx)
|
||||
case *json.RawMessage:
|
||||
// if the data type is raw message (json []byte)
|
||||
// then it should contain exp (and iat and nbf) keys.
|
||||
// Unmarshal raw message to validate against.
|
||||
v := new(Claims)
|
||||
err = json.Unmarshal(*c, v)
|
||||
if err == nil {
|
||||
return validateClaims(ctx, v)
|
||||
}
|
||||
default:
|
||||
ctx.Values().Set(needsValidationContextKey, struct{}{})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err == jwt.ErrExpired {
|
||||
return ErrTokenExpired
|
||||
switch err {
|
||||
case jwt.ErrExpired:
|
||||
return ErrExpired
|
||||
case jwt.ErrNotValidYet:
|
||||
return ErrNotValidYet
|
||||
case jwt.ErrIssuedInTheFuture:
|
||||
return ErrIssuedInTheFuture
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,7 +477,7 @@ func (j *JWT) VerifyToken(ctx context.Context, claimsPtr interface{}) error {
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
return ErrTokenMissing
|
||||
return ErrMissing
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -422,11 +496,11 @@ func (j *JWT) VerifyToken(ctx context.Context, claimsPtr interface{}) error {
|
||||
parsedToken, err = jwt.ParseSigned(token)
|
||||
}
|
||||
if err != nil {
|
||||
return ErrTokenInvalid
|
||||
return err
|
||||
}
|
||||
|
||||
if err = parsedToken.Claims(j.VerificationKey, claimsPtr); err != nil {
|
||||
return ErrTokenInvalid
|
||||
return err
|
||||
}
|
||||
|
||||
return validateClaims(ctx, claimsPtr)
|
||||
@@ -463,12 +537,12 @@ func (j *JWT) Verify(ctx context.Context) {
|
||||
func ReadClaims(ctx context.Context, claimsPtr interface{}) error {
|
||||
v := ctx.Values().Get(ClaimsContextKey)
|
||||
if v == nil {
|
||||
return ErrTokenMissing
|
||||
return ErrMissing
|
||||
}
|
||||
|
||||
raw, ok := v.(json.RawMessage)
|
||||
if !ok {
|
||||
return ErrTokenMissing
|
||||
return ErrMissing
|
||||
}
|
||||
|
||||
err := json.Unmarshal(raw, claimsPtr)
|
||||
@@ -476,9 +550,9 @@ func ReadClaims(ctx context.Context, claimsPtr interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// If already validated on VerifyToken (a claimsValidator/claimsAlternativeValidator)
|
||||
// then no need to perform the check again.
|
||||
if !IsValidated(ctx) {
|
||||
// If already validated on `Verify/VerifyToken`
|
||||
// then no need to perform the check again.
|
||||
ctx.Values().Remove(needsValidationContextKey)
|
||||
return validateClaims(ctx, claimsPtr)
|
||||
}
|
||||
@@ -518,7 +592,7 @@ func ReadClaims(ctx context.Context, claimsPtr interface{}) error {
|
||||
func Get(ctx context.Context) (interface{}, error) {
|
||||
claims := ctx.Values().Get(ClaimsContextKey)
|
||||
if claims == nil {
|
||||
return nil, ErrTokenMissing
|
||||
return nil, ErrMissing
|
||||
}
|
||||
|
||||
if !IsValidated(ctx) {
|
||||
|
||||
@@ -19,22 +19,22 @@ type userClaims struct {
|
||||
const testMaxAge = 3 * time.Second
|
||||
|
||||
// Random RSA verification and encryption.
|
||||
func TestDefaultRSA(t *testing.T) {
|
||||
j := jwt.DefaultRSA(testMaxAge)
|
||||
func TestRSA(t *testing.T) {
|
||||
j := jwt.RSA(testMaxAge)
|
||||
t.Cleanup(func() {
|
||||
os.Remove(jwt.SignFilename)
|
||||
os.Remove(jwt.EncFilename)
|
||||
os.Remove(jwt.DefaultSignFilename)
|
||||
os.Remove(jwt.DefaultEncFilename)
|
||||
})
|
||||
testWriteVerifyToken(t, j)
|
||||
}
|
||||
|
||||
// HMAC verification and encryption.
|
||||
func TestDefaultHMAC(t *testing.T) {
|
||||
j := jwt.DefaultHMAC(testMaxAge, "secret", "itsa16bytesecret")
|
||||
func TestHMAC(t *testing.T) {
|
||||
j := jwt.HMAC(testMaxAge, "secret", "itsa16bytesecret")
|
||||
testWriteVerifyToken(t, j)
|
||||
}
|
||||
|
||||
func TestHMAC(t *testing.T) {
|
||||
func TestNew_HMAC(t *testing.T) {
|
||||
j, err := jwt.New(testMaxAge, jwt.HS256, []byte("secret"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -81,7 +81,7 @@ func testWriteVerifyToken(t *testing.T, j *jwt.JWT) {
|
||||
ctx.JSON(claims)
|
||||
})
|
||||
|
||||
app.Post("/restricted_middleware", j.Verify, func(ctx iris.Context) {
|
||||
app.Post("/restricted_middleware_readclaims", j.Verify, func(ctx iris.Context) {
|
||||
var claims userClaims
|
||||
if err := jwt.ReadClaims(ctx, &claims); err != nil {
|
||||
ctx.StopWithStatus(iris.StatusUnauthorized)
|
||||
@@ -91,6 +91,16 @@ func testWriteVerifyToken(t *testing.T, j *jwt.JWT) {
|
||||
ctx.JSON(claims)
|
||||
})
|
||||
|
||||
app.Post("/restricted_middleware_get", j.Verify, func(ctx iris.Context) {
|
||||
claims, err := jwt.Get(ctx)
|
||||
if err != nil {
|
||||
ctx.StopWithStatus(iris.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(claims)
|
||||
})
|
||||
|
||||
e := httptest.New(t, app)
|
||||
|
||||
// Get token.
|
||||
@@ -99,7 +109,7 @@ func testWriteVerifyToken(t *testing.T, j *jwt.JWT) {
|
||||
t.Fatalf("empty token")
|
||||
}
|
||||
|
||||
restrictedPaths := [...]string{"/restricted", "/restricted_middleware"}
|
||||
restrictedPaths := [...]string{"/restricted", "/restricted_middleware_readclaims", "/restricted_middleware_get"}
|
||||
|
||||
now := time.Now()
|
||||
for _, path := range restrictedPaths {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Package logger provides request logging via middleware. See _examples/http_request/request-logger
|
||||
// Package logger provides request logging via middleware. See _examples/logging/request-logger
|
||||
package logger
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Package pprof provides native pprof support via middleware. See _examples/miscellaneous/pprof
|
||||
// Package pprof provides native pprof support via middleware. See _examples/pprof
|
||||
package pprof
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Package rate implements rate limiter for Iris client requests.
|
||||
// Example can be found at: _examples/miscellaneous/ratelimit/main.go.
|
||||
// Example can be found at: _examples/request-ratelimit/main.go.
|
||||
package rate
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Package recover provides recovery for specific routes or for the whole app via middleware. See _examples/miscellaneous/recover
|
||||
// Package recover provides recovery for specific routes or for the whole app via middleware. See _examples/recover
|
||||
package recover
|
||||
|
||||
import (
|
||||
|
||||
@@ -10,7 +10,7 @@ func init() {
|
||||
context.SetHandlerName("iris/middleware/requestid.*", "iris.request.id")
|
||||
}
|
||||
|
||||
const xRequestIDHeaderValue = "X-Request-ID"
|
||||
const xRequestIDHeaderValue = "X-Request-Id"
|
||||
|
||||
// Generator defines the function which should extract or generate
|
||||
// a Request ID. See `DefaultGenerator` and `New` package-level functions.
|
||||
@@ -40,13 +40,14 @@ var DefaultGenerator Generator = func(ctx context.Context) string {
|
||||
}
|
||||
|
||||
// New returns a new request id middleware.
|
||||
// It accepts an ID Generator.
|
||||
// It optionally accepts an ID Generator.
|
||||
// The Generator can stop the handlers chain with an error or
|
||||
// return a valid ID (string).
|
||||
// If it's nil then the `DefaultGenerator` will be used instead.
|
||||
func New(gen Generator) context.Handler {
|
||||
if gen == nil {
|
||||
gen = DefaultGenerator
|
||||
func New(generator ...Generator) context.Handler {
|
||||
gen := DefaultGenerator
|
||||
if len(generator) > 0 {
|
||||
gen = generator[0]
|
||||
}
|
||||
|
||||
return func(ctx context.Context) {
|
||||
|
||||
@@ -17,7 +17,7 @@ func TestRequestID(t *testing.T) {
|
||||
|
||||
def := app.Party("/default")
|
||||
{
|
||||
def.Use(requestid.New(nil))
|
||||
def.Use(requestid.New())
|
||||
def.Get("/", h)
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func TestRequestID(t *testing.T) {
|
||||
ctx.SetID(expectedCustomIDFromOtherMiddleware)
|
||||
ctx.Next()
|
||||
})
|
||||
changeID.Use(requestid.New(nil))
|
||||
changeID.Use(requestid.New())
|
||||
changeID.Get("/", h)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user