github.com/danielpfeifer02/quic-go-prio-packs@v0.41.0-28/http3/frames.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/internal/protocol" 10 "github.com/danielpfeifer02/quic-go-prio-packs/quicvarint" 11 ) 12 13 // FrameType is the frame type of a HTTP/3 frame 14 type FrameType uint64 15 16 type unknownFrameHandlerFunc func(FrameType, error) (processed bool, err error) 17 18 type frame interface{} 19 20 var errHijacked = errors.New("hijacked") 21 22 func parseNextFrame(r io.Reader, unknownFrameHandler unknownFrameHandlerFunc) (frame, error) { 23 qr := quicvarint.NewReader(r) 24 for { 25 t, err := quicvarint.Read(qr) 26 if err != nil { 27 if unknownFrameHandler != nil { 28 hijacked, err := unknownFrameHandler(0, err) 29 if err != nil { 30 return nil, err 31 } 32 if hijacked { 33 return nil, errHijacked 34 } 35 } 36 return nil, err 37 } 38 // Call the unknownFrameHandler for frames not defined in the HTTP/3 spec 39 if t > 0xd && unknownFrameHandler != nil { 40 hijacked, err := unknownFrameHandler(FrameType(t), nil) 41 if err != nil { 42 return nil, err 43 } 44 if hijacked { 45 return nil, errHijacked 46 } 47 // If the unknownFrameHandler didn't process the frame, it is our responsibility to skip it. 48 } 49 l, err := quicvarint.Read(qr) 50 if err != nil { 51 return nil, err 52 } 53 54 switch t { 55 case 0x0: 56 return &dataFrame{Length: l}, nil 57 case 0x1: 58 return &headersFrame{Length: l}, nil 59 case 0x4: 60 return parseSettingsFrame(r, l) 61 case 0x3: // CANCEL_PUSH 62 case 0x5: // PUSH_PROMISE 63 case 0x7: // GOAWAY 64 case 0xd: // MAX_PUSH_ID 65 } 66 // skip over unknown frames 67 if _, err := io.CopyN(io.Discard, qr, int64(l)); err != nil { 68 return nil, err 69 } 70 } 71 } 72 73 type dataFrame struct { 74 Length uint64 75 } 76 77 func (f *dataFrame) Append(b []byte) []byte { 78 b = quicvarint.Append(b, 0x0) 79 return quicvarint.Append(b, f.Length) 80 } 81 82 type headersFrame struct { 83 Length uint64 84 } 85 86 func (f *headersFrame) Append(b []byte) []byte { 87 b = quicvarint.Append(b, 0x1) 88 return quicvarint.Append(b, f.Length) 89 } 90 91 const ( 92 // Extended CONNECT, RFC 9220 93 settingExtendedConnect = 0x8 94 // HTTP Datagrams, RFC 9297 95 settingDatagram = 0x33 96 ) 97 98 type settingsFrame struct { 99 Datagram bool // HTTP Datagrams, RFC 9297 100 ExtendedConnect bool // Extended CONNECT, RFC 9220 101 102 Other map[uint64]uint64 // all settings that we don't explicitly recognize 103 } 104 105 func parseSettingsFrame(r io.Reader, l uint64) (*settingsFrame, error) { 106 if l > 8*(1<<10) { 107 return nil, fmt.Errorf("unexpected size for SETTINGS frame: %d", l) 108 } 109 buf := make([]byte, l) 110 if _, err := io.ReadFull(r, buf); err != nil { 111 if err == io.ErrUnexpectedEOF { 112 return nil, io.EOF 113 } 114 return nil, err 115 } 116 frame := &settingsFrame{} 117 b := bytes.NewReader(buf) 118 var readDatagram, readExtendedConnect bool 119 for b.Len() > 0 { 120 id, err := quicvarint.Read(b) 121 if err != nil { // should not happen. We allocated the whole frame already. 122 return nil, err 123 } 124 val, err := quicvarint.Read(b) 125 if err != nil { // should not happen. We allocated the whole frame already. 126 return nil, err 127 } 128 129 switch id { 130 case settingExtendedConnect: 131 if readExtendedConnect { 132 return nil, fmt.Errorf("duplicate setting: %d", id) 133 } 134 readExtendedConnect = true 135 if val != 0 && val != 1 { 136 return nil, fmt.Errorf("invalid value for SETTINGS_ENABLE_CONNECT_PROTOCOL: %d", val) 137 } 138 frame.ExtendedConnect = val == 1 139 case settingDatagram: 140 if readDatagram { 141 return nil, fmt.Errorf("duplicate setting: %d", id) 142 } 143 readDatagram = true 144 if val != 0 && val != 1 { 145 return nil, fmt.Errorf("invalid value for SETTINGS_H3_DATAGRAM: %d", val) 146 } 147 frame.Datagram = val == 1 148 default: 149 if _, ok := frame.Other[id]; ok { 150 return nil, fmt.Errorf("duplicate setting: %d", id) 151 } 152 if frame.Other == nil { 153 frame.Other = make(map[uint64]uint64) 154 } 155 frame.Other[id] = val 156 } 157 } 158 return frame, nil 159 } 160 161 func (f *settingsFrame) Append(b []byte) []byte { 162 b = quicvarint.Append(b, 0x4) 163 var l protocol.ByteCount 164 for id, val := range f.Other { 165 l += quicvarint.Len(id) + quicvarint.Len(val) 166 } 167 if f.Datagram { 168 l += quicvarint.Len(settingDatagram) + quicvarint.Len(1) 169 } 170 if f.ExtendedConnect { 171 l += quicvarint.Len(settingExtendedConnect) + quicvarint.Len(1) 172 } 173 b = quicvarint.Append(b, uint64(l)) 174 if f.Datagram { 175 b = quicvarint.Append(b, settingDatagram) 176 b = quicvarint.Append(b, 1) 177 } 178 if f.ExtendedConnect { 179 b = quicvarint.Append(b, settingExtendedConnect) 180 b = quicvarint.Append(b, 1) 181 } 182 for id, val := range f.Other { 183 b = quicvarint.Append(b, id) 184 b = quicvarint.Append(b, val) 185 } 186 return b 187 }