mirror of
https://github.com/golang/go
synced 2024-11-21 23:04:39 -07:00
http: fix regression permitting io.Copy on HEAD response
With the ReadFrom change in the sendfile CL, it became possible to illegally send a response to a HEAD request if you did it via io.Copy. Fixes #1939 R=rsc CC=golang-dev https://golang.org/cl/4584049
This commit is contained in:
parent
aac6afbb11
commit
5e8b9c614b
@ -12,6 +12,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
. "http"
|
. "http"
|
||||||
"http/httptest"
|
"http/httptest"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@ -495,6 +496,12 @@ func TestHeadResponses(t *testing.T) {
|
|||||||
if err != ErrBodyNotAllowed {
|
if err != ErrBodyNotAllowed {
|
||||||
t.Errorf("on Write, expected ErrBodyNotAllowed, got %v", err)
|
t.Errorf("on Write, expected ErrBodyNotAllowed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also exercise the ReaderFrom path
|
||||||
|
_, err = io.Copy(w, strings.NewReader("Ignored body"))
|
||||||
|
if err != ErrBodyNotAllowed {
|
||||||
|
t.Errorf("on Copy, expected ErrBodyNotAllowed, got %v", err)
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
res, err := Head(ts.URL)
|
res, err := Head(ts.URL)
|
||||||
|
@ -129,7 +129,7 @@ func (r *response) ReadFrom(src io.Reader) (n int64, err os.Error) {
|
|||||||
// WriteHeader if it hasn't been called yet, and WriteHeader
|
// WriteHeader if it hasn't been called yet, and WriteHeader
|
||||||
// is what sets r.chunking.
|
// is what sets r.chunking.
|
||||||
r.Flush()
|
r.Flush()
|
||||||
if !r.chunking {
|
if !r.chunking && r.bodyAllowed() {
|
||||||
if rf, ok := r.conn.rwc.(io.ReaderFrom); ok {
|
if rf, ok := r.conn.rwc.(io.ReaderFrom); ok {
|
||||||
n, err = rf.ReadFrom(src)
|
n, err = rf.ReadFrom(src)
|
||||||
r.written += n
|
r.written += n
|
||||||
@ -335,6 +335,15 @@ func (w *response) WriteHeader(code int) {
|
|||||||
io.WriteString(w.conn.buf, "\r\n")
|
io.WriteString(w.conn.buf, "\r\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bodyAllowed returns true if a Write is allowed for this response type.
|
||||||
|
// It's illegal to call this before the header has been flushed.
|
||||||
|
func (w *response) bodyAllowed() bool {
|
||||||
|
if !w.wroteHeader {
|
||||||
|
panic("")
|
||||||
|
}
|
||||||
|
return w.status != StatusNotModified && w.req.Method != "HEAD"
|
||||||
|
}
|
||||||
|
|
||||||
func (w *response) Write(data []byte) (n int, err os.Error) {
|
func (w *response) Write(data []byte) (n int, err os.Error) {
|
||||||
if w.conn.hijacked {
|
if w.conn.hijacked {
|
||||||
log.Print("http: response.Write on hijacked connection")
|
log.Print("http: response.Write on hijacked connection")
|
||||||
@ -346,9 +355,7 @@ func (w *response) Write(data []byte) (n int, err os.Error) {
|
|||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
if !w.bodyAllowed() {
|
||||||
if w.status == StatusNotModified || w.req.Method == "HEAD" {
|
|
||||||
// Must not have body.
|
|
||||||
return 0, ErrBodyNotAllowed
|
return 0, ErrBodyNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user