Skip to content

Commit 2731ece

Browse files
secfix
1 parent 9f80274 commit 2731ece

3 files changed

Lines changed: 66 additions & 6 deletions

File tree

internal/transport/http2_server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ func (t *http2Server) operateHeaders(ctx context.Context, frame *http2.MetaHeade
531531
if frame.StreamEnded() {
532532
// s is just created by the caller. No lock needed.
533533
s.state = streamReadDone
534+
s.write(recvMsg{err: io.EOF})
534535
}
535536
if timeoutSet {
536537
s.ctx, s.cancel = context.WithTimeout(ctx, timeout)

test/end2end_test.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4765,14 +4765,20 @@ func testClientInitialHeaderEndStream(t *testing.T, e env) {
47654765
te := newTest(t, e)
47664766
ts := &funcServer{streamingInputCall: func(stream testgrpc.TestService_StreamingInputCallServer) error {
47674767
defer close(handlerDone)
4768-
// Block on serverTester receiving RST_STREAM. This ensures server has closed
4769-
// stream before stream.Recv().
4768+
// Block on serverTester receiving RST_STREAM. This ensures server has
4769+
// closed stream before stream.Recv().
47704770
<-frameCheckingDone
4771-
data, err := stream.Recv()
4772-
if err == nil {
4773-
t.Errorf("unexpected data received in func server method: '%v'", data)
4771+
// Depending on whether the context cancellation (due to the illegal data
4772+
// RST_STREAM) or the buffered EOF (from the initial HEADERS END_STREAM) is
4773+
// selected first in recvBufferReader, stream.Recv() can return either
4774+
// io.EOF or Canceled.
4775+
if _, err := stream.Recv(); err != io.EOF && status.Code(err) != codes.Canceled {
4776+
t.Errorf("expected EOF or canceled error, instead received '%v'", err)
4777+
}
4778+
if err := stream.SendMsg(nil); err == nil {
4779+
t.Error("expected error sending message on stream after stream closed due to illegal data")
47744780
} else if status.Code(err) != codes.Canceled {
4775-
t.Errorf("expected canceled error, instead received '%v'", err)
4781+
t.Errorf("expected cancel error, instead received '%v'", err)
47764782
}
47774783
return nil
47784784
}}

test/transport_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,3 +302,56 @@ func (s) TestCancelWhileServerWaitingForFlowControl(t *testing.T) {
302302
t.Fatalf("Failed to read from the stream: %v", err)
303303
}
304304
}
305+
306+
// Tests that when a client sends a HEADERS frame with EndStream=true, the
307+
// server-side stream receives an io.EOF on Recv() and does not hang waiting
308+
// for data frames.
309+
func (s) TestHeadersEndStreamNoHang(t *testing.T) {
310+
receivedErr := make(chan error, 1)
311+
ss := &stubserver.StubServer{
312+
FullDuplexCallF: func(stream testgrpc.TestService_FullDuplexCallServer) error {
313+
_, err := stream.Recv()
314+
receivedErr <- err
315+
return nil
316+
},
317+
}
318+
if err := ss.Start(nil); err != nil {
319+
t.Fatalf("Error starting endpoint server: %v", err)
320+
}
321+
defer ss.Stop()
322+
323+
conn, err := net.DialTimeout("tcp", ss.Address, defaultTestTimeout)
324+
if err != nil {
325+
t.Fatalf("Failed to dial: %v", err)
326+
}
327+
defer conn.Close()
328+
329+
st := newServerTesterFromConn(t, conn)
330+
st.greet()
331+
332+
// Send HEADERS with EndStream = true and no grpc-timeout header.
333+
st.writeHeaders(http2.HeadersFrameParam{
334+
StreamID: 1,
335+
BlockFragment: st.encodeHeader(
336+
":method", "POST",
337+
":path", "/grpc.testing.TestService/FullDuplexCall",
338+
":authority", "localhost",
339+
"content-type", "application/grpc",
340+
"te", "trailers",
341+
),
342+
EndStream: true,
343+
EndHeaders: true,
344+
})
345+
346+
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
347+
defer cancel()
348+
349+
select {
350+
case err := <-receivedErr:
351+
if err != io.EOF {
352+
t.Fatalf("Streaming handler expected io.EOF, got %v", err)
353+
}
354+
case <-ctx.Done():
355+
t.Fatalf("Timed out waiting for Recv() on the server to complete: %v", ctx.Err())
356+
}
357+
}

0 commit comments

Comments
 (0)