github.com/MerlinKodo/quic-go@v0.39.2/http3/frames_test.go (about) 1 package http3 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 9 "github.com/MerlinKodo/quic-go/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("H3_DATAGRAM", func() { 131 It("reads the 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 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 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 H3_DATAGRAM: 1337")) 164 }) 165 166 It("writes the 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 175 Context("hijacking", func() { 176 It("reads a frame without hijacking the stream", func() { 177 buf := bytes.NewBuffer(quicvarint.Append(nil, 1337)) 178 customFrameContents := []byte("foobar") 179 buf.Write(customFrameContents) 180 181 var called bool 182 _, err := parseNextFrame(buf, func(ft FrameType, e error) (hijacked bool, err error) { 183 Expect(e).ToNot(HaveOccurred()) 184 Expect(ft).To(BeEquivalentTo(1337)) 185 called = true 186 b := make([]byte, 3) 187 _, err = io.ReadFull(buf, b) 188 Expect(err).ToNot(HaveOccurred()) 189 Expect(string(b)).To(Equal("foo")) 190 return true, nil 191 }) 192 Expect(err).To(MatchError(errHijacked)) 193 Expect(called).To(BeTrue()) 194 }) 195 196 It("passes on errors that occur when reading the frame type", func() { 197 testErr := errors.New("test error") 198 var called bool 199 _, err := parseNextFrame(errReader{err: testErr}, func(ft FrameType, e error) (hijacked bool, err error) { 200 Expect(e).To(MatchError(testErr)) 201 Expect(ft).To(BeZero()) 202 called = true 203 return true, nil 204 }) 205 Expect(err).To(MatchError(errHijacked)) 206 Expect(called).To(BeTrue()) 207 }) 208 209 It("reads a frame without hijacking the stream", func() { 210 b := quicvarint.Append(nil, 1337) 211 customFrameContents := []byte("custom frame") 212 b = quicvarint.Append(b, uint64(len(customFrameContents))) 213 b = append(b, customFrameContents...) 214 b = (&dataFrame{Length: 6}).Append(b) 215 b = append(b, []byte("foobar")...) 216 217 var called bool 218 frame, err := parseNextFrame(bytes.NewReader(b), func(ft FrameType, e error) (hijacked bool, err error) { 219 Expect(e).ToNot(HaveOccurred()) 220 Expect(ft).To(BeEquivalentTo(1337)) 221 called = true 222 return false, nil 223 }) 224 Expect(err).ToNot(HaveOccurred()) 225 Expect(frame).To(Equal(&dataFrame{Length: 6})) 226 Expect(called).To(BeTrue()) 227 }) 228 }) 229 })