mirror of
https://github.com/kataras/iris.git
synced 2025-12-28 15:27:03 +00:00
(#1554) Add support for all common compressions (write and read)
- Remove the context.Context interface and export the *context, the iris.Context now points to the pointer\nSupport compression and rate limiting in the FileServer\nBit of code organisation Former-commit-id: ad1c61bf968059510c6be9e7f2cceec7da70ba17
This commit is contained in:
@@ -97,7 +97,7 @@ func (b *basicAuthMiddleware) findAuth(headerValue string) (*encodedUser, bool)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (b *basicAuthMiddleware) askForCredentials(ctx context.Context) {
|
||||
func (b *basicAuthMiddleware) askForCredentials(ctx *context.Context) {
|
||||
ctx.Header("WWW-Authenticate", b.realmHeaderValue)
|
||||
ctx.StatusCode(iris.StatusUnauthorized)
|
||||
if b.askHandlerEnabled {
|
||||
@@ -106,7 +106,7 @@ func (b *basicAuthMiddleware) askForCredentials(ctx context.Context) {
|
||||
}
|
||||
|
||||
// Serve the actual middleware
|
||||
func (b *basicAuthMiddleware) Serve(ctx context.Context) {
|
||||
func (b *basicAuthMiddleware) Serve(ctx *context.Context) {
|
||||
auth, found := b.findAuth(ctx.GetHeader("Authorization"))
|
||||
if !found {
|
||||
b.askForCredentials(ctx)
|
||||
|
||||
@@ -50,6 +50,6 @@ func DefaultConfig() Config {
|
||||
}
|
||||
|
||||
// User returns the user from context key same as ctx.Request().BasicAuth().
|
||||
func (c Config) User(ctx context.Context) (string, string, bool) {
|
||||
func (c Config) User(ctx *context.Context) (string, string, bool) {
|
||||
return ctx.Request().BasicAuth()
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ var (
|
||||
ResponseContextKey string = "iris.hcaptcha"
|
||||
// DefaultFailureHandler is the default HTTP handler that is fired on hcaptcha failures.
|
||||
// See `Client.FailureHandler`.
|
||||
DefaultFailureHandler = func(ctx context.Context) {
|
||||
DefaultFailureHandler = func(ctx *context.Context) {
|
||||
ctx.StopWithStatus(http.StatusTooManyRequests)
|
||||
}
|
||||
)
|
||||
@@ -73,7 +73,7 @@ func New(secret string, options ...Option) context.Handler {
|
||||
// otherwise it calls the Client's `FailureHandler`.
|
||||
// The hcaptcha's `Response` (which contains any `ErrorCodes`)
|
||||
// is saved on the Request's Context (see `GetResponseFromContext`).
|
||||
func (c *Client) Handler(ctx context.Context) {
|
||||
func (c *Client) Handler(ctx *context.Context) {
|
||||
v := SiteVerify(ctx, c.secret)
|
||||
ctx.Values().Set(ResponseContextKey, v)
|
||||
if v.Success {
|
||||
@@ -93,7 +93,7 @@ const apiURL = "https://hcaptcha.com/siteverify"
|
||||
// It returns the hcaptcha's `Response`.
|
||||
// The `response.Success` reports whether the validation passed.
|
||||
// Any errors are passed through the `response.ErrorCodes` field.
|
||||
func SiteVerify(ctx context.Context, secret string) (response Response) {
|
||||
func SiteVerify(ctx *context.Context, secret string) (response Response) {
|
||||
generatedResponseID := ctx.FormValue("h-captcha-response")
|
||||
|
||||
if generatedResponseID == "" {
|
||||
@@ -130,7 +130,7 @@ func SiteVerify(ctx context.Context, secret string) (response Response) {
|
||||
}
|
||||
|
||||
// Get returns the hcaptcha `Response` of the current request and reports whether was found or not.
|
||||
func Get(ctx context.Context) (Response, bool) {
|
||||
func Get(ctx *context.Context) (Response, bool) {
|
||||
v := ctx.Values().Get(ResponseContextKey)
|
||||
if v != nil {
|
||||
if response, ok := v.(Response); ok {
|
||||
@@ -161,6 +161,6 @@ func ParseForm(dataSiteKey, postActionRelativePath string) string {
|
||||
|
||||
// RenderForm writes the `HTMLForm` to "w" response writer.
|
||||
// See `_examples/auth/hcaptcha/templates/register_form.html` example for a custom form instead.
|
||||
func RenderForm(ctx context.Context, dataSiteKey, postActionRelativePath string) (int, error) {
|
||||
func RenderForm(ctx *context.Context, dataSiteKey, postActionRelativePath string) (int, error) {
|
||||
return ctx.HTML(ParseForm(dataSiteKey, postActionRelativePath))
|
||||
}
|
||||
|
||||
@@ -21,12 +21,12 @@ func init() {
|
||||
// TokenExtractor is a function that takes a context as input and returns
|
||||
// a token. An empty string should be returned if no token found
|
||||
// without additional information.
|
||||
type TokenExtractor func(context.Context) string
|
||||
type TokenExtractor func(*context.Context) string
|
||||
|
||||
// FromHeader is a token extractor.
|
||||
// It reads the token from the Authorization request header of form:
|
||||
// Authorization: "Bearer {token}".
|
||||
func FromHeader(ctx context.Context) string {
|
||||
func FromHeader(ctx *context.Context) string {
|
||||
authHeader := ctx.GetHeader("Authorization")
|
||||
if authHeader == "" {
|
||||
return ""
|
||||
@@ -43,7 +43,7 @@ func FromHeader(ctx context.Context) string {
|
||||
|
||||
// FromQuery is a token extractor.
|
||||
// It reads the token from the "token" url query parameter.
|
||||
func FromQuery(ctx context.Context) string {
|
||||
func FromQuery(ctx *context.Context) string {
|
||||
return ctx.URLParam("token")
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func FromQuery(ctx context.Context) string {
|
||||
// The request content-type should contain the: application/json header value, otherwise
|
||||
// this method will not try to read and consume the body.
|
||||
func FromJSON(jsonKey string) TokenExtractor {
|
||||
return func(ctx context.Context) string {
|
||||
return func(ctx *context.Context) string {
|
||||
if ctx.GetContentTypeRequested() != context.ContentJSONHeaderValue {
|
||||
return ""
|
||||
}
|
||||
@@ -388,7 +388,7 @@ func validateMapClaims(m map[string]interface{}, e jwt.Expected, leeway time.Dur
|
||||
// a new token to the client in plain text format.
|
||||
//
|
||||
// Use the `Token` method to get a new generated token raw string value.
|
||||
func (j *JWT) WriteToken(ctx context.Context, claims interface{}) error {
|
||||
func (j *JWT) WriteToken(ctx *context.Context, claims interface{}) error {
|
||||
token, err := j.Token(claims)
|
||||
if err != nil {
|
||||
ctx.StatusCode(500)
|
||||
@@ -418,18 +418,18 @@ type (
|
||||
Validate() error
|
||||
}
|
||||
claimsContextValidator interface {
|
||||
Validate(ctx context.Context) error
|
||||
Validate(ctx *context.Context) error
|
||||
}
|
||||
)
|
||||
|
||||
// IsValidated reports whether a token is already validated through
|
||||
// `VerifyToken`. It returns true when the claims are compatible
|
||||
// validators: a `Claims` value or a value that implements the `Validate() error` method.
|
||||
func IsValidated(ctx context.Context) bool { // see the `ReadClaims`.
|
||||
func IsValidated(ctx *context.Context) bool { // see the `ReadClaims`.
|
||||
return ctx.Values().Get(needsValidationContextKey) == nil
|
||||
}
|
||||
|
||||
func validateClaims(ctx context.Context, claims interface{}) (err error) {
|
||||
func validateClaims(ctx *context.Context, claims interface{}) (err error) {
|
||||
switch c := claims.(type) {
|
||||
case claimsValidator:
|
||||
err = c.ValidateWithLeeway(jwt.Expected{Time: time.Now()}, 0)
|
||||
@@ -467,7 +467,7 @@ func validateClaims(ctx context.Context, claims interface{}) (err error) {
|
||||
// VerifyToken verifies (and decrypts) the request token,
|
||||
// it also validates and binds the parsed token's claims to the "claimsPtr" (destination).
|
||||
// It does return a nil error on success.
|
||||
func (j *JWT) VerifyToken(ctx context.Context, claimsPtr interface{}) error {
|
||||
func (j *JWT) VerifyToken(ctx *context.Context, claimsPtr interface{}) error {
|
||||
var token string
|
||||
|
||||
for _, extract := range j.Extractors {
|
||||
@@ -520,7 +520,7 @@ const (
|
||||
//
|
||||
// A call of `ReadClaims` is required to validate and acquire the jwt claims
|
||||
// on the next request.
|
||||
func (j *JWT) Verify(ctx context.Context) {
|
||||
func (j *JWT) Verify(ctx *context.Context) {
|
||||
var raw json.RawMessage
|
||||
if err := j.VerifyToken(ctx, &raw); err != nil {
|
||||
ctx.StopWithStatus(401)
|
||||
@@ -534,7 +534,7 @@ func (j *JWT) Verify(ctx context.Context) {
|
||||
// ReadClaims binds the "claimsPtr" (destination)
|
||||
// to the verified (and decrypted) claims.
|
||||
// The `Verify` method should be called first (registered as middleware).
|
||||
func ReadClaims(ctx context.Context, claimsPtr interface{}) error {
|
||||
func ReadClaims(ctx *context.Context, claimsPtr interface{}) error {
|
||||
v := ctx.Values().Get(ClaimsContextKey)
|
||||
if v == nil {
|
||||
return ErrMissing
|
||||
@@ -589,7 +589,7 @@ func ReadClaims(ctx context.Context, claimsPtr interface{}) error {
|
||||
// }
|
||||
// [use claims...]
|
||||
// })
|
||||
func Get(ctx context.Context) (interface{}, error) {
|
||||
func Get(ctx *context.Context) (interface{}, error) {
|
||||
claims := ctx.Values().Get(ClaimsContextKey)
|
||||
if claims == nil {
|
||||
return nil, ErrMissing
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
// The SkipperFunc signature, used to serve the main request without logs.
|
||||
// See `Configuration` too.
|
||||
type SkipperFunc func(ctx context.Context) bool
|
||||
type SkipperFunc func(ctx *context.Context) bool
|
||||
|
||||
// Config contains the options for the logger middleware
|
||||
// can be optionally be passed to the `New`.
|
||||
@@ -71,7 +71,7 @@ type Config struct {
|
||||
LogFunc func(endTime time.Time, latency time.Duration, status, ip, method, path string, message interface{}, headerMessage interface{})
|
||||
// LogFuncCtx can be used instead of `LogFunc` if handlers need to customize the output based on
|
||||
// custom request-time information that the LogFunc isn't aware of.
|
||||
LogFuncCtx func(ctx context.Context, latency time.Duration)
|
||||
LogFuncCtx func(ctx *context.Context, latency time.Duration)
|
||||
// Skippers used to skip the logging i.e by `ctx.Path()` and serve
|
||||
// the next/main handler immediately.
|
||||
Skippers []SkipperFunc
|
||||
@@ -110,7 +110,7 @@ func (c *Config) buildSkipper() {
|
||||
return
|
||||
}
|
||||
skippersLocked := c.Skippers[0:]
|
||||
c.skip = func(ctx context.Context) bool {
|
||||
c.skip = func(ctx *context.Context) bool {
|
||||
for _, s := range skippersLocked {
|
||||
if s(ctx) {
|
||||
return true
|
||||
|
||||
@@ -36,7 +36,7 @@ func New(cfg ...Config) context.Handler {
|
||||
}
|
||||
|
||||
// Serve serves the middleware
|
||||
func (l *requestLoggerMiddleware) ServeHTTP(ctx context.Context) {
|
||||
func (l *requestLoggerMiddleware) ServeHTTP(ctx *context.Context) {
|
||||
// skip logs and serve the main request immediately
|
||||
if l.config.skip != nil {
|
||||
if l.config.skip(ctx) {
|
||||
|
||||
@@ -26,7 +26,7 @@ func New() context.Handler {
|
||||
threadcreateHandler := handlerconv.FromStd(pprof.Handler("threadcreate"))
|
||||
debugBlockHandler := handlerconv.FromStd(pprof.Handler("block"))
|
||||
|
||||
return func(ctx context.Context) {
|
||||
return func(ctx *context.Context) {
|
||||
ctx.ContentType("text/html")
|
||||
action := ctx.Params().Get("action")
|
||||
if action != "" {
|
||||
|
||||
@@ -35,7 +35,7 @@ func ExceedHandler(handler context.Handler) Option {
|
||||
// ClientData is an `Option` that can be passed at the `Limit` package-level function.
|
||||
// It accepts a function which provides the Iris Context and should return custom data
|
||||
// that will be stored to the Client and be retrieved as `Get(ctx).Client.Data` later on.
|
||||
func ClientData(clientDataFunc func(ctx context.Context) interface{}) Option {
|
||||
func ClientData(clientDataFunc func(ctx *context.Context) interface{}) Option {
|
||||
return func(l *Limiter) {
|
||||
l.clientDataFunc = clientDataFunc
|
||||
}
|
||||
@@ -79,8 +79,8 @@ type (
|
||||
// old clients from the memory. Limiter is not exposed by a function,
|
||||
// callers should use it inside an `Option` for the `Limit` package-level function.
|
||||
Limiter struct {
|
||||
clientDataFunc func(ctx context.Context) interface{} // fill the Client's Data field.
|
||||
exceedHandler context.Handler // when too many requests.
|
||||
clientDataFunc func(ctx *context.Context) interface{} // fill the Client's Data field.
|
||||
exceedHandler context.Handler // when too many requests.
|
||||
|
||||
limit rate.Limit
|
||||
burstSize int
|
||||
@@ -116,7 +116,7 @@ func Limit(limit float64, burst int, options ...Option) context.Handler {
|
||||
clients: make(map[string]*Client),
|
||||
limit: rate.Limit(limit),
|
||||
burstSize: burst,
|
||||
exceedHandler: func(ctx context.Context) {
|
||||
exceedHandler: func(ctx *context.Context) {
|
||||
ctx.StopWithStatus(429) // Too Many Requests.
|
||||
},
|
||||
}
|
||||
@@ -139,7 +139,7 @@ func (l *Limiter) Purge(condition func(*Client) bool) {
|
||||
l.mu.Unlock()
|
||||
}
|
||||
|
||||
func (l *Limiter) serveHTTP(ctx context.Context) {
|
||||
func (l *Limiter) serveHTTP(ctx *context.Context) {
|
||||
id := getIdentifier(ctx)
|
||||
l.mu.RLock()
|
||||
client, ok := l.clients[id]
|
||||
@@ -182,11 +182,11 @@ const identifierContextKey = "iris.ratelimit.identifier"
|
||||
|
||||
// SetIdentifier can be called manually from a handler or a middleare
|
||||
// to change the identifier per client. The default key for a client is its Remote IP.
|
||||
func SetIdentifier(ctx context.Context, key string) {
|
||||
func SetIdentifier(ctx *context.Context, key string) {
|
||||
ctx.Values().Set(identifierContextKey, key)
|
||||
}
|
||||
|
||||
func getIdentifier(ctx context.Context) string {
|
||||
func getIdentifier(ctx *context.Context) string {
|
||||
if entry, ok := ctx.Values().GetEntry(identifierContextKey); ok {
|
||||
return entry.ValueRaw.(string)
|
||||
}
|
||||
@@ -202,7 +202,7 @@ const clientContextKey = "iris.ratelimit.client"
|
||||
// You can read more about X-RateLimit response headers at:
|
||||
// https://tools.ietf.org/id/draft-polli-ratelimit-headers-00.html.
|
||||
// A good example of that is the GitHub API itself: https://developer.github.com/v3/#rate-limiting
|
||||
func Get(ctx context.Context) *Client {
|
||||
func Get(ctx *context.Context) *Client {
|
||||
if v := ctx.Values().Get(clientContextKey); v != nil {
|
||||
if c, ok := v.(*Client); ok {
|
||||
return c
|
||||
|
||||
@@ -42,7 +42,7 @@ var Client = netutil.Client(time.Duration(20 * time.Second))
|
||||
//
|
||||
// Use `SiteVerify` to verify a request inside another handler if needed.
|
||||
func New(secret string) context.Handler {
|
||||
return func(ctx context.Context) {
|
||||
return func(ctx *context.Context) {
|
||||
if SiteVerify(ctx, secret).Success {
|
||||
ctx.Next()
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func New(secret string) context.Handler {
|
||||
// then validation passed.
|
||||
//
|
||||
// Use `New` for middleware use instead.
|
||||
func SiteVerify(ctx context.Context, secret string) (response Response) {
|
||||
func SiteVerify(ctx *context.Context, secret string) (response Response) {
|
||||
generatedResponseID := ctx.FormValue("g-recaptcha-response")
|
||||
if generatedResponseID == "" {
|
||||
response.ErrorCodes = append(response.ErrorCodes,
|
||||
@@ -113,7 +113,7 @@ var recaptchaForm = `<form action="%s" method="POST">
|
||||
// Example Code:
|
||||
//
|
||||
// Method: "POST" | Path: "/contact"
|
||||
// func postContact(ctx context.Context) {
|
||||
// func postContact(ctx *context.Context) {
|
||||
// // [...]
|
||||
// response := recaptcha.SiteVerify(ctx, recaptchaSecret)
|
||||
//
|
||||
@@ -125,7 +125,7 @@ var recaptchaForm = `<form action="%s" method="POST">
|
||||
// }
|
||||
//
|
||||
// Method: "GET" | Path: "/contact"
|
||||
// func getContact(ctx context.Context) {
|
||||
// func getContact(ctx *context.Context) {
|
||||
// // render the recaptcha form
|
||||
// ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, "/contact"))
|
||||
// }
|
||||
|
||||
@@ -13,7 +13,7 @@ func init() {
|
||||
context.SetHandlerName("iris/middleware/recover.*", "iris.recover")
|
||||
}
|
||||
|
||||
func getRequestLogs(ctx context.Context) string {
|
||||
func getRequestLogs(ctx *context.Context) string {
|
||||
var status, ip, method, path string
|
||||
status = strconv.Itoa(ctx.GetStatusCode())
|
||||
path = ctx.Path()
|
||||
@@ -27,7 +27,7 @@ func getRequestLogs(ctx context.Context) string {
|
||||
// it recovers from panics and logs
|
||||
// the panic message to the application's logger "Warn" level.
|
||||
func New() context.Handler {
|
||||
return func(ctx context.Context) {
|
||||
return func(ctx *context.Context) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
if ctx.IsStopped() {
|
||||
|
||||
@@ -14,7 +14,7 @@ const xRequestIDHeaderValue = "X-Request-Id"
|
||||
|
||||
// Generator defines the function which should extract or generate
|
||||
// a Request ID. See `DefaultGenerator` and `New` package-level functions.
|
||||
type Generator func(ctx context.Context) string
|
||||
type Generator func(ctx *context.Context) string
|
||||
|
||||
// DefaultGenerator is the default `Generator` that is used
|
||||
// when nil is passed on `New` package-level function.
|
||||
@@ -22,7 +22,7 @@ type Generator func(ctx context.Context) string
|
||||
// or, if missing, it generates a new UUID(v4) and sets the header and context value.
|
||||
//
|
||||
// See `Get` package-level function too.
|
||||
var DefaultGenerator Generator = func(ctx context.Context) string {
|
||||
var DefaultGenerator Generator = func(ctx *context.Context) string {
|
||||
id := ctx.GetHeader(xRequestIDHeaderValue)
|
||||
|
||||
if id == "" {
|
||||
@@ -50,7 +50,7 @@ func New(generator ...Generator) context.Handler {
|
||||
gen = generator[0]
|
||||
}
|
||||
|
||||
return func(ctx context.Context) {
|
||||
return func(ctx *context.Context) {
|
||||
if Get(ctx) != "" {
|
||||
ctx.Next()
|
||||
return
|
||||
@@ -71,7 +71,7 @@ func New(generator ...Generator) context.Handler {
|
||||
// Get returns the Request ID or empty string.
|
||||
//
|
||||
// A shortcut of `context.GetID().(string)`.
|
||||
func Get(ctx context.Context) string {
|
||||
func Get(ctx *context.Context) string {
|
||||
v := ctx.GetID()
|
||||
if v != nil {
|
||||
if id, ok := v.(string); ok {
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestRequestID(t *testing.T) {
|
||||
const expectedCustomID = "my_id"
|
||||
custom := app.Party("/custom")
|
||||
{
|
||||
customGen := func(ctx context.Context) string {
|
||||
customGen := func(ctx *context.Context) string {
|
||||
return expectedCustomID
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestRequestID(t *testing.T) {
|
||||
const expectedErrMsg = "no id"
|
||||
customWithErr := app.Party("/custom_err")
|
||||
{
|
||||
customGen := func(ctx context.Context) string {
|
||||
customGen := func(ctx *context.Context) string {
|
||||
ctx.StopWithText(iris.StatusUnauthorized, expectedErrMsg)
|
||||
return ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user