From 8349a80562433c9d2f8d50dfa14e981fce24f4b9 Mon Sep 17 00:00:00 2001 From: demouth Date: Sat, 9 Sep 2023 08:01:58 +0900 Subject: [PATCH 1/2] fix `fatal error: concurrent map writes` --- timeout.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/timeout.go b/timeout.go index ec59143..63d9c94 100644 --- a/timeout.go +++ b/timeout.go @@ -85,9 +85,9 @@ func New(opts ...Option) gin.HandlerFunc { tw.FreeBuffer() bufPool.Put(buffer) - c.Writer = w - t.response(c) - c.Writer = tw + cc := c.Copy() + cc.Writer = w + t.response(cc) } } } From 5480e527b1c81a03f1e0bf27f49de4234848b2bd Mon Sep 17 00:00:00 2001 From: demouth Date: Sat, 25 Nov 2023 20:05:55 +0900 Subject: [PATCH 2/2] test(response): add large response test --- timeout_test.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/timeout_test.go b/timeout_test.go index 63aa7bd..43deae9 100644 --- a/timeout_test.go +++ b/timeout_test.go @@ -4,6 +4,7 @@ import ( "context" "net/http" "net/http/httptest" + "sync" "testing" "time" @@ -100,3 +101,33 @@ func TestPanic(t *testing.T) { assert.Equal(t, http.StatusInternalServerError, w.Code) assert.Equal(t, "", w.Body.String()) } + +func TestLargeResponse(t *testing.T) { + r := gin.New() + r.GET("/slow", New( + WithTimeout(1*time.Second), + WithHandler(func(c *gin.Context) { + c.Next() + }), + WithResponse(func(c *gin.Context) { + c.String(http.StatusRequestTimeout, `{"error": "timeout error"}`) + }), + ), func(c *gin.Context) { + time.Sleep(999*time.Millisecond + 500*time.Microsecond) // wait almost same as timeout + c.String(http.StatusRequestTimeout, `{"error": "handler error"}`) + }) + + wg := sync.WaitGroup{} + for i := 0; i < 100; i++ { + wg.Add(1) + go func() { + defer wg.Done() + w := httptest.NewRecorder() + req, _ := http.NewRequestWithContext(context.Background(), "GET", "/slow", nil) + r.ServeHTTP(w, req) + assert.Equal(t, http.StatusRequestTimeout, w.Code) + assert.Equal(t, `{"error": "timeout error"}`, w.Body.String()) + }() + } + wg.Wait() +}