diff --git a/server/routes/clean_response_middleware.go b/server/routes/clean_response_middleware.go index 5161e71432..29b407fcfa 100644 --- a/server/routes/clean_response_middleware.go +++ b/server/routes/clean_response_middleware.go @@ -46,6 +46,12 @@ func (w customResponseWriter) WriteString(s string) (int, error) { // cleanResponseMiddleware is a Gin middleware to clean up data in the response body. func cleanResponseMiddleware() gin.HandlerFunc { return func(c *gin.Context) { + // Skip buffering for streaming endpoints (e.g. pod logs with follow=true), + // otherwise the response would never be written to the client. + if strings.HasSuffix(c.FullPath(), "/pods/:pod/logs") { + c.Next() + return + } // Replace the original response writer with our custom one w := &customResponseWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer} c.Writer = w diff --git a/server/routes/clean_response_middleware_test.go b/server/routes/clean_response_middleware_test.go index eea6b52e35..8b20719c8a 100644 --- a/server/routes/clean_response_middleware_test.go +++ b/server/routes/clean_response_middleware_test.go @@ -397,6 +397,31 @@ func TestCustomResponseWriter_Write(t *testing.T) { }) } +func TestCleanResponseMiddleware_SkipsPodLogsStreaming(t *testing.T) { + gin.SetMode(gin.TestMode) + + t.Run("pod logs route bypasses response buffering", func(t *testing.T) { + router := gin.New() + router.Use(cleanResponseMiddleware()) + + w := httptest.NewRecorder() + var bytesReceivedDuringHandler int + router.GET("/api/v1/namespaces/:namespace/pods/:pod/logs", func(c *gin.Context) { + _, _ = c.Writer.WriteString("log line 1\n") + c.Writer.Flush() + bytesReceivedDuringHandler = w.Body.Len() + _, _ = c.Writer.WriteString("log line 2\n") + }) + + req, _ := http.NewRequest(http.MethodGet, "/api/v1/namespaces/ns/pods/my-pod/logs?container=numa&follow=true", nil) + router.ServeHTTP(w, req) + + assert.Greater(t, bytesReceivedDuringHandler, 0, "logs should reach the client while the handler is still streaming") + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "log line 1\nlog line 2\n", w.Body.String()) + }) +} + func TestCleanResponseMiddleware_EdgeCases(t *testing.T) { gin.SetMode(gin.TestMode)