mirror of
https://github.com/golang/go
synced 2024-11-18 19:34:41 -07:00
net/http: don't send implicit Content-Length if Transfer-Encoding is set
Fixes #9987 Change-Id: Ibebd105a2bcdc1741f3b41aa78cb986f3f518b53 Reviewed-on: https://go-review.googlesource.com/9638 Reviewed-by: Andrew Gerrand <adg@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
62fb472b71
commit
c661cb01f7
@ -2767,6 +2767,43 @@ func TestServerKeepAliveAfterWriteError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue 9987: shouldn't add automatic Content-Length (or
|
||||||
|
// Content-Type) if a Transfer-Encoding was set by the handler.
|
||||||
|
func TestNoContentLengthIfTransferEncoding(t *testing.T) {
|
||||||
|
defer afterTest(t)
|
||||||
|
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||||
|
w.Header().Set("Transfer-Encoding", "foo")
|
||||||
|
io.WriteString(w, "<html>")
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
c, err := net.Dial("tcp", ts.Listener.Addr().String())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Dial: %v", err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
if _, err := io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
bs := bufio.NewScanner(c)
|
||||||
|
var got bytes.Buffer
|
||||||
|
for bs.Scan() {
|
||||||
|
if strings.TrimSpace(bs.Text()) == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
got.WriteString(bs.Text())
|
||||||
|
got.WriteByte('\n')
|
||||||
|
}
|
||||||
|
if err := bs.Err(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if strings.Contains(got.String(), "Content-Length") {
|
||||||
|
t.Errorf("Unexpected Content-Length in response headers: %s", got.String())
|
||||||
|
}
|
||||||
|
if strings.Contains(got.String(), "Content-Type") {
|
||||||
|
t.Errorf("Unexpected Content-Type in response headers: %s", got.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkClientServer(b *testing.B) {
|
func BenchmarkClientServer(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
|
@ -781,6 +781,9 @@ func (cw *chunkWriter) writeHeader(p []byte) {
|
|||||||
foreachHeaderElement(v, cw.res.declareTrailer)
|
foreachHeaderElement(v, cw.res.declareTrailer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
te := header.get("Transfer-Encoding")
|
||||||
|
hasTE := te != ""
|
||||||
|
|
||||||
// If the handler is done but never sent a Content-Length
|
// If the handler is done but never sent a Content-Length
|
||||||
// response header and this is our first (and last) write, set
|
// response header and this is our first (and last) write, set
|
||||||
// it, even to zero. This helps HTTP/1.0 clients keep their
|
// it, even to zero. This helps HTTP/1.0 clients keep their
|
||||||
@ -793,7 +796,9 @@ func (cw *chunkWriter) writeHeader(p []byte) {
|
|||||||
// write non-zero bytes. If it's actually 0 bytes and the
|
// write non-zero bytes. If it's actually 0 bytes and the
|
||||||
// handler never looked at the Request.Method, we just don't
|
// handler never looked at the Request.Method, we just don't
|
||||||
// send a Content-Length header.
|
// send a Content-Length header.
|
||||||
if w.handlerDone && !trailers && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
|
// Further, we don't send an automatic Content-Length if they
|
||||||
|
// set a Transfer-Encoding, because they're generally incompatible.
|
||||||
|
if w.handlerDone && !trailers && !hasTE && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
|
||||||
w.contentLength = int64(len(p))
|
w.contentLength = int64(len(p))
|
||||||
setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10)
|
setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10)
|
||||||
}
|
}
|
||||||
@ -845,7 +850,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
|
|||||||
if bodyAllowedForStatus(code) {
|
if bodyAllowedForStatus(code) {
|
||||||
// If no content type, apply sniffing algorithm to body.
|
// If no content type, apply sniffing algorithm to body.
|
||||||
_, haveType := header["Content-Type"]
|
_, haveType := header["Content-Type"]
|
||||||
if !haveType {
|
if !haveType && !hasTE {
|
||||||
setHeader.contentType = DetectContentType(p)
|
setHeader.contentType = DetectContentType(p)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -858,8 +863,6 @@ func (cw *chunkWriter) writeHeader(p []byte) {
|
|||||||
setHeader.date = appendTime(cw.res.dateBuf[:0], time.Now())
|
setHeader.date = appendTime(cw.res.dateBuf[:0], time.Now())
|
||||||
}
|
}
|
||||||
|
|
||||||
te := header.get("Transfer-Encoding")
|
|
||||||
hasTE := te != ""
|
|
||||||
if hasCL && hasTE && te != "identity" {
|
if hasCL && hasTE && te != "identity" {
|
||||||
// TODO: return an error if WriteHeader gets a return parameter
|
// TODO: return an error if WriteHeader gets a return parameter
|
||||||
// For now just ignore the Content-Length.
|
// For now just ignore the Content-Length.
|
||||||
|
Loading…
Reference in New Issue
Block a user