github.com/ooni/psiphon/tunnel-core@v0.0.0-20230105123940-fe12a24c96ee/oovendor/quic-go/http3/frames.go (about)

     1  package http3
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  
     9  	"github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/internal/protocol"
    10  	"github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/quicvarint"
    11  )
    12  
    13  type frame interface{}
    14  
    15  func parseNextFrame(r io.Reader) (frame, error) {
    16  	qr := quicvarint.NewReader(r)
    17  	for {
    18  		t, err := quicvarint.Read(qr)
    19  		if err != nil {
    20  			return nil, err
    21  		}
    22  		l, err := quicvarint.Read(qr)
    23  		if err != nil {
    24  			return nil, err
    25  		}
    26  
    27  		switch t {
    28  		case 0x0:
    29  			return &dataFrame{Length: l}, nil
    30  		case 0x1:
    31  			return &headersFrame{Length: l}, nil
    32  		case 0x4:
    33  			return parseSettingsFrame(r, l)
    34  		case 0x3: // CANCEL_PUSH
    35  			fallthrough
    36  		case 0x5: // PUSH_PROMISE
    37  			fallthrough
    38  		case 0x7: // GOAWAY
    39  			fallthrough
    40  		case 0xd: // MAX_PUSH_ID
    41  			fallthrough
    42  		case 0xe: // DUPLICATE_PUSH
    43  			fallthrough
    44  		default:
    45  			// skip over unknown frames
    46  			if _, err := io.CopyN(ioutil.Discard, qr, int64(l)); err != nil {
    47  				return nil, err
    48  			}
    49  		}
    50  	}
    51  }
    52  
    53  type dataFrame struct {
    54  	Length uint64
    55  }
    56  
    57  func (f *dataFrame) Write(b *bytes.Buffer) {
    58  	quicvarint.Write(b, 0x0)
    59  	quicvarint.Write(b, f.Length)
    60  }
    61  
    62  type headersFrame struct {
    63  	Length uint64
    64  }
    65  
    66  func (f *headersFrame) Write(b *bytes.Buffer) {
    67  	quicvarint.Write(b, 0x1)
    68  	quicvarint.Write(b, f.Length)
    69  }
    70  
    71  const settingDatagram = 0x276
    72  
    73  type settingsFrame struct {
    74  	Datagram bool
    75  	other    map[uint64]uint64 // all settings that we don't explicitly recognize
    76  }
    77  
    78  func parseSettingsFrame(r io.Reader, l uint64) (*settingsFrame, error) {
    79  	if l > 8*(1<<10) {
    80  		return nil, fmt.Errorf("unexpected size for SETTINGS frame: %d", l)
    81  	}
    82  	buf := make([]byte, l)
    83  	if _, err := io.ReadFull(r, buf); err != nil {
    84  		if err == io.ErrUnexpectedEOF {
    85  			return nil, io.EOF
    86  		}
    87  		return nil, err
    88  	}
    89  	frame := &settingsFrame{}
    90  	b := bytes.NewReader(buf)
    91  	var readDatagram bool
    92  	for b.Len() > 0 {
    93  		id, err := quicvarint.Read(b)
    94  		if err != nil { // should not happen. We allocated the whole frame already.
    95  			return nil, err
    96  		}
    97  		val, err := quicvarint.Read(b)
    98  		if err != nil { // should not happen. We allocated the whole frame already.
    99  			return nil, err
   100  		}
   101  
   102  		switch id {
   103  		case settingDatagram:
   104  			if readDatagram {
   105  				return nil, fmt.Errorf("duplicate setting: %d", id)
   106  			}
   107  			readDatagram = true
   108  			if val != 0 && val != 1 {
   109  				return nil, fmt.Errorf("invalid value for H3_DATAGRAM: %d", val)
   110  			}
   111  			frame.Datagram = val == 1
   112  		default:
   113  			if _, ok := frame.other[id]; ok {
   114  				return nil, fmt.Errorf("duplicate setting: %d", id)
   115  			}
   116  			if frame.other == nil {
   117  				frame.other = make(map[uint64]uint64)
   118  			}
   119  			frame.other[id] = val
   120  		}
   121  	}
   122  	return frame, nil
   123  }
   124  
   125  func (f *settingsFrame) Write(b *bytes.Buffer) {
   126  	quicvarint.Write(b, 0x4)
   127  	var l protocol.ByteCount
   128  	for id, val := range f.other {
   129  		l += quicvarint.Len(id) + quicvarint.Len(val)
   130  	}
   131  	if f.Datagram {
   132  		l += quicvarint.Len(settingDatagram) + quicvarint.Len(1)
   133  	}
   134  	quicvarint.Write(b, uint64(l))
   135  	if f.Datagram {
   136  		quicvarint.Write(b, settingDatagram)
   137  		quicvarint.Write(b, 1)
   138  	}
   139  	for id, val := range f.other {
   140  		quicvarint.Write(b, id)
   141  		quicvarint.Write(b, val)
   142  	}
   143  }