mirror of
https://github.com/labstack/echo.git
synced 2025-01-24 03:16:14 +02:00
feat: Bind data using headers as source (#1866)
Currently, echo supports binding data from query, path or body. Sometimes we need to read bind data from headers. It would be nice to automatically bind those using the `bindData` func, which is already well prepared to accept `http.Header`. I didn't add this to the `Bind` func, so this will not happen automatically. Main reason is backwards compatability. It might be confusing if variables are bound from headers when upgrading, and might even have become a security issue as pointed out in #1670. * Add docs for BindHeaders * Add test for BindHeader with invalid data type
This commit is contained in:
parent
2acb24adb0
commit
7846e3fa6b
10
bind.go
10
bind.go
@ -97,6 +97,14 @@ func (b *DefaultBinder) BindBody(c Context, i interface{}) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// BindHeaders binds HTTP headers to a bindable object
|
||||
func (b *DefaultBinder) BindHeaders(c Context, i interface{}) error {
|
||||
if err := b.bindData(i, c.Request().Header, "header"); err != nil {
|
||||
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bind implements the `Binder#Bind` function.
|
||||
// Binding is done in following order: 1) path params; 2) query params; 3) request body. Each step COULD override previous
|
||||
// step binded values. For single source binding use their own methods BindBody, BindQueryParams, BindPathParams.
|
||||
@ -134,7 +142,7 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
|
||||
|
||||
// !struct
|
||||
if typ.Kind() != reflect.Struct {
|
||||
if tag == "param" || tag == "query" {
|
||||
if tag == "param" || tag == "query" || tag == "header" {
|
||||
// incompatible type, data is probably to be found in the body
|
||||
return nil
|
||||
}
|
||||
|
31
bind_test.go
31
bind_test.go
@ -269,6 +269,37 @@ func TestBindQueryParamsCaseSensitivePrioritized(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBindHeaderParam(t *testing.T) {
|
||||
e := New()
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
req.Header.Set("Name", "Jon Doe")
|
||||
req.Header.Set("Id", "2")
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
u := new(user)
|
||||
err := (&DefaultBinder{}).BindHeaders(c, u)
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, 2, u.ID)
|
||||
assert.Equal(t, "Jon Doe", u.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBindHeaderParamBadType(t *testing.T) {
|
||||
e := New()
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
req.Header.Set("Id", "salamander")
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
u := new(user)
|
||||
err := (&DefaultBinder{}).BindHeaders(c, u)
|
||||
assert.Error(t, err)
|
||||
|
||||
httpErr, ok := err.(*HTTPError)
|
||||
if assert.True(t, ok) {
|
||||
assert.Equal(t, http.StatusBadRequest, httpErr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBindUnmarshalParam(t *testing.T) {
|
||||
e := New()
|
||||
req := httptest.NewRequest(http.MethodGet, "/?ts=2016-12-06T19:09:05Z&sa=one,two,three&ta=2016-12-06T19:09:05Z&ta=2016-12-06T19:09:05Z&ST=baz", nil)
|
||||
|
@ -24,8 +24,8 @@ import (
|
||||
|
||||
type (
|
||||
user struct {
|
||||
ID int `json:"id" xml:"id" form:"id" query:"id" param:"id"`
|
||||
Name string `json:"name" xml:"name" form:"name" query:"name" param:"name"`
|
||||
ID int `json:"id" xml:"id" form:"id" query:"id" param:"id" header:"id"`
|
||||
Name string `json:"name" xml:"name" form:"name" query:"name" param:"name" header:"name"`
|
||||
}
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user