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