capsule.go 1.8 KB

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