github.com/tumi8/quic-go@v0.37.4-tum/http3/frames.go (about) 1 package http3 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 9 "github.com/tumi8/quic-go/noninternal/protocol" 10 "github.com/tumi8/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 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 settingDatagram = 0xffd277 92 93 type settingsFrame struct { 94 Datagram bool 95 Other map[uint64]uint64 // all settings that we don't explicitly recognize 96 } 97 98 func parseSettingsFrame(r io.Reader, l uint64) (*settingsFrame, error) { 99 if l > 8*(1<<10) { 100 return nil, fmt.Errorf("unexpected size for SETTINGS frame: %d", l) 101 } 102 buf := make([]byte, l) 103 if _, err := io.ReadFull(r, buf); err != nil { 104 if err == io.ErrUnexpectedEOF { 105 return nil, io.EOF 106 } 107 return nil, err 108 } 109 frame := &settingsFrame{} 110 b := bytes.NewReader(buf) 111 var readDatagram bool 112 for b.Len() > 0 { 113 id, err := quicvarint.Read(b) 114 if err != nil { // should not happen. We allocated the whole frame already. 115 return nil, err 116 } 117 val, err := quicvarint.Read(b) 118 if err != nil { // should not happen. We allocated the whole frame already. 119 return nil, err 120 } 121 122 switch id { 123 case settingDatagram: 124 if readDatagram { 125 return nil, fmt.Errorf("duplicate setting: %d", id) 126 } 127 readDatagram = true 128 if val != 0 && val != 1 { 129 return nil, fmt.Errorf("invalid value for H3_DATAGRAM: %d", val) 130 } 131 frame.Datagram = val == 1 132 default: 133 if _, ok := frame.Other[id]; ok { 134 return nil, fmt.Errorf("duplicate setting: %d", id) 135 } 136 if frame.Other == nil { 137 frame.Other = make(map[uint64]uint64) 138 } 139 frame.Other[id] = val 140 } 141 } 142 return frame, nil 143 } 144 145 func (f *settingsFrame) Append(b []byte) []byte { 146 b = quicvarint.Append(b, 0x4) 147 var l protocol.ByteCount 148 for id, val := range f.Other { 149 l += quicvarint.Len(id) + quicvarint.Len(val) 150 } 151 if f.Datagram { 152 l += quicvarint.Len(settingDatagram) + quicvarint.Len(1) 153 } 154 b = quicvarint.Append(b, uint64(l)) 155 if f.Datagram { 156 b = quicvarint.Append(b, settingDatagram) 157 b = quicvarint.Append(b, 1) 158 } 159 for id, val := range f.Other { 160 b = quicvarint.Append(b, id) 161 b = quicvarint.Append(b, val) 162 } 163 return b 164 }