lib/httpserver: make sure the gzipResponseWriter.Write() is called on Flush() and Close() calls

This should fix the `http: superfluous response.WriteHeader call` issue

See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1078
This commit is contained in:
Aliaksandr Valialkin 2021-02-28 19:21:30 +02:00
parent 9a2bf65134
commit 9e644ef111
2 changed files with 19 additions and 9 deletions

View file

@ -26,6 +26,7 @@
* BUGFIX: vmselect: do not cache partial query results on timeout when receiving data from `vmstorage` nodes. See https://github.com/VictoriaMetrics/VictoriaMetrics/pull/1085 * BUGFIX: vmselect: do not cache partial query results on timeout when receiving data from `vmstorage` nodes. See https://github.com/VictoriaMetrics/VictoriaMetrics/pull/1085
* BUGFIX: properly handle `stale NFS file handle` error. * BUGFIX: properly handle `stale NFS file handle` error.
* BUGFIX: properly cache query results when `extra_label` query arg is used. Previously the cached results could clash for different `extra_label` values. See https://github.com/VictoriaMetrics/VictoriaMetrics/pull/1095 * BUGFIX: properly cache query results when `extra_label` query arg is used. Previously the cached results could clash for different `extra_label` values. See https://github.com/VictoriaMetrics/VictoriaMetrics/pull/1095
* BUGFIX: fix `http: superfluous response.WriteHeader call` issue. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1078
# [v1.54.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.54.1) # [v1.54.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.54.1)

View file

@ -298,9 +298,9 @@ func maybeGzipResponseWriter(w http.ResponseWriter, r *http.Request) http.Respon
zw := getGzipWriter(w) zw := getGzipWriter(w)
bw := getBufioWriter(zw) bw := getBufioWriter(zw)
zrw := &gzipResponseWriter{ zrw := &gzipResponseWriter{
ResponseWriter: w, rw: w,
zw: zw, zw: zw,
bw: bw, bw: bw,
} }
return zrw return zrw
} }
@ -346,7 +346,7 @@ func putGzipWriter(zw *gzip.Writer) {
var gzipWriterPool sync.Pool var gzipWriterPool sync.Pool
type gzipResponseWriter struct { type gzipResponseWriter struct {
http.ResponseWriter rw http.ResponseWriter
zw *gzip.Writer zw *gzip.Writer
bw *bufio.Writer bw *bufio.Writer
statusCode int statusCode int
@ -355,6 +355,12 @@ type gzipResponseWriter struct {
disableCompression bool disableCompression bool
} }
// Implements http.ResponseWriter.Header method.
func (zrw *gzipResponseWriter) Header() http.Header {
return zrw.rw.Header()
}
// Implements http.ResponseWriter.Write method.
func (zrw *gzipResponseWriter) Write(p []byte) (int, error) { func (zrw *gzipResponseWriter) Write(p []byte) (int, error) {
if !zrw.firstWriteDone { if !zrw.firstWriteDone {
h := zrw.Header() h := zrw.Header()
@ -377,11 +383,12 @@ func (zrw *gzipResponseWriter) Write(p []byte) (int, error) {
zrw.firstWriteDone = true zrw.firstWriteDone = true
} }
if zrw.disableCompression { if zrw.disableCompression {
return zrw.ResponseWriter.Write(p) return zrw.rw.Write(p)
} }
return zrw.bw.Write(p) return zrw.bw.Write(p)
} }
// Implements http.ResponseWriter.WriteHeader method.
func (zrw *gzipResponseWriter) WriteHeader(statusCode int) { func (zrw *gzipResponseWriter) WriteHeader(statusCode int) {
zrw.statusCode = statusCode zrw.statusCode = statusCode
} }
@ -390,11 +397,14 @@ func (zrw *gzipResponseWriter) writeHeader() {
if zrw.statusCode == 0 { if zrw.statusCode == 0 {
zrw.statusCode = http.StatusOK zrw.statusCode = http.StatusOK
} }
zrw.ResponseWriter.WriteHeader(zrw.statusCode) zrw.rw.WriteHeader(zrw.statusCode)
} }
// Implements http.Flusher // Implements http.Flusher
func (zrw *gzipResponseWriter) Flush() { func (zrw *gzipResponseWriter) Flush() {
if !zrw.firstWriteDone {
zrw.Write(nil)
}
if !zrw.disableCompression { if !zrw.disableCompression {
if err := zrw.bw.Flush(); err != nil && !isTrivialNetworkError(err) { if err := zrw.bw.Flush(); err != nil && !isTrivialNetworkError(err) {
logger.Warnf("gzipResponseWriter.Flush (buffer): %s", err) logger.Warnf("gzipResponseWriter.Flush (buffer): %s", err)
@ -403,15 +413,14 @@ func (zrw *gzipResponseWriter) Flush() {
logger.Warnf("gzipResponseWriter.Flush (gzip): %s", err) logger.Warnf("gzipResponseWriter.Flush (gzip): %s", err)
} }
} }
if fw, ok := zrw.ResponseWriter.(http.Flusher); ok { if fw, ok := zrw.rw.(http.Flusher); ok {
fw.Flush() fw.Flush()
} }
} }
func (zrw *gzipResponseWriter) Close() error { func (zrw *gzipResponseWriter) Close() error {
if !zrw.firstWriteDone { if !zrw.firstWriteDone {
zrw.writeHeader() zrw.Write(nil)
return nil
} }
zrw.Flush() zrw.Flush()
var err error var err error