github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/http3/http_stream_test.go (about) 1 package http3 2 3 import ( 4 "bytes" 5 "io" 6 "math" 7 "net/http" 8 9 mockquic "github.com/apernet/quic-go/internal/mocks/quic" 10 "github.com/apernet/quic-go/internal/protocol" 11 "github.com/apernet/quic-go/internal/qerr" 12 13 "github.com/quic-go/qpack" 14 15 . "github.com/onsi/ginkgo/v2" 16 . "github.com/onsi/gomega" 17 "go.uber.org/mock/gomock" 18 ) 19 20 func getDataFrame(data []byte) []byte { 21 b := (&dataFrame{Length: uint64(len(data))}).Append(nil) 22 return append(b, data...) 23 } 24 25 var _ = Describe("Stream", func() { 26 Context("reading", func() { 27 var ( 28 str Stream 29 qstr *mockquic.MockStream 30 buf *bytes.Buffer 31 errorCbCalled bool 32 ) 33 34 BeforeEach(func() { 35 buf = &bytes.Buffer{} 36 errorCbCalled = false 37 qstr = mockquic.NewMockStream(mockCtrl) 38 qstr.EXPECT().Write(gomock.Any()).DoAndReturn(buf.Write).AnyTimes() 39 qstr.EXPECT().Read(gomock.Any()).DoAndReturn(buf.Read).AnyTimes() 40 conn := mockquic.NewMockEarlyConnection(mockCtrl) 41 conn.EXPECT().CloseWithError(gomock.Any(), gomock.Any()).Do(func(qerr.ApplicationErrorCode, string) error { 42 errorCbCalled = true 43 return nil 44 }).AnyTimes() 45 str = newStream(qstr, newConnection(conn, false, protocol.PerspectiveClient, nil), nil) 46 }) 47 48 It("reads DATA frames in a single run", func() { 49 buf.Write(getDataFrame([]byte("foobar"))) 50 b := make([]byte, 6) 51 n, err := str.Read(b) 52 Expect(err).ToNot(HaveOccurred()) 53 Expect(n).To(Equal(6)) 54 Expect(b).To(Equal([]byte("foobar"))) 55 }) 56 57 It("reads DATA frames in multiple runs", func() { 58 buf.Write(getDataFrame([]byte("foobar"))) 59 b := make([]byte, 3) 60 n, err := str.Read(b) 61 Expect(err).ToNot(HaveOccurred()) 62 Expect(n).To(Equal(3)) 63 Expect(b).To(Equal([]byte("foo"))) 64 n, err = str.Read(b) 65 Expect(err).ToNot(HaveOccurred()) 66 Expect(n).To(Equal(3)) 67 Expect(b).To(Equal([]byte("bar"))) 68 }) 69 70 It("reads DATA frames into too large buffers", func() { 71 buf.Write(getDataFrame([]byte("foobar"))) 72 b := make([]byte, 10) 73 n, err := str.Read(b) 74 Expect(err).ToNot(HaveOccurred()) 75 Expect(n).To(Equal(6)) 76 Expect(b[:n]).To(Equal([]byte("foobar"))) 77 }) 78 79 It("reads DATA frames into too large buffers, in multiple runs", func() { 80 buf.Write(getDataFrame([]byte("foobar"))) 81 b := make([]byte, 4) 82 n, err := str.Read(b) 83 Expect(err).ToNot(HaveOccurred()) 84 Expect(n).To(Equal(4)) 85 Expect(b).To(Equal([]byte("foob"))) 86 n, err = str.Read(b) 87 Expect(err).ToNot(HaveOccurred()) 88 Expect(n).To(Equal(2)) 89 Expect(b[:n]).To(Equal([]byte("ar"))) 90 }) 91 92 It("reads multiple DATA frames", func() { 93 buf.Write(getDataFrame([]byte("foo"))) 94 buf.Write(getDataFrame([]byte("bar"))) 95 b := make([]byte, 6) 96 n, err := str.Read(b) 97 Expect(err).ToNot(HaveOccurred()) 98 Expect(n).To(Equal(3)) 99 Expect(b[:n]).To(Equal([]byte("foo"))) 100 n, err = str.Read(b) 101 Expect(err).ToNot(HaveOccurred()) 102 Expect(n).To(Equal(3)) 103 Expect(b[:n]).To(Equal([]byte("bar"))) 104 }) 105 106 It("skips HEADERS frames", func() { 107 b := getDataFrame([]byte("foo")) 108 b = (&headersFrame{Length: 10}).Append(b) 109 b = append(b, make([]byte, 10)...) 110 b = append(b, getDataFrame([]byte("bar"))...) 111 buf.Write(b) 112 r := make([]byte, 6) 113 n, err := io.ReadFull(str, r) 114 Expect(err).ToNot(HaveOccurred()) 115 Expect(n).To(Equal(6)) 116 Expect(r).To(Equal([]byte("foobar"))) 117 }) 118 119 It("errors when it can't parse the frame", func() { 120 buf.Write([]byte("invalid")) 121 _, err := str.Read([]byte{0}) 122 Expect(err).To(HaveOccurred()) 123 }) 124 125 It("errors on unexpected frames, and calls the error callback", func() { 126 b := (&settingsFrame{}).Append(nil) 127 buf.Write(b) 128 _, err := str.Read([]byte{0}) 129 Expect(err).To(MatchError("peer sent an unexpected frame: *http3.settingsFrame")) 130 Expect(errorCbCalled).To(BeTrue()) 131 }) 132 }) 133 134 Context("writing", func() { 135 It("writes data frames", func() { 136 buf := &bytes.Buffer{} 137 qstr := mockquic.NewMockStream(mockCtrl) 138 qstr.EXPECT().Write(gomock.Any()).DoAndReturn(buf.Write).AnyTimes() 139 str := newStream(qstr, nil, nil) 140 str.Write([]byte("foo")) 141 str.Write([]byte("foobar")) 142 143 f, err := parseNextFrame(buf, nil) 144 Expect(err).ToNot(HaveOccurred()) 145 Expect(f).To(Equal(&dataFrame{Length: 3})) 146 b := make([]byte, 3) 147 _, err = io.ReadFull(buf, b) 148 Expect(err).ToNot(HaveOccurred()) 149 Expect(b).To(Equal([]byte("foo"))) 150 151 f, err = parseNextFrame(buf, nil) 152 Expect(err).ToNot(HaveOccurred()) 153 Expect(f).To(Equal(&dataFrame{Length: 6})) 154 b = make([]byte, 6) 155 _, err = io.ReadFull(buf, b) 156 Expect(err).ToNot(HaveOccurred()) 157 Expect(b).To(Equal([]byte("foobar"))) 158 }) 159 }) 160 }) 161 162 var _ = Describe("Request Stream", func() { 163 var str *requestStream 164 var qstr *mockquic.MockStream 165 166 BeforeEach(func() { 167 qstr = mockquic.NewMockStream(mockCtrl) 168 requestWriter := newRequestWriter() 169 conn := mockquic.NewMockEarlyConnection(mockCtrl) 170 str = newRequestStream( 171 newStream(qstr, newConnection(conn, false, protocol.PerspectiveClient, nil), nil), 172 requestWriter, 173 make(chan struct{}), 174 qpack.NewDecoder(func(qpack.HeaderField) {}), 175 true, 176 math.MaxUint64, 177 ) 178 }) 179 180 It("refuses to read before having read the response", func() { 181 _, err := str.Read(make([]byte, 100)) 182 Expect(err).To(MatchError("http3: invalid use of RequestStream.Read: need to call ReadResponse first")) 183 }) 184 185 It("prevents duplicate calls to SendRequestHeader", func() { 186 req, err := http.NewRequest(http.MethodGet, "https://quic-go.net", nil) 187 Expect(err).ToNot(HaveOccurred()) 188 qstr.EXPECT().Write(gomock.Any()).AnyTimes() 189 Expect(str.SendRequestHeader(req)).To(Succeed()) 190 Expect(str.SendRequestHeader(req)).To(MatchError("http3: invalid duplicate use of SendRequestHeader")) 191 }) 192 193 It("reads after the response", func() { 194 req, err := http.NewRequest(http.MethodGet, "https://quic-go.net", nil) 195 Expect(err).ToNot(HaveOccurred()) 196 qstr.EXPECT().Write(gomock.Any()).AnyTimes() 197 Expect(str.SendRequestHeader(req)).To(Succeed()) 198 199 buf := bytes.NewBuffer(encodeResponse(200)) 200 buf.Write((&dataFrame{Length: 6}).Append(nil)) 201 buf.Write([]byte("foobar")) 202 qstr.EXPECT().Read(gomock.Any()).DoAndReturn(buf.Read).AnyTimes() 203 rsp, err := str.ReadResponse() 204 Expect(err).ToNot(HaveOccurred()) 205 Expect(rsp.StatusCode).To(Equal(200)) 206 b := make([]byte, 10) 207 n, err := str.Read(b) 208 Expect(err).ToNot(HaveOccurred()) 209 Expect(n).To(Equal(6)) 210 Expect(b[:n]).To(Equal([]byte("foobar"))) 211 }) 212 })