소스 검색

Fix failing partial read on last frame of closed session (#95)

If the sending side of a stream closes both their stream and their
session, a partial read of the final frame on the receiving side may
fail because the receiving side tries to send a window update on a
closed session.

This commit changes Stream.Read() so that it ignores "session
shutdown" errors return by Stream.sendWindowUpdate(). This will let
Read() calls consume all of the final frame.
Jacob Vosmaer 2 년 전
부모
커밋
6c5a7317d6
2개의 변경된 파일59개의 추가작업 그리고 0개의 파일을 삭제
  1. 56 0
      session_test.go
  2. 3 0
      stream.go

+ 56 - 0
session_test.go

@@ -775,6 +775,62 @@ func TestHalfClose(t *testing.T) {
 	}
 }
 
+func TestHalfCloseSessionShutdown(t *testing.T) {
+	client, server := testClientServer()
+	defer client.Close()
+	defer server.Close()
+
+	// dataSize must be large enough to ensure the server will send a window
+	// update
+	dataSize := int64(server.config.MaxStreamWindowSize)
+
+	data := make([]byte, dataSize)
+	for idx := range data {
+		data[idx] = byte(idx % 256)
+	}
+
+	stream, err := client.Open()
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	if _, err = stream.Write(data); err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	stream2, err := server.Accept()
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if err := stream.Close(); err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Shut down the session of the sending side. This should not cause reads
+	// to fail on the receiving side.
+	if err := client.Close(); err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	buf := make([]byte, dataSize)
+	n, err := stream2.Read(buf)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	if int64(n) != dataSize {
+		t.Fatalf("bad: %v", n)
+	}
+
+	// EOF after close
+	n, err = stream2.Read(buf)
+	if err != io.EOF {
+		t.Fatalf("err: %v", err)
+	}
+	if n != 0 {
+		t.Fatalf("bad: %v", n)
+	}
+}
+
 func TestReadDeadline(t *testing.T) {
 	client, server := testClientServer()
 	defer client.Close()

+ 3 - 0
stream.go

@@ -128,6 +128,9 @@ START:
 
 	// Send a window update potentially
 	err = s.sendWindowUpdate()
+	if err == ErrSessionShutdown {
+		err = nil
+	}
 	return n, err
 
 WAIT: