diff --git a/bind.go b/bind.go index bec2e3b3a..d16e8160d 100644 --- a/bind.go +++ b/bind.go @@ -241,6 +241,9 @@ func bindData(destination any, data map[string][]string, tag string, dataFiles m val.Set(reflect.MakeMap(typ)) } for k, v := range data { + if len(v) == 0 { + continue + } if isElemString { val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0])) } else if isElemInterface { @@ -323,6 +326,10 @@ func bindData(destination any, data map[string][]string, tag string, dataFiles m continue } + if len(inputValue) == 0 { + continue + } + // NOTE: algorithm here is not particularly sophisticated. It probably does not work with absurd types like `**[]*int` // but it is smart enough to handle niche cases like `*int`,`*[]string`,`[]*int` . diff --git a/bind_test.go b/bind_test.go index 771c59fb8..904169672 100644 --- a/bind_test.go +++ b/bind_test.go @@ -306,6 +306,54 @@ func TestBindHeaderParamBadType(t *testing.T) { } } +func TestBindHeadersEmptyValues(t *testing.T) { + for _, values := range [][]string{nil, {}} { + e := New() + req := httptest.NewRequest(http.MethodGet, "/", nil) + req.Header["X-Empty"] = values + c := e.NewContext(req, httptest.NewRecorder()) + + var dst struct { + Value string `header:"X-Empty"` + } + assert.NotPanics(t, func() { + assert.NoError(t, BindHeaders(c, &dst)) + }) + assert.Equal(t, "", dst.Value) + + var sliceDst struct { + Values []string `header:"X-Empty"` + } + assert.NotPanics(t, func() { + assert.NoError(t, BindHeaders(c, &sliceDst)) + }) + assert.Empty(t, sliceDst.Values) + + var stringMap map[string]string + assert.NotPanics(t, func() { + assert.NoError(t, BindHeaders(c, &stringMap)) + }) + assert.NotContains(t, stringMap, "X-Empty") + + var anyMap map[string]any + assert.NotPanics(t, func() { + assert.NoError(t, BindHeaders(c, &anyMap)) + }) + assert.NotContains(t, anyMap, "X-Empty") + } + + // controls: normal value and single empty string still bind + e := New() + req := httptest.NewRequest(http.MethodGet, "/", nil) + req.Header.Set("X-Empty", "value") + c := e.NewContext(req, httptest.NewRecorder()) + var dst struct { + Value string `header:"X-Empty"` + } + assert.NoError(t, BindHeaders(c, &dst)) + assert.Equal(t, "value", dst.Value) +} + 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)