Closed
Description
The net/http server removes all explicitly set Transfer-Encoding
headers (when operating in HTTP/1.1 mode).
This bug was introduced by the fix of #15960 (f9b4556), sorry for any ambiguous wording on my end.
Example:
package main
import (
"compress/gzip"
"net/http"
"strings"
)
const Level int = -1
func myHandler(w http.ResponseWriter, r *http.Request) {
if strings.Contains(r.Header.Get("TE"), "gzip") {
writer, err := gzip.NewWriterLevel(w, Level)
if err != nil {
panic(err)
}
w.Header().Set("Transfer-Encoding", "gzip")
writer.Write([]byte("Some content..."))
} else {
w.Write([]byte("Couldn't gzip (not accepted)"))
}
}
func main() {
http.ListenAndServe(":8080", http.HandlerFunc(myHandler))
}
For clients accepting a gzip
transfer-coding, net/http removes the explicitly set gzip
from the Transfer-Encoding
header and only sends chunked
.
To fix both issues there must be a check for the header field's value (== "chunked"
).
E.g. (the line introduced by #15960 also has to be removed):
...
if hasTE && te == "identity" {
cw.chunking = false
w.closeAfterReply = true
} else if hasTE && te == "chunked" {
cw.chunking = true
setHeader.transferEncoding = "chunked"
delHeader("Transfer-Encoding")
} else {
// HTTP/1.1 or greater: use chunked transfer encoding
...
To reiterate:
- An explicitly set transfer-coding of
chunked
should not result in a duplicateTransfer-Encoding: chunked
header - Whenever another transfer-coding is set,
chunked
must be applied also, but the explicitly set transfer-encoding should be kept in the header
Details can be found in RFC 2616 Section 3.6.