diff --git a/pkg/object/httpserver/mux.go b/pkg/object/httpserver/mux.go index c55e12893a..2babc439a3 100644 --- a/pkg/object/httpserver/mux.go +++ b/pkg/object/httpserver/mux.go @@ -249,7 +249,7 @@ func (mi *muxInstance) sendResponse(ctx *context.Context, stdw http.ResponseWrit stdw.WriteHeader(resp.StatusCode()) var writer io.Writer - if responseNeedFlush(resp) { + if responseIsRealTime(resp) { writer = NewResponseFlushWriter(stdw) } else { writer = stdw @@ -287,15 +287,25 @@ func NewResponseFlushWriter(w http.ResponseWriter) *ResponseFlushWriter { } } -func responseNeedFlush(resp *httpprot.Response) bool { +// responseIsRealTime returns whether the response needs to be flushed immediately. +// The response needs to be flushed immediately if the response has no content length (chunked), +// or the response is a Server-Sent Events response. +func responseIsRealTime(resp *httpprot.Response) bool { + // Based on https://en.wikipedia.org/wiki/Chunked_transfer_encoding + // If the Transfer-Encoding header field is present in a response and its value is "chunked", + // then the body of response is considered as a stream of chunks. + if len(resp.TransferEncoding) > 0 && resp.TransferEncoding[0] == "chunked" && resp.ContentLength <= 0 { + return true + } + resCTHeader := resp.Std().Header.Get("Content-Type") resCT, _, err := mime.ParseMediaType(resCTHeader) - // For Server-Sent Events responses, flush immediately. // The MIME type is defined in https://www.w3.org/TR/eventsource/#text-event-stream if err == nil && resCT == "text/event-stream" { return true } + return false }