From 04eebb7f6ae63992eaae514405f757ea18afcb65 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Mon, 21 Dec 2020 15:31:36 +0700 Subject: [PATCH] reject push streams initiated by the client --- http3/server.go | 9 ++++++++- http3/server_test.go | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/http3/server.go b/http3/server.go index fbc46b2c..4a745d77 100644 --- a/http3/server.go +++ b/http3/server.go @@ -40,6 +40,7 @@ const ( nextProtoH3Draft29 = "h3-29" nextProtoH3Draft32 = "h3-32" streamTypeControlStream = 0 + streamTypePushStream = 1 ) func versionToALPN(v protocol.VersionNumber) string { @@ -272,7 +273,13 @@ func (s *Server) handleUnidirectionalStreams(sess quic.EarlySession) { s.logger.Debugf("reading stream type on stream %d failed: %s", str.StreamID(), err) return } - if streamType != streamTypeControlStream { + // We're only interested in the control stream here. + switch streamType { + case streamTypeControlStream: + case streamTypePushStream: // only the server can push + sess.CloseWithError(quic.ErrorCode(errorStreamCreationError), "") + return + default: return } f, err := parseNextFrame(str) diff --git a/http3/server_test.go b/http3/server_test.go index b4afaf22..018195c7 100644 --- a/http3/server_test.go +++ b/http3/server_test.go @@ -287,6 +287,29 @@ var _ = Describe("Server", func() { s.handleConn(sess) Eventually(done).Should(BeClosed()) }) + + It("errors when the client opens a push stream", func() { + buf := &bytes.Buffer{} + utils.WriteVarInt(buf, streamTypePushStream) + (&dataFrame{}).Write(buf) + controlStr := mockquic.NewMockStream(mockCtrl) + controlStr.EXPECT().Read(gomock.Any()).DoAndReturn(buf.Read).AnyTimes() + sess.EXPECT().AcceptUniStream(gomock.Any()).DoAndReturn(func(context.Context) (quic.ReceiveStream, error) { + return controlStr, nil + }) + sess.EXPECT().AcceptUniStream(gomock.Any()).DoAndReturn(func(context.Context) (quic.ReceiveStream, error) { + <-testDone + return nil, errors.New("test done") + }) + done := make(chan struct{}) + sess.EXPECT().CloseWithError(gomock.Any(), gomock.Any()).Do(func(code quic.ErrorCode, _ string) { + defer GinkgoRecover() + Expect(code).To(BeEquivalentTo(errorStreamCreationError)) + close(done) + }) + s.handleConn(sess) + Eventually(done).Should(BeClosed()) + }) }) Context("stream- and connection-level errors", func() {