github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/http3/frames.go (about)

     1  package http3
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  
     9  	"github.com/apernet/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  }