github.com/quic-go/quic-go@v0.44.0/http3/frames_test.go (about) 1 package http3 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 9 "github.com/quic-go/quic-go" 10 mockquic "github.com/quic-go/quic-go/internal/mocks/quic" 11 "github.com/quic-go/quic-go/quicvarint" 12 13 . "github.com/onsi/ginkgo/v2" 14 . "github.com/onsi/gomega" 15 "go.uber.org/mock/gomock" 16 ) 17 18 type errReader struct{ err error } 19 20 func (e errReader) Read([]byte) (int, error) { return 0, e.err } 21 22 var _ = Describe("Frames", func() { 23 It("skips unknown frames", func() { 24 data := quicvarint.Append(nil, 0xdeadbeef) // type byte 25 data = quicvarint.Append(data, 0x42) 26 data = append(data, make([]byte, 0x42)...) 27 data = (&dataFrame{Length: 0x1234}).Append(data) 28 fp := frameParser{r: bytes.NewReader(data)} 29 frame, err := fp.ParseNext() 30 Expect(err).ToNot(HaveOccurred()) 31 Expect(frame).To(BeAssignableToTypeOf(&dataFrame{})) 32 Expect(frame.(*dataFrame).Length).To(Equal(uint64(0x1234))) 33 }) 34 35 It("closes the connection when encountering a reserved frame type", func() { 36 conn := mockquic.NewMockEarlyConnection(mockCtrl) 37 for _, ft := range []uint64{0x2, 0x6, 0x8, 0x9} { 38 data := quicvarint.Append(nil, ft) 39 data = quicvarint.Append(data, 6) 40 data = append(data, []byte("foobar")...) 41 42 conn.EXPECT().CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), gomock.Any()) 43 fp := frameParser{ 44 r: bytes.NewReader(data), 45 conn: conn, 46 } 47 _, err := fp.ParseNext() 48 Expect(err).To(HaveOccurred()) 49 Expect(err.Error()).To(ContainSubstring("http3: reserved frame type")) 50 } 51 }) 52 53 Context("DATA frames", func() { 54 It("parses", func() { 55 data := quicvarint.Append(nil, 0) // type byte 56 data = quicvarint.Append(data, 0x1337) 57 fp := frameParser{r: bytes.NewReader(data)} 58 frame, err := fp.ParseNext() 59 Expect(err).ToNot(HaveOccurred()) 60 Expect(frame).To(BeAssignableToTypeOf(&dataFrame{})) 61 Expect(frame.(*dataFrame).Length).To(Equal(uint64(0x1337))) 62 }) 63 64 It("writes", func() { 65 fp := frameParser{r: bytes.NewReader((&dataFrame{Length: 0xdeadbeef}).Append(nil))} 66 frame, err := fp.ParseNext() 67 Expect(err).ToNot(HaveOccurred()) 68 Expect(err).ToNot(HaveOccurred()) 69 Expect(frame).To(BeAssignableToTypeOf(&dataFrame{})) 70 Expect(frame.(*dataFrame).Length).To(Equal(uint64(0xdeadbeef))) 71 }) 72 }) 73 74 Context("HEADERS frames", func() { 75 It("parses", func() { 76 data := quicvarint.Append(nil, 1) // type byte 77 data = quicvarint.Append(data, 0x1337) 78 fp := frameParser{r: bytes.NewReader(data)} 79 frame, err := fp.ParseNext() 80 Expect(err).ToNot(HaveOccurred()) 81 Expect(frame).To(BeAssignableToTypeOf(&headersFrame{})) 82 Expect(frame.(*headersFrame).Length).To(Equal(uint64(0x1337))) 83 }) 84 85 It("writes", func() { 86 data := (&headersFrame{Length: 0xdeadbeef}).Append(nil) 87 fp := frameParser{r: bytes.NewReader(data)} 88 frame, err := fp.ParseNext() 89 Expect(err).ToNot(HaveOccurred()) 90 Expect(err).ToNot(HaveOccurred()) 91 Expect(frame).To(BeAssignableToTypeOf(&headersFrame{})) 92 Expect(frame.(*headersFrame).Length).To(Equal(uint64(0xdeadbeef))) 93 }) 94 }) 95 96 Context("SETTINGS frames", func() { 97 It("parses", func() { 98 settings := quicvarint.Append(nil, 13) 99 settings = quicvarint.Append(settings, 37) 100 settings = quicvarint.Append(settings, 0xdead) 101 settings = quicvarint.Append(settings, 0xbeef) 102 data := quicvarint.Append(nil, 4) // type byte 103 data = quicvarint.Append(data, uint64(len(settings))) 104 data = append(data, settings...) 105 fp := frameParser{r: bytes.NewReader(data)} 106 frame, err := fp.ParseNext() 107 Expect(err).ToNot(HaveOccurred()) 108 Expect(frame).To(BeAssignableToTypeOf(&settingsFrame{})) 109 sf := frame.(*settingsFrame) 110 Expect(sf.Other).To(HaveKeyWithValue(uint64(13), uint64(37))) 111 Expect(sf.Other).To(HaveKeyWithValue(uint64(0xdead), uint64(0xbeef))) 112 }) 113 114 It("rejects duplicate settings", func() { 115 settings := quicvarint.Append(nil, 13) 116 settings = quicvarint.Append(settings, 37) 117 settings = quicvarint.Append(settings, 13) 118 settings = quicvarint.Append(settings, 38) 119 data := quicvarint.Append(nil, 4) // type byte 120 data = quicvarint.Append(data, uint64(len(settings))) 121 data = append(data, settings...) 122 fp := frameParser{r: bytes.NewReader(data)} 123 _, err := fp.ParseNext() 124 Expect(err).To(MatchError("duplicate setting: 13")) 125 }) 126 127 It("writes", func() { 128 sf := &settingsFrame{Other: map[uint64]uint64{ 129 1: 2, 130 99: 999, 131 13: 37, 132 }} 133 fp := frameParser{r: bytes.NewReader(sf.Append(nil))} 134 frame, err := fp.ParseNext() 135 Expect(err).ToNot(HaveOccurred()) 136 Expect(frame).To(Equal(sf)) 137 }) 138 139 It("errors on EOF", func() { 140 sf := &settingsFrame{Other: map[uint64]uint64{ 141 13: 37, 142 0xdeadbeef: 0xdecafbad, 143 }} 144 data := sf.Append(nil) 145 fp := frameParser{r: bytes.NewReader(data)} 146 _, err := fp.ParseNext() 147 Expect(err).ToNot(HaveOccurred()) 148 149 for i := range data { 150 b := make([]byte, i) 151 copy(b, data[:i]) 152 fp := frameParser{r: bytes.NewReader(b)} 153 _, err := fp.ParseNext() 154 Expect(err).To(MatchError(io.EOF)) 155 } 156 }) 157 158 Context("HTTP Datagrams", func() { 159 It("reads the SETTINGS_H3_DATAGRAM value", func() { 160 settings := quicvarint.Append(nil, settingDatagram) 161 settings = quicvarint.Append(settings, 1) 162 data := quicvarint.Append(nil, 4) // type byte 163 data = quicvarint.Append(data, uint64(len(settings))) 164 data = append(data, settings...) 165 fp := frameParser{r: bytes.NewReader(data)} 166 f, err := fp.ParseNext() 167 Expect(err).ToNot(HaveOccurred()) 168 Expect(f).To(BeAssignableToTypeOf(&settingsFrame{})) 169 sf := f.(*settingsFrame) 170 Expect(sf.Datagram).To(BeTrue()) 171 }) 172 173 It("rejects duplicate SETTINGS_H3_DATAGRAM entries", func() { 174 settings := quicvarint.Append(nil, settingDatagram) 175 settings = quicvarint.Append(settings, 1) 176 settings = quicvarint.Append(settings, settingDatagram) 177 settings = quicvarint.Append(settings, 1) 178 data := quicvarint.Append(nil, 4) // type byte 179 data = quicvarint.Append(data, uint64(len(settings))) 180 data = append(data, settings...) 181 fp := frameParser{r: bytes.NewReader(data)} 182 _, err := fp.ParseNext() 183 Expect(err).To(MatchError(fmt.Sprintf("duplicate setting: %d", settingDatagram))) 184 }) 185 186 It("rejects invalid values for the SETTINGS_H3_DATAGRAM entry", func() { 187 settings := quicvarint.Append(nil, settingDatagram) 188 settings = quicvarint.Append(settings, 1337) 189 data := quicvarint.Append(nil, 4) // type byte 190 data = quicvarint.Append(data, uint64(len(settings))) 191 data = append(data, settings...) 192 fp := frameParser{r: bytes.NewReader(data)} 193 _, err := fp.ParseNext() 194 Expect(err).To(MatchError("invalid value for SETTINGS_H3_DATAGRAM: 1337")) 195 }) 196 197 It("writes the SETTINGS_H3_DATAGRAM setting", func() { 198 sf := &settingsFrame{Datagram: true} 199 fp := frameParser{r: bytes.NewReader(sf.Append(nil))} 200 frame, err := fp.ParseNext() 201 Expect(err).ToNot(HaveOccurred()) 202 Expect(frame).To(Equal(sf)) 203 }) 204 }) 205 206 Context("Extended Connect", func() { 207 It("reads the SETTINGS_ENABLE_CONNECT_PROTOCOL value", func() { 208 settings := quicvarint.Append(nil, settingExtendedConnect) 209 settings = quicvarint.Append(settings, 1) 210 data := quicvarint.Append(nil, 4) // type byte 211 data = quicvarint.Append(data, uint64(len(settings))) 212 data = append(data, settings...) 213 fp := frameParser{r: bytes.NewReader(data)} 214 f, err := fp.ParseNext() 215 Expect(err).ToNot(HaveOccurred()) 216 Expect(f).To(BeAssignableToTypeOf(&settingsFrame{})) 217 sf := f.(*settingsFrame) 218 Expect(sf.ExtendedConnect).To(BeTrue()) 219 }) 220 221 It("rejects duplicate SETTINGS_ENABLE_CONNECT_PROTOCOL entries", func() { 222 settings := quicvarint.Append(nil, settingExtendedConnect) 223 settings = quicvarint.Append(settings, 1) 224 settings = quicvarint.Append(settings, settingExtendedConnect) 225 settings = quicvarint.Append(settings, 1) 226 data := quicvarint.Append(nil, 4) // type byte 227 data = quicvarint.Append(data, uint64(len(settings))) 228 data = append(data, settings...) 229 fp := frameParser{r: bytes.NewReader(data)} 230 _, err := fp.ParseNext() 231 Expect(err).To(MatchError(fmt.Sprintf("duplicate setting: %d", settingExtendedConnect))) 232 }) 233 234 It("rejects invalid values for the SETTINGS_ENABLE_CONNECT_PROTOCOL entry", func() { 235 settings := quicvarint.Append(nil, settingExtendedConnect) 236 settings = quicvarint.Append(settings, 1337) 237 data := quicvarint.Append(nil, 4) // type byte 238 data = quicvarint.Append(data, uint64(len(settings))) 239 data = append(data, settings...) 240 fp := frameParser{r: bytes.NewReader(data)} 241 _, err := fp.ParseNext() 242 Expect(err).To(MatchError("invalid value for SETTINGS_ENABLE_CONNECT_PROTOCOL: 1337")) 243 }) 244 245 It("writes the SETTINGS_ENABLE_CONNECT_PROTOCOL setting", func() { 246 sf := &settingsFrame{ExtendedConnect: true} 247 fp := frameParser{r: bytes.NewReader(sf.Append(nil))} 248 frame, err := fp.ParseNext() 249 Expect(err).ToNot(HaveOccurred()) 250 Expect(frame).To(Equal(sf)) 251 }) 252 }) 253 }) 254 255 Context("hijacking", func() { 256 It("reads a frame without hijacking the stream", func() { 257 buf := bytes.NewBuffer(quicvarint.Append(nil, 1337)) 258 customFrameContents := []byte("foobar") 259 buf.Write(customFrameContents) 260 261 var called bool 262 fp := frameParser{ 263 r: buf, 264 unknownFrameHandler: func(ft FrameType, e error) (hijacked bool, err error) { 265 Expect(e).ToNot(HaveOccurred()) 266 Expect(ft).To(BeEquivalentTo(1337)) 267 called = true 268 b := make([]byte, 3) 269 _, err = io.ReadFull(buf, b) 270 Expect(err).ToNot(HaveOccurred()) 271 Expect(string(b)).To(Equal("foo")) 272 return true, nil 273 }, 274 } 275 _, err := fp.ParseNext() 276 Expect(err).To(MatchError(errHijacked)) 277 Expect(called).To(BeTrue()) 278 }) 279 280 It("passes on errors that occur when reading the frame type", func() { 281 testErr := errors.New("test error") 282 var called bool 283 fp := frameParser{ 284 r: errReader{err: testErr}, 285 unknownFrameHandler: func(ft FrameType, e error) (hijacked bool, err error) { 286 Expect(e).To(MatchError(testErr)) 287 Expect(ft).To(BeZero()) 288 called = true 289 return true, nil 290 }, 291 } 292 _, err := fp.ParseNext() 293 Expect(err).To(MatchError(errHijacked)) 294 Expect(called).To(BeTrue()) 295 }) 296 297 It("reads a frame without hijacking the stream", func() { 298 b := quicvarint.Append(nil, 1337) 299 customFrameContents := []byte("custom frame") 300 b = quicvarint.Append(b, uint64(len(customFrameContents))) 301 b = append(b, customFrameContents...) 302 b = (&dataFrame{Length: 6}).Append(b) 303 b = append(b, []byte("foobar")...) 304 305 var called bool 306 fp := frameParser{ 307 r: bytes.NewReader(b), 308 unknownFrameHandler: func(ft FrameType, e error) (hijacked bool, err error) { 309 Expect(e).ToNot(HaveOccurred()) 310 Expect(ft).To(BeEquivalentTo(1337)) 311 called = true 312 return false, nil 313 }, 314 } 315 frame, err := fp.ParseNext() 316 Expect(err).ToNot(HaveOccurred()) 317 Expect(frame).To(Equal(&dataFrame{Length: 6})) 318 Expect(called).To(BeTrue()) 319 }) 320 }) 321 })