Skip to content

Commit

Permalink
don't close the request stream when http3.DataStreamer was used (quic…
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-seemann authored and sudarshan-reddy committed Aug 9, 2022
1 parent ec17125 commit 3b0b415
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 11 deletions.
18 changes: 10 additions & 8 deletions http3/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -582,15 +582,17 @@ func (s *Server) handleRequest(conn quic.Connection, str quic.Stream, decoder *q
handler.ServeHTTP(r, req)
}()

if !r.usedDataStream() {
if panicked {
r.WriteHeader(500)
} else {
r.WriteHeader(200)
}
// If the EOF was read by the handler, CancelRead() is a no-op.
str.CancelRead(quic.StreamErrorCode(errorNoError))
if r.usedDataStream() {
return requestError{err: errHijacked}
}

if panicked {
r.WriteHeader(500)
} else {
r.WriteHeader(200)
}
// If the EOF was read by the handler, CancelRead() is a no-op.
str.CancelRead(quic.StreamErrorCode(errorNoError))
return requestError{}
}

Expand Down
30 changes: 27 additions & 3 deletions http3/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,13 +228,37 @@ var _ = Describe("Server", func() {
str.Write([]byte("foobar"))
})

rspWritten := make(chan struct{})
setRequest(encodeRequest(exampleGetRequest))
str.EXPECT().Context().Return(reqContext)
str.EXPECT().Write([]byte("foobar"))
str.EXPECT().Write([]byte("foobar")).Do(func(b []byte) (int, error) {
close(rspWritten)
return len(b), nil
})
// don't EXPECT CancelRead()

serr := s.handleRequest(conn, str, qpackDecoder, nil)
Expect(serr.err).ToNot(HaveOccurred())
ctrlStr := mockquic.NewMockStream(mockCtrl)
ctrlStr.EXPECT().Write(gomock.Any()).AnyTimes()
conn.EXPECT().OpenUniStream().Return(ctrlStr, nil)
conn.EXPECT().AcceptUniStream(gomock.Any()).DoAndReturn(func(context.Context) (quic.ReceiveStream, error) {
<-rspWritten
return nil, errors.New("done")
})
conn.EXPECT().AcceptStream(gomock.Any()).Return(str, nil)
conn.EXPECT().AcceptStream(gomock.Any()).DoAndReturn(func(context.Context) (quic.Stream, error) {
<-rspWritten
return nil, errors.New("done")
})

done := make(chan struct{})
go func() {
defer GinkgoRecover()
defer close(done)
s.handleConn(conn)
}()
Eventually(rspWritten).Should(BeClosed())
time.Sleep(50 * time.Millisecond) // make sure that after str.Write there are no further calls to stream methods
Eventually(done).Should(BeClosed())
})

Context("hijacking unidirectional streams", func() {
Expand Down

0 comments on commit 3b0b415

Please sign in to comment.