From 5852327f306f0081eeb9eaeed1272d0d9b1d772a Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Wed, 8 Apr 2020 17:27:23 +0300 Subject: [PATCH] move the hero binding logic to the new 'context.ReadBody' Former-commit-id: d336bb1ec6ca66087fe9e8d28b38062508b45227 --- HISTORY.md | 1 + context/context.go | 54 +++++++++++++++++++++++++++++++++++++++++++++- hero/binding.go | 40 +--------------------------------- 3 files changed, 55 insertions(+), 40 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index b2c9d35b..79674620 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -180,6 +180,7 @@ New Context Methods: - `context.MsgPack(interface{})` sends msgpack format data to the client - `context.ReadProtobuf(ptr)` binds request body to a proto message - `context.ReadMsgPack(ptr)` binds request body of a msgpack format to a struct +- `context.ReadBody(ptr)` binds the request body to the "ptr" depending on the request's Method and ContentType - `context.Defer(Handler)` works like `Party.Done` but for the request life-cycle. - `context.ReflectValue() []reflect.Value` stores and returns the `[]reflect.ValueOf(context)` - `context.Controller() reflect.Value` returns the current MVC Controller value (when fired from inside a controller's method). diff --git a/context/context.go b/context/context.go index 7cbcc974..6719e8b7 100644 --- a/context/context.go +++ b/context/context.go @@ -624,6 +624,12 @@ type Context interface { ReadProtobuf(ptr proto.Message) error // ReadMsgPack binds the request body of msgpack format to the "ptr" and returns any error. ReadMsgPack(ptr interface{}) error + // ReadBody binds the request body to the "ptr" depending on the HTTP Method and the Request's Content-Type. + // If a GET method request then it reads from a form (or URL Query), otherwise + // it tries to match (depending on the request content-type) the data format e.g. + // JSON, Protobuf, MsgPack, XML, YAML, MultipartForm and binds the result to the "ptr". + ReadBody(ptr interface{}) error + // +------------------------------------------------------------+ // | Body (raw) Writers | // +------------------------------------------------------------+ @@ -1931,9 +1937,18 @@ func (ctx *context) GetContentType() string { return ctx.writer.Header().Get(ContentTypeHeaderKey) } +func trimHeaderValue(cType string) string { + for i, char := range cType { + if char == ' ' || char == ';' { + return cType[:i] + } + } + return cType +} + // GetContentType returns the request's header value of "Content-Type". func (ctx *context) GetContentTypeRequested() string { - return ctx.GetHeader(ContentTypeHeaderKey) + return trimHeaderValue(ctx.GetHeader(ContentTypeHeaderKey)) } // GetContentLength returns the request's header value of "Content-Length". @@ -2707,6 +2722,43 @@ func (ctx *context) ReadMsgPack(ptr interface{}) error { return msgpack.Unmarshal(rawData, ptr) } +// ReadBody binds the request body to the "ptr" depending on the HTTP Method and the Request's Content-Type. +// If a GET method request then it reads from a form (or URL Query), otherwise +// it tries to match (depending on the request content-type) the data format e.g. +// JSON, Protobuf, MsgPack, XML, YAML, MultipartForm and binds the result to the "ptr". +func (ctx *context) ReadBody(ptr interface{}) error { + if ctx.Method() == http.MethodGet { + return ctx.ReadForm(ptr) + } + + switch ctx.GetContentTypeRequested() { + case ContentXMLHeaderValue: + return ctx.ReadXML(ptr) + case ContentYAMLHeaderValue: + return ctx.ReadYAML(ptr) + case ContentFormHeaderValue, ContentFormMultipartHeaderValue: + return ctx.ReadForm(ptr) + case ContentJSONHeaderValue: + return ctx.ReadJSON(ptr) + case ContentProtobufHeaderValue: + msg, ok := ptr.(proto.Message) + if !ok { + return ErrContentNotSupported + } + + return ctx.ReadProtobuf(msg) + case ContentMsgPackHeaderValue, ContentMsgPack2HeaderValue: + return ctx.ReadMsgPack(ptr) + default: + if ctx.Request().URL.RawQuery != "" { + // try read from query. + return ctx.ReadQuery(ptr) + } + // otherwise default to JSON. + return ctx.ReadJSON(ptr) + } +} + // +------------------------------------------------------------+ // | Body (raw) Writers | // +------------------------------------------------------------+ diff --git a/hero/binding.go b/hero/binding.go index c9ab240b..8695df7c 100644 --- a/hero/binding.go +++ b/hero/binding.go @@ -4,11 +4,8 @@ import ( "fmt" "reflect" "sort" - "strings" "github.com/kataras/iris/v12/context" - - "github.com/golang/protobuf/proto" ) // binding contains the Dependency and the Input, it's the result of a function or struct + dependencies. @@ -328,42 +325,7 @@ func payloadBinding(index int, typ reflect.Type) *binding { newValue = reflect.New(indirectType(input.Type)) ptr := newValue.Interface() - - contentType := ctx.GetContentTypeRequested() - if contentType != "" { - if idx := strings.IndexByte(contentType, ';'); idx > 0 { - // e.g. contentType=[multipart/form-data] trailing: ; boundary=4e2946168dbbac - contentType = contentType[:idx] - } - } - - switch contentType { - case context.ContentXMLHeaderValue: - err = ctx.ReadXML(ptr) - case context.ContentYAMLHeaderValue: - err = ctx.ReadYAML(ptr) - case context.ContentFormHeaderValue, context.ContentFormMultipartHeaderValue: - err = ctx.ReadForm(ptr) - case context.ContentJSONHeaderValue: - err = ctx.ReadJSON(ptr) - case context.ContentProtobufHeaderValue: - if msg, ok := ptr.(proto.Message); ok { - err = ctx.ReadProtobuf(msg) - } else { - err = context.ErrContentNotSupported - } - case context.ContentMsgPackHeaderValue, context.ContentMsgPack2HeaderValue: - err = ctx.ReadMsgPack(ptr) - default: - if ctx.Request().URL.RawQuery != "" { - // try read from query. - err = ctx.ReadQuery(ptr) - } else { - // otherwise default to JSON. - err = ctx.ReadJSON(ptr) - } - } - + err = ctx.ReadBody(ptr) if !wasPtr { newValue = newValue.Elem() }