http2: Discard data reads on HEAD requests

If a server returns a DATA frame while procesing a HEAD request, the
client will discard the data.

Fixes golang/go#22376

Change-Id: Ief9c17ddfe51cc17f7f6326c87330ac9d8b9d3ff
Reviewed-on: https://go-review.googlesource.com/72551
Run-TryBot: Tom Bergan <tombergan@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tom Bergan <tombergan@google.com>
Reviewed-on: https://go-review.googlesource.com/88655
Run-TryBot: Andrew Bonventre <andybons@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Michael Fraenkel 2017-10-22 13:59:00 -04:00 коммит произвёл Andrew Bonventre
Родитель ab5485076f
Коммит 44b7c21cbf
2 изменённых файлов: 62 добавлений и 0 удалений

Просмотреть файл

@ -1703,6 +1703,14 @@ func (rl *clientConnReadLoop) processData(f *DataFrame) error {
return nil
}
if f.Length > 0 {
if cs.req.Method == "HEAD" && len(data) > 0 {
cc.logf("protocol error: received DATA on a HEAD request")
rl.endStreamError(cs, StreamError{
StreamID: f.StreamID,
Code: ErrCodeProtocol,
})
return nil
}
// Check connection-level flow control.
cc.mu.Lock()
if cs.inflow.available() >= int32(f.Length) {

Просмотреть файл

@ -2026,6 +2026,60 @@ func TestTransportReadHeadResponse(t *testing.T) {
ct.run()
}
func TestTransportReadHeadResponseWithBody(t *testing.T) {
response := "redirecting to /elsewhere"
ct := newClientTester(t)
clientDone := make(chan struct{})
ct.client = func() error {
defer close(clientDone)
req, _ := http.NewRequest("HEAD", "https://dummy.tld/", nil)
res, err := ct.tr.RoundTrip(req)
if err != nil {
return err
}
if res.ContentLength != int64(len(response)) {
return fmt.Errorf("Content-Length = %d; want %d", res.ContentLength, len(response))
}
slurp, err := ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("ReadAll: %v", err)
}
if len(slurp) > 0 {
return fmt.Errorf("Unexpected non-empty ReadAll body: %q", slurp)
}
return nil
}
ct.server = func() error {
ct.greet()
for {
f, err := ct.fr.ReadFrame()
if err != nil {
t.Logf("ReadFrame: %v", err)
return nil
}
hf, ok := f.(*HeadersFrame)
if !ok {
continue
}
var buf bytes.Buffer
enc := hpack.NewEncoder(&buf)
enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
enc.WriteField(hpack.HeaderField{Name: "content-length", Value: strconv.Itoa(len(response))})
ct.fr.WriteHeaders(HeadersFrameParam{
StreamID: hf.StreamID,
EndHeaders: true,
EndStream: false,
BlockFragment: buf.Bytes(),
})
ct.fr.WriteData(hf.StreamID, true, []byte(response))
<-clientDone
return nil
}
}
ct.run()
}
type neverEnding byte
func (b neverEnding) Read(p []byte) (int, error) {