Skip to content

Commit 3c1185a

Browse files
neildgopherbot
authored andcommitted
internal/http3: return error on mid-frame EOF
When a stream ends in the middle of a frame, return a non-EOF error from Read or ReadByte. When a stream ends at the end of a frame, don't return io.EOF from the Read call that reads the last byte of the frame. (This complicates stream.Read slightly, but means that code that reads frames consistently never sees an io.EOF, but gets an error if it tries to read past the end of a frame.) For golang/go#70914 Change-Id: If1b852716fe5e3aa3503f6970e2e1fba2ebb5f48 Reviewed-on: https://go-review.googlesource.com/c/net/+/644116 Auto-Submit: Damien Neil <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Jonathan Amsterdam <[email protected]>
1 parent a6c2c7f commit 3c1185a

File tree

2 files changed

+65
-8
lines changed

2 files changed

+65
-8
lines changed

internal/http3/stream.go

+16-7
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func (st *stream) ReadByte() (b byte, err error) {
114114
}
115115
b, err = st.stream.ReadByte()
116116
if err != nil {
117-
if err == io.EOF {
117+
if err == io.EOF && st.lim < 0 {
118118
return 0, io.EOF
119119
}
120120
return 0, errH3FrameError
@@ -125,14 +125,23 @@ func (st *stream) ReadByte() (b byte, err error) {
125125
// Read reads from the stream.
126126
func (st *stream) Read(b []byte) (int, error) {
127127
n, err := st.stream.Read(b)
128-
if err != nil {
129-
if err == io.EOF {
130-
return 0, io.EOF
128+
if e2 := st.recordBytesRead(n); e2 != nil {
129+
return 0, e2
130+
}
131+
if err == io.EOF {
132+
if st.lim == 0 {
133+
// EOF at end of frame, ignore.
134+
return n, nil
135+
} else if st.lim > 0 {
136+
// EOF inside frame, error.
137+
return 0, errH3FrameError
138+
} else {
139+
// EOF outside of frame, surface to caller.
140+
return n, io.EOF
131141
}
132-
return 0, errH3FrameError
133142
}
134-
if err := st.recordBytesRead(n); err != nil {
135-
return 0, err
143+
if err != nil {
144+
return 0, errH3FrameError
136145
}
137146
return n, nil
138147
}

internal/http3/stream_test.go

+49-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ func TestStreamReadFrameOverflow(t *testing.T) {
183183
}
184184
}
185185

186-
func TestStreamReadFramePartial(t *testing.T) {
186+
func TestStreamReadFrameHeaderPartial(t *testing.T) {
187187
var frame []byte
188188
frame = quicwire.AppendVarint(frame, 1000) // type
189189
frame = quicwire.AppendVarint(frame, 2000) // size
@@ -202,6 +202,54 @@ func TestStreamReadFramePartial(t *testing.T) {
202202
}
203203
}
204204

205+
func TestStreamReadFrameDataPartial(t *testing.T) {
206+
st1, st2 := newStreamPair(t)
207+
st1.writeVarint(1) // type
208+
st1.writeVarint(100) // size
209+
st1.Write(make([]byte, 50)) // data
210+
st1.stream.CloseWrite()
211+
if _, err := st2.readFrameHeader(); err != nil {
212+
t.Fatalf("st.readFrameHeader() = %v", err)
213+
}
214+
if n, err := io.ReadAll(st2); err == nil {
215+
t.Fatalf("io.ReadAll with partial frame = %v, nil; want error", n)
216+
}
217+
}
218+
219+
func TestStreamReadByteFrameDataPartial(t *testing.T) {
220+
st1, st2 := newStreamPair(t)
221+
st1.writeVarint(1) // type
222+
st1.writeVarint(100) // size
223+
st1.stream.CloseWrite()
224+
if _, err := st2.readFrameHeader(); err != nil {
225+
t.Fatalf("st.readFrameHeader() = %v", err)
226+
}
227+
if b, err := st2.ReadByte(); err == nil {
228+
t.Fatalf("io.ReadAll with partial frame = %v, nil; want error", b)
229+
}
230+
}
231+
232+
func TestStreamReadFrameDataAtEOF(t *testing.T) {
233+
const typ = 10
234+
data := []byte("hello")
235+
st1, st2 := newStreamPair(t)
236+
st1.writeVarint(typ) // type
237+
st1.writeVarint(int64(len(data))) // size
238+
if err := st1.Flush(); err != nil {
239+
t.Fatal(err)
240+
}
241+
if got, err := st2.readFrameHeader(); err != nil || got != typ {
242+
t.Fatalf("st.readFrameHeader() = %v, %v; want %v, nil", got, err, typ)
243+
}
244+
245+
st1.Write(data) // data
246+
st1.stream.CloseWrite() // end stream
247+
got := make([]byte, len(data)+1)
248+
if n, err := st2.Read(got); err != nil || n != len(data) || !bytes.Equal(got[:n], data) {
249+
t.Fatalf("st.Read() = %v, %v (data=%x); want %v, nil (data=%x)", n, err, got[:n], len(data), data)
250+
}
251+
}
252+
205253
func TestStreamReadFrameData(t *testing.T) {
206254
const typ = 10
207255
data := []byte("hello")

0 commit comments

Comments
 (0)