diff --git a/h2quic/server.go b/h2quic/server.go index 8b591ec2..82166310 100644 --- a/h2quic/server.go +++ b/h2quic/server.go @@ -154,6 +154,10 @@ func (s *Server) handleRequest(session streamCreator, headerStream utils.Stream, if err != nil { return err } + // this can happen if the client immediately closes the data stream after sending the request and the runtime processes the reset before the request + if dataStream == nil { + return nil + } var streamEnded bool if h2headersFrame.StreamEnded() { diff --git a/h2quic/server_test.go b/h2quic/server_test.go index 231647c1..1f9a22c7 100644 --- a/h2quic/server_test.go +++ b/h2quic/server_test.go @@ -25,7 +25,7 @@ import ( type mockSession struct { closed bool closedWithError error - dataStream *mockStream + dataStream utils.Stream } func (s *mockSession) GetOrOpenStream(id protocol.StreamID) (utils.Stream, error) { @@ -153,6 +153,22 @@ var _ = Describe("H2 server", func() { Expect(handlerCalled).To(BeTrue()) }) + It("handles a request for which the client immediately resets the data stream", func() { + session.dataStream = nil + var handlerCalled bool + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + handlerCalled = true + }) + headerStream.dataToRead.Write([]byte{ + 0x0, 0x0, 0x11, 0x1, 0x5, 0x0, 0x0, 0x0, 0x5, + // Taken from https://http2.github.io/http2-spec/compression.html#request.examples.with.huffman.coding + 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, + }) + err := s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) + Expect(err).NotTo(HaveOccurred()) + Consistently(func() bool { return handlerCalled }).Should(BeFalse()) + }) + It("resets the dataStream when the body of POST request is not read, and the request handler replaces the request.Body", func() { var handlerCalled bool s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {