frames.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package http3
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "github.com/Psiphon-Labs/quic-go"
  8. "github.com/Psiphon-Labs/quic-go/quicvarint"
  9. )
  10. // FrameType is the frame type of a HTTP/3 frame
  11. type FrameType uint64
  12. type unknownFrameHandlerFunc func(FrameType, error) (processed bool, err error)
  13. type frame interface{}
  14. var errHijacked = errors.New("hijacked")
  15. type frameParser struct {
  16. r io.Reader
  17. conn quic.Connection
  18. unknownFrameHandler unknownFrameHandlerFunc
  19. }
  20. func (p *frameParser) ParseNext() (frame, error) {
  21. qr := quicvarint.NewReader(p.r)
  22. for {
  23. t, err := quicvarint.Read(qr)
  24. if err != nil {
  25. if p.unknownFrameHandler != nil {
  26. hijacked, err := p.unknownFrameHandler(0, err)
  27. if err != nil {
  28. return nil, err
  29. }
  30. if hijacked {
  31. return nil, errHijacked
  32. }
  33. }
  34. return nil, err
  35. }
  36. // Call the unknownFrameHandler for frames not defined in the HTTP/3 spec
  37. if t > 0xd && p.unknownFrameHandler != nil {
  38. hijacked, err := p.unknownFrameHandler(FrameType(t), nil)
  39. if err != nil {
  40. return nil, err
  41. }
  42. if hijacked {
  43. return nil, errHijacked
  44. }
  45. // If the unknownFrameHandler didn't process the frame, it is our responsibility to skip it.
  46. }
  47. l, err := quicvarint.Read(qr)
  48. if err != nil {
  49. return nil, err
  50. }
  51. switch t {
  52. case 0x0:
  53. return &dataFrame{Length: l}, nil
  54. case 0x1:
  55. return &headersFrame{Length: l}, nil
  56. case 0x4:
  57. return parseSettingsFrame(p.r, l)
  58. case 0x3: // CANCEL_PUSH
  59. case 0x5: // PUSH_PROMISE
  60. case 0x7:
  61. return parseGoAwayFrame(qr, l)
  62. case 0xd: // MAX_PUSH_ID
  63. case 0x2, 0x6, 0x8, 0x9:
  64. p.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "")
  65. return nil, fmt.Errorf("http3: reserved frame type: %d", t)
  66. }
  67. // skip over unknown frames
  68. if _, err := io.CopyN(io.Discard, qr, int64(l)); err != nil {
  69. return nil, err
  70. }
  71. }
  72. }
  73. type dataFrame struct {
  74. Length uint64
  75. }
  76. func (f *dataFrame) Append(b []byte) []byte {
  77. b = quicvarint.Append(b, 0x0)
  78. return quicvarint.Append(b, f.Length)
  79. }
  80. type headersFrame struct {
  81. Length uint64
  82. }
  83. func (f *headersFrame) Append(b []byte) []byte {
  84. b = quicvarint.Append(b, 0x1)
  85. return quicvarint.Append(b, f.Length)
  86. }
  87. const (
  88. // Extended CONNECT, RFC 9220
  89. settingExtendedConnect = 0x8
  90. // HTTP Datagrams, RFC 9297
  91. settingDatagram = 0x33
  92. )
  93. type settingsFrame struct {
  94. Datagram bool // HTTP Datagrams, RFC 9297
  95. ExtendedConnect bool // Extended CONNECT, RFC 9220
  96. Other map[uint64]uint64 // all settings that we don't explicitly recognize
  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, readExtendedConnect 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. switch id {
  122. case settingExtendedConnect:
  123. if readExtendedConnect {
  124. return nil, fmt.Errorf("duplicate setting: %d", id)
  125. }
  126. readExtendedConnect = true
  127. if val != 0 && val != 1 {
  128. return nil, fmt.Errorf("invalid value for SETTINGS_ENABLE_CONNECT_PROTOCOL: %d", val)
  129. }
  130. frame.ExtendedConnect = val == 1
  131. case settingDatagram:
  132. if readDatagram {
  133. return nil, fmt.Errorf("duplicate setting: %d", id)
  134. }
  135. readDatagram = true
  136. if val != 0 && val != 1 {
  137. return nil, fmt.Errorf("invalid value for SETTINGS_H3_DATAGRAM: %d", val)
  138. }
  139. frame.Datagram = val == 1
  140. default:
  141. if _, ok := frame.Other[id]; ok {
  142. return nil, fmt.Errorf("duplicate setting: %d", id)
  143. }
  144. if frame.Other == nil {
  145. frame.Other = make(map[uint64]uint64)
  146. }
  147. frame.Other[id] = val
  148. }
  149. }
  150. return frame, nil
  151. }
  152. func (f *settingsFrame) Append(b []byte) []byte {
  153. b = quicvarint.Append(b, 0x4)
  154. var l int
  155. for id, val := range f.Other {
  156. l += quicvarint.Len(id) + quicvarint.Len(val)
  157. }
  158. if f.Datagram {
  159. l += quicvarint.Len(settingDatagram) + quicvarint.Len(1)
  160. }
  161. if f.ExtendedConnect {
  162. l += quicvarint.Len(settingExtendedConnect) + quicvarint.Len(1)
  163. }
  164. b = quicvarint.Append(b, uint64(l))
  165. if f.Datagram {
  166. b = quicvarint.Append(b, settingDatagram)
  167. b = quicvarint.Append(b, 1)
  168. }
  169. if f.ExtendedConnect {
  170. b = quicvarint.Append(b, settingExtendedConnect)
  171. b = quicvarint.Append(b, 1)
  172. }
  173. for id, val := range f.Other {
  174. b = quicvarint.Append(b, id)
  175. b = quicvarint.Append(b, val)
  176. }
  177. return b
  178. }
  179. type goAwayFrame struct {
  180. StreamID quic.StreamID
  181. }
  182. func parseGoAwayFrame(r io.ByteReader, l uint64) (*goAwayFrame, error) {
  183. frame := &goAwayFrame{}
  184. cbr := countingByteReader{ByteReader: r}
  185. id, err := quicvarint.Read(&cbr)
  186. if err != nil {
  187. return nil, err
  188. }
  189. if cbr.Read != int(l) {
  190. return nil, errors.New("GOAWAY frame: inconsistent length")
  191. }
  192. frame.StreamID = quic.StreamID(id)
  193. return frame, nil
  194. }
  195. func (f *goAwayFrame) Append(b []byte) []byte {
  196. b = quicvarint.Append(b, 0x7)
  197. b = quicvarint.Append(b, uint64(quicvarint.Len(uint64(f.StreamID))))
  198. return quicvarint.Append(b, uint64(f.StreamID))
  199. }