1
0
mirror of https://github.com/golang/go synced 2024-11-21 21:54:40 -07:00

net/http: don't send an automatic Content-Length on a 304 Not Modified

Also start of some test helper unification, long overdue.
I refrained from cleaning up the rest in this CL.

Fixes #6157

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/13030043
This commit is contained in:
Brad Fitzpatrick 2013-08-15 17:40:05 -07:00
parent 9c248e3406
commit 67a69bce6b
2 changed files with 63 additions and 13 deletions

View File

@ -122,6 +122,28 @@ func reqBytes(req string) []byte {
return []byte(strings.Replace(strings.TrimSpace(req), "\n", "\r\n", -1) + "\r\n\r\n")
}
type handlerTest struct {
handler Handler
}
func newHandlerTest(h Handler) handlerTest {
return handlerTest{h}
}
func (ht handlerTest) rawResponse(req string) string {
reqb := reqBytes(req)
var output bytes.Buffer
conn := &rwTestConn{
Reader: bytes.NewReader(reqb),
Writer: &output,
closec: make(chan bool, 1),
}
ln := &oneConnListener{conn: conn}
go Serve(ln, ht.handler)
<-conn.closec
return output.String()
}
func TestConsumingBodyOnNextConn(t *testing.T) {
conn := new(testConn)
for i := 0; i < 2; i++ {
@ -1588,7 +1610,6 @@ func TestOptions(t *testing.T) {
// ones, even if the handler modifies them (~erroneously) after the
// first Write.
func TestHeaderToWire(t *testing.T) {
req := reqBytes("GET / HTTP/1.1\nHost: golang.org")
tests := []struct {
name string
handler func(ResponseWriter, *Request)
@ -1751,17 +1772,10 @@ func TestHeaderToWire(t *testing.T) {
},
}
for _, tc := range tests {
var output bytes.Buffer
conn := &rwTestConn{
Reader: bytes.NewReader(req),
Writer: &output,
closec: make(chan bool, 1),
}
ln := &oneConnListener{conn: conn}
go Serve(ln, HandlerFunc(tc.handler))
<-conn.closec
if err := tc.check(output.String()); err != nil {
t.Errorf("%s: %v\nGot response:\n%s", tc.name, err, output.Bytes())
ht := newHandlerTest(HandlerFunc(tc.handler))
got := ht.rawResponse("GET / HTTP/1.1\nHost: golang.org")
if err := tc.check(got); err != nil {
t.Errorf("%s: %v\nGot response:\n%s", tc.name, err, got)
}
}
}
@ -1952,6 +1966,34 @@ func TestServerReaderFromOrder(t *testing.T) {
}
}
// Issue 6157
func TestNoContentTypeOnNotModified(t *testing.T) {
ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.URL.Path == "/header" {
w.Header().Set("Content-Length", "123")
}
w.WriteHeader(StatusNotModified)
if r.URL.Path == "/more" {
w.Write([]byte("stuff"))
}
}))
for _, req := range []string{
"GET / HTTP/1.0",
"GET /header HTTP/1.0",
"GET /more HTTP/1.0",
"GET / HTTP/1.1",
"GET /header HTTP/1.1",
"GET /more HTTP/1.1",
} {
got := ht.rawResponse(req)
if !strings.Contains(got, "304 Not Modified") {
t.Errorf("Non-304 Not Modified for %q: %s", req, got)
} else if strings.Contains(got, "Content-Length") {
t.Errorf("Got a Content-Length from %q: %s", req, got)
}
}
}
func BenchmarkClientServer(b *testing.B) {
b.ReportAllocs()
b.StopTimer()

View File

@ -737,7 +737,15 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// response header and this is our first (and last) write, set
// it, even to zero. This helps HTTP/1.0 clients keep their
// "keep-alive" connections alive.
if w.handlerDone && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
// Exceptions: 304 responses never get Content-Length, and if
// it was a HEAD request, we don't know the difference between
// 0 actual bytes and 0 bytes because the handler noticed it
// was a HEAD request and chose not to write anything. So for
// HEAD, the handler should either write the Content-Length or
// write non-zero bytes. If it's actually 0 bytes and the
// handler never looked at the Request.Method, we just don't
// send a Content-Length header.
if w.handlerDone && w.status != StatusNotModified && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
w.contentLength = int64(len(p))
setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10)
}