Skip to content
Open
9 changes: 9 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,15 @@ func (c *Context) Render(code int, r render.Render) {
return
}

if c.Writer.Written() && IsDebugging() {
// Skip warning for SSE and streaming responses (status code -1)
Comment thread
raju-mechatronics marked this conversation as resolved.
Resolved
if code != -1 {
if _, ok := r.(sse.Event); !ok {
debugPrint("[WARNING] Response body already written. Attempting to write again with status code %d", code)
}
Comment thread
raju-mechatronics marked this conversation as resolved.
Resolved
}
}

if err := r.Render(c.Writer); err != nil {
// Pushing error to c.Errors
_ = c.Error(err)
Expand Down
37 changes: 37 additions & 0 deletions context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1396,6 +1396,43 @@ func TestContextRenderNoContentData(t *testing.T) {
assert.Equal(t, "text/csv", w.Header().Get("Content-Type"))
}

// Test multiple JSON writes in debug mode
func TestContextRenderMultipleJSON(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)

oldMode := os.Getenv("GIN_MODE")
defer os.Setenv("GIN_MODE", oldMode)
SetMode(DebugMode)
Comment thread
raju-mechatronics marked this conversation as resolved.
Resolved

Comment thread
raju-mechatronics marked this conversation as resolved.
Resolved
output := captureOutput(t, func() {
c.JSON(http.StatusOK, H{"foo": "bar"})
c.JSON(http.StatusOK, H{"baz": "qux"})
})

assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, output, "[WARNING] Response body already written")
assert.Contains(t, output, "status code 200")
}

// Test multiple SSE writes in debug mode
func TestContextRenderMultipleSSE(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)

oldMode := os.Getenv("GIN_MODE")
defer os.Setenv("GIN_MODE", oldMode)
SetMode(DebugMode)
Comment thread
raju-mechatronics marked this conversation as resolved.
Resolved

Comment thread
raju-mechatronics marked this conversation as resolved.
Resolved
output := captureOutput(t, func() {
c.SSEvent("message", "test1")
c.SSEvent("message", "test2")
})

assert.Equal(t, http.StatusOK, w.Code)
assert.NotContains(t, output, "[WARNING] Response body already written")
}

func TestContextRenderSSE(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)
Expand Down