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