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