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

     1  package http3
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/apernet/quic-go/quicvarint"
     7  )
     8  
     9  // CapsuleType is the type of the capsule.
    10  type CapsuleType uint64
    11  
    12  type exactReader struct {
    13  	R *io.LimitedReader
    14  }
    15  
    16  func (r *exactReader) Read(b []byte) (int, error) {
    17  	n, err := r.R.Read(b)
    18  	if r.R.N > 0 {
    19  		return n, io.ErrUnexpectedEOF
    20  	}
    21  	return n, err
    22  }
    23  
    24  // ParseCapsule parses the header of a Capsule.
    25  // It returns an io.LimitedReader that can be used to read the Capsule value.
    26  // The Capsule value must be read entirely (i.e. until the io.EOF) before using r again.
    27  func ParseCapsule(r quicvarint.Reader) (CapsuleType, io.Reader, error) {
    28  	ct, err := quicvarint.Read(r)
    29  	if err != nil {
    30  		if err == io.EOF {
    31  			return 0, nil, io.ErrUnexpectedEOF
    32  		}
    33  		return 0, nil, err
    34  	}
    35  	l, err := quicvarint.Read(r)
    36  	if err != nil {
    37  		if err == io.EOF {
    38  			return 0, nil, io.ErrUnexpectedEOF
    39  		}
    40  		return 0, nil, err
    41  	}
    42  	return CapsuleType(ct), &exactReader{R: io.LimitReader(r, int64(l)).(*io.LimitedReader)}, nil
    43  }
    44  
    45  // WriteCapsule writes a capsule
    46  func WriteCapsule(w quicvarint.Writer, ct CapsuleType, value []byte) error {
    47  	b := make([]byte, 0, 16)
    48  	b = quicvarint.Append(b, uint64(ct))
    49  	b = quicvarint.Append(b, uint64(len(value)))
    50  	if _, err := w.Write(b); err != nil {
    51  		return err
    52  	}
    53  	_, err := w.Write(value)
    54  	return err
    55  }