1
0
mirror of https://github.com/labstack/echo.git synced 2024-11-24 08:22:21 +02:00

Support internal error when Bind() data #888 (#1164)

This commit is contained in:
Thuc Le 2018-09-29 00:41:13 +07:00 committed by Vishal Rana
parent eb84122d4e
commit f7470482fe
4 changed files with 41 additions and 18 deletions

18
bind.go
View File

@ -33,7 +33,7 @@ func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
if req.ContentLength == 0 {
if req.Method == GET || req.Method == DELETE {
if err = b.bindData(i, c.QueryParams(), "query"); err != nil {
return NewHTTPError(http.StatusBadRequest, err.Error())
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
}
return
}
@ -44,28 +44,32 @@ func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
case strings.HasPrefix(ctype, MIMEApplicationJSON):
if err = json.NewDecoder(req.Body).Decode(i); err != nil {
if ute, ok := err.(*json.UnmarshalTypeError); ok {
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, field=%v, offset=%v", ute.Type, ute.Value, ute.Field, ute.Offset))
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, field=%v, offset=%v", ute.Type, ute.Value, ute.Field, ute.Offset)).SetInternal(err)
} else if se, ok := err.(*json.SyntaxError); ok {
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error()))
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error())).SetInternal(err)
} else {
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
}
return NewHTTPError(http.StatusBadRequest, err.Error())
}
case strings.HasPrefix(ctype, MIMEApplicationXML), strings.HasPrefix(ctype, MIMETextXML):
if err = xml.NewDecoder(req.Body).Decode(i); err != nil {
if ute, ok := err.(*xml.UnsupportedTypeError); ok {
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error()))
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error())).SetInternal(err)
} else if se, ok := err.(*xml.SyntaxError); ok {
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: line=%v, error=%v", se.Line, se.Error()))
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: line=%v, error=%v", se.Line, se.Error())).SetInternal(err)
} else {
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
}
return NewHTTPError(http.StatusBadRequest, err.Error())
}
case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
params, err := c.FormParams()
if err != nil {
return NewHTTPError(http.StatusBadRequest, err.Error())
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
}
if err = b.bindData(i, params, "form"); err != nil {
return NewHTTPError(http.StatusBadRequest, err.Error())
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
}
default:
return ErrUnsupportedMediaType

View File

@ -2,11 +2,15 @@ package echo
import (
"bytes"
"encoding/json"
"encoding/xml"
"errors"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"reflect"
"strconv"
"strings"
"testing"
"time"
@ -117,19 +121,24 @@ var values = map[string][]string{
func TestBindJSON(t *testing.T) {
testBindOkay(t, strings.NewReader(userJSON), MIMEApplicationJSON)
testBindError(t, strings.NewReader(invalidContent), MIMEApplicationJSON)
testBindError(t, strings.NewReader(invalidContent), MIMEApplicationJSON, &json.SyntaxError{})
testBindError(t, strings.NewReader(userJSONInvalidType), MIMEApplicationJSON, &json.UnmarshalTypeError{})
}
func TestBindXML(t *testing.T) {
testBindOkay(t, strings.NewReader(userXML), MIMEApplicationXML)
testBindError(t, strings.NewReader(invalidContent), MIMEApplicationXML)
testBindError(t, strings.NewReader(invalidContent), MIMEApplicationXML, errors.New(""))
testBindError(t, strings.NewReader(userXMLConvertNumberError), MIMEApplicationXML, &strconv.NumError{})
testBindError(t, strings.NewReader(userXMLUnsupportedTypeError), MIMEApplicationXML, &xml.SyntaxError{})
testBindOkay(t, strings.NewReader(userXML), MIMETextXML)
testBindError(t, strings.NewReader(invalidContent), MIMETextXML)
testBindError(t, strings.NewReader(invalidContent), MIMETextXML, errors.New(""))
testBindError(t, strings.NewReader(userXMLConvertNumberError), MIMETextXML, &strconv.NumError{})
testBindError(t, strings.NewReader(userXMLUnsupportedTypeError), MIMETextXML, &xml.SyntaxError{})
}
func TestBindForm(t *testing.T) {
testBindOkay(t, strings.NewReader(userForm), MIMEApplicationForm)
testBindError(t, nil, MIMEApplicationForm)
testBindError(t, nil, MIMEApplicationForm, nil)
e := New()
req := httptest.NewRequest(POST, "/", strings.NewReader(userForm))
rec := httptest.NewRecorder()
@ -224,7 +233,7 @@ func TestBindMultipartForm(t *testing.T) {
}
func TestBindUnsupportedMediaType(t *testing.T) {
testBindError(t, strings.NewReader(invalidContent), MIMEApplicationJSON)
testBindError(t, strings.NewReader(invalidContent), MIMEApplicationJSON, &json.SyntaxError{})
}
func TestBindbindData(t *testing.T) {
@ -246,7 +255,7 @@ func TestBindUnmarshalTypeError(t *testing.T) {
err := c.Bind(u)
he := &HTTPError{Code: http.StatusBadRequest, Message: "Unmarshal type error: expected=int, got=string, field=id, offset=14"}
he := &HTTPError{Code: http.StatusBadRequest, Message: "Unmarshal type error: expected=int, got=string, field=id, offset=14", Internal: err.(*HTTPError).Internal}
assert.Equal(t, he, err)
}
@ -353,7 +362,7 @@ func testBindOkay(t *testing.T, r io.Reader, ctype string) {
}
}
func testBindError(t *testing.T, r io.Reader, ctype string) {
func testBindError(t *testing.T, r io.Reader, ctype string, expectedInternal error) {
e := New()
req := httptest.NewRequest(POST, "/", r)
rec := httptest.NewRecorder()
@ -367,10 +376,12 @@ func testBindError(t *testing.T, r io.Reader, ctype string) {
strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
if assert.IsType(t, new(HTTPError), err) {
assert.Equal(t, http.StatusBadRequest, err.(*HTTPError).Code)
assert.IsType(t, expectedInternal, err.(*HTTPError).Internal)
}
default:
if assert.IsType(t, new(HTTPError), err) {
assert.Equal(t, ErrUnsupportedMediaType, err)
assert.IsType(t, expectedInternal, err.(*HTTPError).Internal)
}
}
}

View File

@ -702,6 +702,11 @@ func (he *HTTPError) Error() string {
return fmt.Sprintf("code=%d, message=%v", he.Code, he.Message)
}
func (he *HTTPError) SetInternal(err error) *HTTPError {
he.Internal = err
return he
}
// WrapHandler wraps `http.Handler` into `echo.HandlerFunc`.
func WrapHandler(h http.Handler) HandlerFunc {
return func(c Context) error {

View File

@ -22,10 +22,13 @@ type (
)
const (
userJSON = `{"id":1,"name":"Jon Snow"}`
userXML = `<user><id>1</id><name>Jon Snow</name></user>`
userForm = `id=1&name=Jon Snow`
invalidContent = "invalid content"
userJSON = `{"id":1,"name":"Jon Snow"}`
userXML = `<user><id>1</id><name>Jon Snow</name></user>`
userForm = `id=1&name=Jon Snow`
invalidContent = "invalid content"
userJSONInvalidType = `{"id":"1","name":"Jon Snow"}`
userXMLConvertNumberError = `<user><id>Number one</id><name>Jon Snow</name></user>`
userXMLUnsupportedTypeError = `<user><>Number one</><name>Jon Snow</name></user>`
)
const userJSONPretty = `{