diff --git a/bind.go b/bind.go index bec2e3b3a..c9bc7f106 100644 --- a/bind.go +++ b/bind.go @@ -80,7 +80,7 @@ func BindBody(c *Context, target any) (err error) { // mediatype is found like `mime.ParseMediaType()` does it base, _, _ := strings.Cut(req.Header.Get(HeaderContentType), ";") - mediatype := strings.TrimSpace(base) + mediatype := strings.ToLower(strings.TrimSpace(base)) switch mediatype { case MIMEApplicationJSON: diff --git a/bind_test.go b/bind_test.go index 771c59fb8..4501e5599 100644 --- a/bind_test.go +++ b/bind_test.go @@ -1151,6 +1151,66 @@ func TestDefaultBinder_BindBody(t *testing.T) { } } +func TestDefaultBinder_BindBody_MediaTypeIsCaseInsensitive(t *testing.T) { + // media type and subtype are case-insensitive, see https://www.rfc-editor.org/rfc/rfc9110.html#section-8.3.1 + type Node struct { + ID int `json:"id" xml:"id" form:"id"` + } + + var testCases = []struct { + name string + givenContentType string + givenContent string + }{ + { + name: "JSON", + givenContentType: "Application/JSON", + givenContent: `{"id": 1}`, + }, + { + name: "JSON with charset", + givenContentType: "APPLICATION/JSON; charset=UTF-8", + givenContent: `{"id": 1}`, + }, + { + name: "application XML", + givenContentType: "Application/XML", + givenContent: `1`, + }, + { + name: "text XML", + givenContentType: "Text/XML; charset=utf-8", + givenContent: `1`, + }, + { + name: "form", + givenContentType: "Application/X-WWW-Form-Urlencoded", + givenContent: `id=1`, + }, + { + name: "multipart form", + givenContentType: "Multipart/Form-Data; boundary=xxx", + givenContent: "--xxx\r\nContent-Disposition: form-data; name=\"id\"\r\n\r\n1\r\n--xxx--\r\n", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + e := New() + req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(tc.givenContent)) + req.Header.Set(HeaderContentType, tc.givenContentType) + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + + target := &Node{} + err := BindBody(c, target) + + assert.NoError(t, err) + assert.Equal(t, &Node{ID: 1}, target) + }) + } +} + func testBindURL(queryString string, target any) error { e := New() req := httptest.NewRequest(http.MethodGet, queryString, nil)