mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-05 05:07:36 +03:00
http3: discard body from responses to HEAD requests (#4115)
* http3: HEAD method should not have a body * add tests * Update http3/server.go Co-authored-by: Marten Seemann <martenseemann@gmail.com> * ruduce the size of responseWriter --------- Co-authored-by: Marten Seemann <martenseemann@gmail.com>
This commit is contained in:
parent
a263164d9f
commit
36f7fe7d07
3 changed files with 48 additions and 1 deletions
|
@ -67,9 +67,10 @@ type responseWriter struct {
|
||||||
bufferedStr *bufio.Writer
|
bufferedStr *bufio.Writer
|
||||||
buf []byte
|
buf []byte
|
||||||
|
|
||||||
headerWritten bool
|
|
||||||
contentLen int64 // if handler set valid Content-Length header
|
contentLen int64 // if handler set valid Content-Length header
|
||||||
numWritten int64 // bytes written
|
numWritten int64 // bytes written
|
||||||
|
headerWritten bool
|
||||||
|
isHead bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -162,6 +163,10 @@ func (w *responseWriter) Write(p []byte) (int, error) {
|
||||||
return 0, http.ErrContentLength
|
return 0, http.ErrContentLength
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if w.isHead {
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
df := &dataFrame{Length: uint64(len(p))}
|
df := &dataFrame{Length: uint64(len(p))}
|
||||||
w.buf = w.buf[:0]
|
w.buf = w.buf[:0]
|
||||||
w.buf = df.Append(w.buf)
|
w.buf = df.Append(w.buf)
|
||||||
|
|
|
@ -599,6 +599,9 @@ func (s *Server) handleRequest(conn quic.Connection, str quic.Stream, decoder *q
|
||||||
ctx = context.WithValue(ctx, http.LocalAddrContextKey, conn.LocalAddr())
|
ctx = context.WithValue(ctx, http.LocalAddrContextKey, conn.LocalAddr())
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
r := newResponseWriter(str, conn, s.logger)
|
r := newResponseWriter(str, conn, s.logger)
|
||||||
|
if req.Method == http.MethodHead {
|
||||||
|
r.isHead = true
|
||||||
|
}
|
||||||
handler := s.Handler
|
handler := s.Handler
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
handler = http.DefaultServeMux
|
handler = http.DefaultServeMux
|
||||||
|
|
|
@ -221,6 +221,45 @@ var _ = Describe("Server", func() {
|
||||||
Expect(hfs).To(HaveLen(3))
|
Expect(hfs).To(HaveLen(3))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("response to HEAD request should not have body", func() {
|
||||||
|
s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("foobar"))
|
||||||
|
})
|
||||||
|
|
||||||
|
headRequest, err := http.NewRequest("HEAD", "https://www.example.com", nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
responseBuf := &bytes.Buffer{}
|
||||||
|
setRequest(encodeRequest(headRequest))
|
||||||
|
str.EXPECT().Context().Return(reqContext)
|
||||||
|
str.EXPECT().Write(gomock.Any()).DoAndReturn(responseBuf.Write).AnyTimes()
|
||||||
|
str.EXPECT().CancelRead(gomock.Any())
|
||||||
|
serr := s.handleRequest(conn, str, qpackDecoder, nil)
|
||||||
|
Expect(serr.err).ToNot(HaveOccurred())
|
||||||
|
hfs := decodeHeader(responseBuf)
|
||||||
|
Expect(hfs).To(HaveKeyWithValue(":status", []string{"200"}))
|
||||||
|
Expect(responseBuf.Bytes()).To(HaveLen(0))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("response to HEAD request should also do content sniffing", func() {
|
||||||
|
s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("<html></html>"))
|
||||||
|
})
|
||||||
|
|
||||||
|
headRequest, err := http.NewRequest("HEAD", "https://www.example.com", nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
responseBuf := &bytes.Buffer{}
|
||||||
|
setRequest(encodeRequest(headRequest))
|
||||||
|
str.EXPECT().Context().Return(reqContext)
|
||||||
|
str.EXPECT().Write(gomock.Any()).DoAndReturn(responseBuf.Write).AnyTimes()
|
||||||
|
str.EXPECT().CancelRead(gomock.Any())
|
||||||
|
serr := s.handleRequest(conn, str, qpackDecoder, nil)
|
||||||
|
Expect(serr.err).ToNot(HaveOccurred())
|
||||||
|
hfs := decodeHeader(responseBuf)
|
||||||
|
Expect(hfs).To(HaveKeyWithValue(":status", []string{"200"}))
|
||||||
|
Expect(hfs).To(HaveKeyWithValue("content-length", []string{"13"}))
|
||||||
|
Expect(hfs).To(HaveKeyWithValue("content-type", []string{"text/html; charset=utf-8"}))
|
||||||
|
})
|
||||||
|
|
||||||
It("handles a aborting handler", func() {
|
It("handles a aborting handler", func() {
|
||||||
s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
panic(http.ErrAbortHandler)
|
panic(http.ErrAbortHandler)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue