1
0
mirror of https://github.com/kataras/iris.git synced 2025-12-18 02:17:05 +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:
Gerasimos (Makis) Maropoulos
2020-07-10 23:21:09 +03:00
parent 645da2b2ef
commit 0f113dfcda
112 changed files with 2119 additions and 3390 deletions

View File

@@ -176,7 +176,7 @@ func getBindingsFor(inputs []reflect.Type, deps []*Dependency, paramsCount int)
// wrap the existing dependency handler.
paramHandler := paramDependencyHandler(getParamIndex())
prevHandler := d.Handle
d.Handle = func(ctx context.Context, input *Input) (reflect.Value, error) {
d.Handle = func(ctx *context.Context, input *Input) (reflect.Value, error) {
v, err := paramHandler(ctx, input)
if err != nil {
v, err = prevHandler(ctx, input)
@@ -315,7 +315,7 @@ func paramBinding(index, paramIndex int, typ reflect.Type) *binding {
}
func paramDependencyHandler(paramIndex int) DependencyHandler {
return func(ctx context.Context, input *Input) (reflect.Value, error) {
return func(ctx *context.Context, input *Input) (reflect.Value, error) {
if ctx.Params().Len() <= paramIndex {
return emptyValue, ErrSeeOther
}
@@ -329,7 +329,7 @@ func paramDependencyHandler(paramIndex int) DependencyHandler {
func payloadBinding(index int, typ reflect.Type) *binding {
return &binding{
Dependency: &Dependency{
Handle: func(ctx context.Context, input *Input) (newValue reflect.Value, err error) {
Handle: func(ctx *context.Context, input *Input) (newValue reflect.Value, err error) {
wasPtr := input.Type.Kind() == reflect.Ptr
if serveDepsV := ctx.Values().Get(context.DependenciesContextKey); serveDepsV != nil {

View File

@@ -45,9 +45,9 @@ func TestGetBindingsForFunc(t *testing.T) {
var testRequestTyp = reflect.TypeOf(testRequest{})
var deps = []*Dependency{
NewDependency(func(ctx context.Context) testRequest { return testRequest{Email: "should be ignored"} }),
NewDependency(func(ctx *context.Context) testRequest { return testRequest{Email: "should be ignored"} }),
NewDependency(42),
NewDependency(func(ctx context.Context) (v testRequest, err error) {
NewDependency(func(ctx *context.Context) (v testRequest, err error) {
err = ctx.ReadJSON(&v)
return
}),
@@ -55,7 +55,7 @@ func TestGetBindingsForFunc(t *testing.T) {
NewDependency("should not be ignored when requested"),
// Dependencies like these should always be registered last.
NewDependency(func(ctx context.Context, input *Input) (newValue reflect.Value, err error) {
NewDependency(func(ctx *context.Context, input *Input) (newValue reflect.Value, err error) {
wasPtr := input.Type.Kind() == reflect.Ptr
newValue = reflect.New(indirectType(input.Type))
@@ -75,19 +75,19 @@ func TestGetBindingsForFunc(t *testing.T) {
Expected []*binding
}{
{ // 0
Func: func(ctx context.Context) {
Func: func(ctx *context.Context) {
ctx.WriteString("t1")
},
Expected: []*binding{contextBinding(0)},
},
{ // 1
Func: func(ctx context.Context) error {
Func: func(ctx *context.Context) error {
return fmt.Errorf("err1")
},
Expected: []*binding{contextBinding(0)},
},
{ // 2
Func: func(ctx context.Context) testResponse {
Func: func(ctx *context.Context) testResponse {
return testResponse{Name: "name"}
},
Expected: []*binding{contextBinding(0)},
@@ -105,19 +105,19 @@ func TestGetBindingsForFunc(t *testing.T) {
Expected: []*binding{{Dependency: deps[2], Input: &Input{Index: 0, Type: testRequestTyp}}},
},
{ // 5
Func: func(ctx context.Context, in testRequest) testResponse {
Func: func(ctx *context.Context, in testRequest) testResponse {
return testResponse{Name: "(with ctx) email of " + in.Email}
},
Expected: []*binding{contextBinding(0), {Dependency: deps[2], Input: &Input{Index: 1, Type: testRequestTyp}}},
},
{ // 6
Func: func(in testRequest, ctx context.Context) testResponse { // reversed.
Func: func(in testRequest, ctx *context.Context) testResponse { // reversed.
return testResponse{Name: "(with ctx) email of " + in.Email}
},
Expected: []*binding{{Dependency: deps[2], Input: &Input{Index: 0, Type: testRequestTyp}}, contextBinding(1)},
},
{ // 7
Func: func(in testRequest, ctx context.Context, in2 string) testResponse { // reversed.
Func: func(in testRequest, ctx *context.Context, in2 string) testResponse { // reversed.
return testResponse{Name: "(with ctx) email of " + in.Email + "and in2: " + in2}
},
Expected: []*binding{
@@ -133,7 +133,7 @@ func TestGetBindingsForFunc(t *testing.T) {
},
},
{ // 8
Func: func(in testRequest, ctx context.Context, in2, in3 string) testResponse { // reversed.
Func: func(in testRequest, ctx *context.Context, in2, in3 string) testResponse { // reversed.
return testResponse{Name: "(with ctx) email of " + in.Email + " | in2: " + in2 + " in3: " + in3}
},
Expected: []*binding{
@@ -153,7 +153,7 @@ func TestGetBindingsForFunc(t *testing.T) {
},
},
{ // 9
Func: func(ctx context.Context, in testRequest, in2 testRequest2) testResponse {
Func: func(ctx *context.Context, in testRequest, in2 testRequest2) testResponse {
return testResponse{Name: fmt.Sprintf("(with ctx) email of %s and in2.Age %d", in.Email, in2.Age)}
},
Expected: []*binding{
@@ -363,7 +363,7 @@ func TestBindingsForStruct(t *testing.T) {
}
var depsInterfaces = []*Dependency{
NewDependency(func(ctx context.Context) interface{} {
NewDependency(func(ctx *context.Context) interface{} {
return "name"
}),
}

View File

@@ -32,7 +32,7 @@ type Container struct {
Dependencies []*Dependency
// GetErrorHandler should return a valid `ErrorHandler` to handle bindings AND handler dispatch errors.
// Defaults to a functon which returns the `DefaultErrorHandler`.
GetErrorHandler func(context.Context) ErrorHandler // cannot be nil.
GetErrorHandler func(*context.Context) ErrorHandler // cannot be nil.
// resultHandlers is a list of functions that serve the return struct value of a function handler.
// Defaults to "defaultResultHandler" but it can be overridden.
@@ -43,13 +43,13 @@ type Container struct {
// Contains the iris context, standard context, iris sessions and time dependencies.
var BuiltinDependencies = []*Dependency{
// iris context dependency.
NewDependency(func(ctx context.Context) context.Context { return ctx }).Explicitly(),
NewDependency(func(ctx *context.Context) *context.Context { return ctx }).Explicitly(),
// standard context dependency.
NewDependency(func(ctx context.Context) stdContext.Context {
NewDependency(func(ctx *context.Context) stdContext.Context {
return ctx.Request().Context()
}).Explicitly(),
// iris session dependency.
NewDependency(func(ctx context.Context) *sessions.Session {
NewDependency(func(ctx *context.Context) *sessions.Session {
session := sessions.Get(ctx)
if session == nil {
panic("binding: session is nil - app.Use(sess.Handler()) to fix it")
@@ -58,19 +58,19 @@ var BuiltinDependencies = []*Dependency{
return session
}).Explicitly(),
// time.Time to time.Now dependency.
NewDependency(func(ctx context.Context) time.Time {
NewDependency(func(ctx *context.Context) time.Time {
return time.Now()
}).Explicitly(),
// standard http Request dependency.
NewDependency(func(ctx context.Context) *http.Request {
NewDependency(func(ctx *context.Context) *http.Request {
return ctx.Request()
}).Explicitly(),
// standard http ResponseWriter dependency.
NewDependency(func(ctx context.Context) http.ResponseWriter {
NewDependency(func(ctx *context.Context) http.ResponseWriter {
return ctx.ResponseWriter()
}).Explicitly(),
// http headers dependency.
NewDependency(func(ctx context.Context) http.Header {
NewDependency(func(ctx *context.Context) http.Header {
return ctx.Request().Header
}).Explicitly(),
// payload and param bindings are dynamically allocated and declared at the end of the `binding` source file.
@@ -86,7 +86,7 @@ func New(dependencies ...interface{}) *Container {
c := &Container{
Sorter: sortByNumMethods,
Dependencies: deps,
GetErrorHandler: func(context.Context) ErrorHandler {
GetErrorHandler: func(*context.Context) ErrorHandler {
return DefaultErrorHandler
},
}

View File

@@ -10,7 +10,7 @@ import (
type (
// DependencyHandler is the native function declaration which implementors should return a value match to an input.
DependencyHandler func(ctx context.Context, input *Input) (reflect.Value, error)
DependencyHandler func(ctx *context.Context, input *Input) (reflect.Value, error)
// Dependency describes the design-time dependency to be injected at serve time.
// Contains its source location, the dependency handler (provider) itself and information
// such as static for static struct values or explicit to bind a value to its exact DestType and not if just assignable to it (interfaces).
@@ -92,11 +92,11 @@ func fromDependencyHandler(_ reflect.Value, dest *Dependency) bool {
dependency := dest.OriginalValue
handler, ok := dependency.(DependencyHandler)
if !ok {
handler, ok = dependency.(func(context.Context, *Input) (reflect.Value, error))
handler, ok = dependency.(func(*context.Context, *Input) (reflect.Value, error))
if !ok {
// It's almost a handler, only the second `Input` argument is missing.
if h, is := dependency.(func(context.Context) (reflect.Value, error)); is {
handler = func(ctx context.Context, _ *Input) (reflect.Value, error) {
if h, is := dependency.(func(*context.Context) (reflect.Value, error)); is {
handler = func(ctx *context.Context, _ *Input) (reflect.Value, error) {
return h(ctx)
}
ok = is
@@ -114,7 +114,7 @@ func fromDependencyHandler(_ reflect.Value, dest *Dependency) bool {
func fromStructValue(v reflect.Value, dest *Dependency) bool {
if !isFunc(v) {
// It's just a static value.
handler := func(context.Context, *Input) (reflect.Value, error) {
handler := func(*context.Context, *Input) (reflect.Value, error) {
return v, nil
}
@@ -183,7 +183,7 @@ func handlerFromFunc(v reflect.Value, typ reflect.Type) DependencyHandler {
hasErrorOut := typ.NumOut() == 2 // if two, always an error type here.
hasInputIn := typ.NumIn() == 2 && typ.In(1) == inputTyp
return func(ctx context.Context, input *Input) (reflect.Value, error) {
return func(ctx *context.Context, input *Input) (reflect.Value, error) {
inputs := ctx.ReflectValue()
if hasInputIn {
inputs = append(inputs, input.selfValue)
@@ -214,7 +214,7 @@ func fromDependentFunc(v reflect.Value, dest *Dependency, funcDependencies []*De
firstOutIsError := numOut == 1 && isError(typ.Out(0))
secondOutIsError := numOut == 2 && isError(typ.Out(1))
handler := func(ctx context.Context, _ *Input) (reflect.Value, error) {
handler := func(ctx *context.Context, _ *Input) (reflect.Value, error) {
inputs := make([]reflect.Value, numIn)
for _, binding := range bindings {

View File

@@ -25,54 +25,54 @@ func TestDependency(t *testing.T) {
Expected: struct{ Name string }{"name"},
},
{
Dependency: func(context.Context, *Input) (reflect.Value, error) {
Dependency: func(*context.Context, *Input) (reflect.Value, error) {
return reflect.ValueOf(42), nil
},
Expected: 42,
},
{
Dependency: DependencyHandler(func(context.Context, *Input) (reflect.Value, error) {
Dependency: DependencyHandler(func(*context.Context, *Input) (reflect.Value, error) {
return reflect.ValueOf(255), nil
}),
Expected: 255,
},
{
Dependency: func(context.Context) (reflect.Value, error) {
Dependency: func(*context.Context) (reflect.Value, error) {
return reflect.ValueOf("OK without Input"), nil
},
Expected: "OK without Input",
},
{
Dependency: func(context.Context, ...string) (reflect.Value, error) {
Dependency: func(*context.Context, ...string) (reflect.Value, error) {
return reflect.ValueOf("OK variadic ignored"), nil
},
Expected: "OK variadic ignored",
},
{
Dependency: func(context.Context) reflect.Value {
Dependency: func(*context.Context) reflect.Value {
return reflect.ValueOf("OK without Input and error")
},
Expected: "OK without Input and error",
},
{
Dependency: func(context.Context, ...int) reflect.Value {
Dependency: func(*context.Context, ...int) reflect.Value {
return reflect.ValueOf("OK without error and variadic ignored")
},
Expected: "OK without error and variadic ignored",
},
{
Dependency: func(context.Context) interface{} {
Dependency: func(*context.Context) interface{} {
return "1"
},
Expected: "1",
},
{
Dependency: func(context.Context) interface{} {
Dependency: func(*context.Context) interface{} {
return false
},
Expected: false,

View File

@@ -11,9 +11,9 @@ import (
)
// ResultHandler describes the function type which should serve the "v" struct value.
type ResultHandler func(ctx context.Context, v interface{}) error
type ResultHandler func(ctx *context.Context, v interface{}) error
func defaultResultHandler(ctx context.Context, v interface{}) error {
func defaultResultHandler(ctx *context.Context, v interface{}) error {
if p, ok := v.(PreflightResult); ok {
if err := p.Preflight(ctx); err != nil {
return err
@@ -57,7 +57,7 @@ func defaultResultHandler(ctx context.Context, v interface{}) error {
// Example at: https://github.com/kataras/iris/tree/master/_examples/dependency-injection/overview.
type Result interface {
// Dispatch should send a response to the client.
Dispatch(context.Context)
Dispatch(*context.Context)
}
// PreflightResult is an interface which implementers
@@ -73,7 +73,7 @@ type Result interface {
// The caller can manage it at the handler itself. However,
// to reduce thoese type of duplications it's preferable to use such a standard interface instead.
type PreflightResult interface {
Preflight(context.Context) error
Preflight(*context.Context) error
}
var defaultFailureResponse = Response{Code: DefaultErrStatusCode}
@@ -115,7 +115,7 @@ type compatibleErr interface {
}
// dispatchErr writes the error to the response.
func dispatchErr(ctx context.Context, status int, err error) bool {
func dispatchErr(ctx *context.Context, status int, err error) bool {
if err == nil {
return false
}
@@ -154,7 +154,7 @@ func dispatchErr(ctx context.Context, status int, err error) bool {
// Result or (Result, error) and so on...
//
// where Get is an HTTP METHOD.
func dispatchFuncResult(ctx context.Context, values []reflect.Value, handler ResultHandler) error {
func dispatchFuncResult(ctx *context.Context, values []reflect.Value, handler ResultHandler) error {
if len(values) == 0 {
return nil
}
@@ -324,7 +324,7 @@ func dispatchFuncResult(ctx context.Context, values []reflect.Value, handler Res
// dispatchCommon is being used internally to send
// commonly used data to the response writer with a smart way.
func dispatchCommon(ctx context.Context,
func dispatchCommon(ctx *context.Context,
statusCode int, contentType string, content []byte, v interface{}, handler ResultHandler, found bool) error {
// if we have a false boolean as a return value
// then skip everything and fire a not found,
@@ -416,7 +416,7 @@ type Response struct {
var _ Result = Response{}
// Dispatch writes the response result to the context's response writer.
func (r Response) Dispatch(ctx context.Context) {
func (r Response) Dispatch(ctx *context.Context) {
if dispatchErr(ctx, r.Code, r.Err) {
return
}
@@ -492,7 +492,7 @@ func ensureExt(s string) string {
// Dispatch writes the template filename, template layout and (any) data to the client.
// Completes the `Result` interface.
func (r View) Dispatch(ctx context.Context) { // r as Response view.
func (r View) Dispatch(ctx *context.Context) { // r as Response view.
if dispatchErr(ctx, r.Code, r.Err) {
return
}
@@ -520,9 +520,7 @@ func (r View) Dispatch(ctx context.Context) { // r as Response view.
// else check if r.Data is map or struct, if struct convert it to map,
// do a range loop and modify the data one by one.
// context.Map is actually a map[string]interface{} but we have to make that check:
if m, ok := r.Data.(map[string]interface{}); ok {
setViewData(ctx, m)
} else if m, ok := r.Data.(context.Map); ok {
if m, ok := r.Data.(context.Map); ok {
setViewData(ctx, m)
} else if reflect.Indirect(reflect.ValueOf(r.Data)).Kind() == reflect.Struct {
setViewData(ctx, structs.Map(r))
@@ -534,7 +532,7 @@ func (r View) Dispatch(ctx context.Context) { // r as Response view.
}
}
func setViewData(ctx context.Context, data map[string]interface{}) {
func setViewData(ctx *context.Context, data map[string]interface{}) {
for k, v := range data {
ctx.ViewData(k, v)
}

View File

@@ -13,15 +13,15 @@ type (
// Handles non-nil errors return from a hero handler or a controller's method (see `getBindingsFor` and `Handler`)
// the error may return from a request-scoped dependency too (see `Handler`).
ErrorHandler interface {
HandleError(context.Context, error)
HandleError(*context.Context, error)
}
// ErrorHandlerFunc implements the `ErrorHandler`.
// It describes the type defnition for an error function handler.
ErrorHandlerFunc func(context.Context, error)
ErrorHandlerFunc func(*context.Context, error)
)
// HandleError fires when a non-nil error returns from a request-scoped dependency at serve-time or the handler itself.
func (fn ErrorHandlerFunc) HandleError(ctx context.Context, err error) {
func (fn ErrorHandlerFunc) HandleError(ctx *context.Context, err error) {
fn(ctx, err)
}
@@ -42,7 +42,7 @@ var (
// DefaultErrorHandler is the default error handler which is fired
// when a function returns a non-nil error or a request-scoped dependency failed to binded.
DefaultErrorHandler = ErrorHandlerFunc(func(ctx context.Context, err error) {
DefaultErrorHandler = ErrorHandlerFunc(func(ctx *context.Context, err error) {
if err != ErrStopExecution {
if status := ctx.GetStatusCode(); status == 0 || !context.StatusCodeNotSuccessful(status) {
ctx.StatusCode(DefaultErrStatusCode)
@@ -67,7 +67,7 @@ func makeHandler(fn interface{}, c *Container, paramsCount int) context.Handler
// 1. A handler which returns just an error, handle it faster.
if handlerWithErr, ok := isHandlerWithError(fn); ok {
return func(ctx context.Context) {
return func(ctx *context.Context) {
if err := handlerWithErr(ctx); err != nil {
c.GetErrorHandler(ctx).HandleError(ctx, err)
}
@@ -85,7 +85,7 @@ func makeHandler(fn interface{}, c *Container, paramsCount int) context.Handler
resultHandler = c.resultHandlers[lidx-i](resultHandler)
}
return func(ctx context.Context) {
return func(ctx *context.Context) {
inputs := make([]reflect.Value, numIn)
for _, binding := range bindings {
@@ -131,15 +131,15 @@ func isHandler(fn interface{}) (context.Handler, bool) {
return handler, ok
}
if handler, ok := fn.(func(context.Context)); ok {
if handler, ok := fn.(func(*context.Context)); ok {
return handler, ok
}
return nil, false
}
func isHandlerWithError(fn interface{}) (func(context.Context) error, bool) {
if handlerWithErr, ok := fn.(func(context.Context) error); ok {
func isHandlerWithError(fn interface{}) (func(*context.Context) error, bool) {
if handlerWithErr, ok := fn.(func(*context.Context) error); ok {
return handlerWithErr, true
}

View File

@@ -13,7 +13,7 @@ func TestPathParams(t *testing.T) {
got = firstname + lastname
})
h.Register(func(ctx context.Context) func() string { return func() string { return "" } })
h.Register(func(ctx *context.Context) func() string { return func() string { return "" } })
handlerWithOther := h.Handler(func(f func() string, firstname string, lastname string) {
got = f() + firstname + lastname
})

View File

@@ -58,11 +58,11 @@ func toError(v reflect.Value) error {
return v.Interface().(error)
}
var contextTyp = reflect.TypeOf((*context.Context)(nil)).Elem()
var contextType = reflect.TypeOf((*context.Context)(nil))
// isContext returns true if the "typ" is a type of Context.
func isContext(typ reflect.Type) bool {
return typ.Implements(contextTyp)
return typ == contextType
}
var errorHandlerTyp = reflect.TypeOf((*ErrorHandler)(nil)).Elem()

View File

@@ -92,7 +92,7 @@ func makeStruct(structPtr interface{}, c *Container, partyParamsCount int) *Stru
Explicitly().
DestType = typ
newContainer.GetErrorHandler = func(ctx context.Context) ErrorHandler {
newContainer.GetErrorHandler = func(ctx *context.Context) ErrorHandler {
if isErrHandler {
return ctx.Controller().Interface().(ErrorHandler)
}
@@ -108,7 +108,7 @@ func makeStruct(structPtr interface{}, c *Container, partyParamsCount int) *Stru
// If the dependencies are all static then these are already set-ed at the initialization of this Struct
// and the same struct value instance will be returned, ignoring the Context. Otherwise
// a new struct value with filled fields by its pre-calculated bindings will be returned instead.
func (s *Struct) Acquire(ctx context.Context) (reflect.Value, error) {
func (s *Struct) Acquire(ctx *context.Context) (reflect.Value, error) {
if s.Singleton {
ctx.Values().Set(context.ControllerContextKey, s.ptrValue)
return s.ptrValue, nil