From 9294652ecc13a0eacbe6d009694be8c00d284489 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Thu, 22 Aug 2019 10:23:51 +0700 Subject: [PATCH] reject http3 requests that exceeded the header size limit --- http3/server.go | 12 +++++++++++- http3/server_test.go | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/http3/server.go b/http3/server.go index 13e74066a..e505a443c 100644 --- a/http3/server.go +++ b/http3/server.go @@ -155,6 +155,13 @@ func (s *Server) handleConn(sess quic.Session) { } } +func (s *Server) maxHeaderBytes() uint64 { + if s.Server.MaxHeaderBytes <= 0 { + return http.DefaultMaxHeaderBytes + } + return uint64(s.Server.MaxHeaderBytes) +} + // TODO: improve error handling. // Most (but not all) of the errors occurring here are connection-level erros. func (s *Server) handleRequest(str quic.Stream, decoder *qpack.Decoder) error { @@ -168,7 +175,10 @@ func (s *Server) handleRequest(str quic.Stream, decoder *qpack.Decoder) error { str.CancelWrite(quic.ErrorCode(errorUnexpectedFrame)) return errors.New("expected first frame to be a headers frame") } - // TODO: check length + if hf.Length > s.maxHeaderBytes() { + str.CancelWrite(quic.ErrorCode(errorLimitExceeded)) + return fmt.Errorf("Headers frame too large: %d bytes (max: %d)", hf.Length, s.maxHeaderBytes()) + } headerBlock := make([]byte, hf.Length) if _, err := io.ReadFull(str, headerBlock); err != nil { str.CancelWrite(quic.ErrorCode(errorIncompleteRequest)) diff --git a/http3/server_test.go b/http3/server_test.go index 314201e21..254095531 100644 --- a/http3/server_test.go +++ b/http3/server_test.go @@ -181,6 +181,28 @@ var _ = Describe("Server", func() { Expect(hfs).To(HaveKeyWithValue(":status", []string{"200"})) }) + It("errors when the client sends a too large header frame", func() { + s.Server.MaxHeaderBytes = 42 + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Fail("Handler should not be called.") + }) + + requestData := encodeRequest(exampleGetRequest) + buf := &bytes.Buffer{} + (&dataFrame{Length: 6}).Write(buf) // add a body + buf.Write([]byte("foobar")) + responseBuf := &bytes.Buffer{} + setRequest(append(requestData, buf.Bytes()...)) + str.EXPECT().Write(gomock.Any()).DoAndReturn(func(p []byte) (int, error) { + return responseBuf.Write(p) + }).AnyTimes() + + str.EXPECT().CancelWrite(quic.ErrorCode(errorLimitExceeded)) + err := s.handleRequest(str, qpackDecoder) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("Headers frame too large")) + }) + It("cancels reading when the body of POST request is not read", func() { handlerCalled := make(chan struct{}) s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {