From d8d025ef010bd3fdfd9ecb7880a3d1fca1f91aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=90=8D=E9=94=90?= <1565842059@qq.com> Date: Fri, 28 Aug 2026 19:51:17 +0800 Subject: [PATCH 1/3] fix(context): prevent nil pointer dereference in initFormCache when Request is nil (fix #4772) --- context.go | 15 ++++++++++----- context_test.go | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/context.go b/context.go index 1dc730e3..aaba738d 100644 --- a/context.go +++ b/context.go @@ -648,13 +648,18 @@ func (c *Context) PostFormArray(key string) (values []string) { func (c *Context) initFormCache() { if c.formCache == nil { c.formCache = make(url.Values) - req := c.Request - if err := req.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil { - if !errors.Is(err, http.ErrNotMultipart) { - debugPrint("error on parse multipart form array: %v", err) + if c.Request != nil { + var maxMemory int64 = defaultMultipartMemory + if c.engine != nil { + maxMemory = c.engine.MaxMultipartMemory } + if err := c.Request.ParseMultipartForm(maxMemory); err != nil { + if !errors.Is(err, http.ErrNotMultipart) { + debugPrint("error on parse multipart form array: %v", err) + } + } + c.formCache = c.Request.PostForm } - c.formCache = req.PostForm } } diff --git a/context_test.go b/context_test.go index e8d305e4..a8ed18b5 100644 --- a/context_test.go +++ b/context_test.go @@ -3955,3 +3955,24 @@ func BenchmarkGetMapFromFormData(b *testing.B) { }) } } + +func TestContextPostFormWithoutRequest(t *testing.T) { + c, _ := CreateTestContext(httptest.NewRecorder()) + c.Request = nil + + val, ok := c.GetPostForm("key") + assert.False(t, ok) + assert.Empty(t, val) + + val = c.PostForm("key") + assert.Empty(t, val) + + val = c.DefaultPostForm("key", "default_val") + assert.Equal(t, "default_val", val) + + vals := c.PostFormArray("key") + assert.Empty(t, vals) + + mapVals := c.PostFormMap("key") + assert.Empty(t, mapVals) +} From b5c998145a4ab099a00b2c6f5cfb6e0bd82f7c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=90=8D=E9=94=90?= <1565842059@qq.com> Date: Fri, 28 Aug 2026 20:13:05 +0800 Subject: [PATCH 2/3] test(context): add comprehensive branch coverage for initFormCache --- context_test.go | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/context_test.go b/context_test.go index a8ed18b5..fe92949b 100644 --- a/context_test.go +++ b/context_test.go @@ -3957,22 +3957,41 @@ func BenchmarkGetMapFromFormData(b *testing.B) { } func TestContextPostFormWithoutRequest(t *testing.T) { - c, _ := CreateTestContext(httptest.NewRecorder()) - c.Request = nil - - val, ok := c.GetPostForm("key") + // Case 1: c.Request is nil, c.engine is nil + c1 := &Context{} + val, ok := c1.GetPostForm("key") assert.False(t, ok) assert.Empty(t, val) + assert.Empty(t, c1.PostForm("key")) + assert.Equal(t, "default_val", c1.DefaultPostForm("key", "default_val")) + assert.Empty(t, c1.PostFormArray("key")) + assert.Empty(t, c1.PostFormMap("key")) - val = c.PostForm("key") + // Case 2: c.Request is nil, c.engine is not nil + c2, _ := CreateTestContext(httptest.NewRecorder()) + c2.Request = nil + val, ok = c2.GetPostForm("key") + assert.False(t, ok) assert.Empty(t, val) + assert.Empty(t, c2.PostForm("key")) + assert.Equal(t, "default_val", c2.DefaultPostForm("key", "default_val")) + assert.Empty(t, c2.PostFormArray("key")) + assert.Empty(t, c2.PostFormMap("key")) - val = c.DefaultPostForm("key", "default_val") - assert.Equal(t, "default_val", val) + // Case 3: c.Request is not nil, c.engine is nil + c3 := &Context{} + req3, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader("key=value3")) + req3.Header.Set("Content-Type", "application/x-www-form-urlencoded") + c3.Request = req3 + val, ok = c3.GetPostForm("key") + assert.True(t, ok) + assert.Equal(t, "value3", val) - vals := c.PostFormArray("key") - assert.Empty(t, vals) - - mapVals := c.PostFormMap("key") - assert.Empty(t, mapVals) + // Case 4: c.Request has multipart error, c.engine is nil + c4 := &Context{} + req4, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader("bad multipart payload")) + req4.Header.Set("Content-Type", "multipart/form-data; boundary=boundary") + c4.Request = req4 + val, ok = c4.GetPostForm("key") + assert.False(t, ok) } From a010fc44ae00a76cecc9800a994f9ca552bb4873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=90=8D=E9=94=90?= <1565842059@qq.com> Date: Fri, 28 Aug 2026 20:16:12 +0800 Subject: [PATCH 3/3] test(context): fix ineffectual assignment in TestContextPostFormWithoutRequest --- context_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context_test.go b/context_test.go index fe92949b..654cfeaf 100644 --- a/context_test.go +++ b/context_test.go @@ -3992,6 +3992,6 @@ func TestContextPostFormWithoutRequest(t *testing.T) { req4, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader("bad multipart payload")) req4.Header.Set("Content-Type", "multipart/form-data; boundary=boundary") c4.Request = req4 - val, ok = c4.GetPostForm("key") + _, ok = c4.GetPostForm("key") assert.False(t, ok) }