frame.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright 2014 The Go Authors.
  2. // See https://code.google.com/p/go/source/browse/CONTRIBUTORS
  3. // Licensed under the same terms as Go itself:
  4. // https://code.google.com/p/go/source/browse/LICENSE
  5. package http2
  6. import (
  7. "encoding/binary"
  8. "io"
  9. "io/ioutil"
  10. "log"
  11. "sync"
  12. )
  13. const frameHeaderLen = 8
  14. type FrameType uint8
  15. // Defined in http://http2.github.io/http2-spec/#rfc.section.11.2
  16. const (
  17. FrameData FrameType = 0x0
  18. FrameHeaders FrameType = 0x1
  19. FramePriority FrameType = 0x2
  20. FrameRSTStream FrameType = 0x3
  21. FrameSettings FrameType = 0x4
  22. FramePushPromise FrameType = 0x5
  23. FramePing FrameType = 0x6
  24. FrameGoAway FrameType = 0x7
  25. FrameWindowUpdate FrameType = 0x8
  26. FrameContinuation FrameType = 0x9
  27. FlagSettingsAck Flags = 0x1
  28. )
  29. type SettingID uint16
  30. const (
  31. SettingHeaderTableSize SettingID = 0x1
  32. SettingEnablePush SettingID = 0x2
  33. SettingMaxConcurrentStreams SettingID = 0x3
  34. SettingInitialWindowSize SettingID = 0x4
  35. )
  36. func knownSetting(id SettingID) bool {
  37. // TODO: permit registration of custom settings values?
  38. // Per server type?
  39. return id >= 1 && id <= 4
  40. }
  41. type frameParser func(FrameHeader, io.Reader) (Frame, error)
  42. var FrameParsers = map[FrameType]frameParser{
  43. FrameSettings: parseFrameSettings,
  44. }
  45. func typeFrameParser(t FrameType) frameParser {
  46. if f, ok := FrameParsers[t]; ok {
  47. return f
  48. }
  49. return parseUnknownFrame
  50. }
  51. type Flags uint8
  52. func (f Flags) Has(v Flags) bool {
  53. return (f & v) == v
  54. }
  55. // A FrameHeader is the 8 byte header of all HTTP/2 frames.
  56. //
  57. // See http://http2.github.io/http2-spec/#FrameHeader
  58. type FrameHeader struct {
  59. Type FrameType
  60. Flags Flags
  61. Length uint16
  62. StreamID uint32
  63. }
  64. func (h FrameHeader) Header() FrameHeader { return h }
  65. // frame header bytes
  66. var fhBytes = sync.Pool{
  67. New: func() interface{} {
  68. buf := make([]byte, frameHeaderLen)
  69. return &buf
  70. },
  71. }
  72. func ReadFrameHeader(r io.Reader) (FrameHeader, error) {
  73. bufp := fhBytes.Get().(*[]byte)
  74. defer fhBytes.Put(bufp)
  75. buf := *bufp
  76. _, err := io.ReadFull(r, buf)
  77. if err != nil {
  78. return FrameHeader{}, err
  79. }
  80. return FrameHeader{
  81. Length: (uint16(buf[0])<<8 + uint16(buf[1])) & (1<<14 - 1),
  82. Flags: Flags(buf[3]),
  83. Type: FrameType(buf[2]),
  84. StreamID: binary.BigEndian.Uint32(buf[4:]) & (1<<31 - 1),
  85. }, nil
  86. }
  87. type Frame interface {
  88. Header() FrameHeader
  89. }
  90. type SettingsFrame struct {
  91. FrameHeader
  92. Settings map[SettingID]uint32
  93. }
  94. func parseFrameSettings(fh FrameHeader, r io.Reader) (Frame, error) {
  95. if fh.Flags.Has(FlagSettingsAck) && fh.Length > 0 {
  96. // When this (ACK 0x1) bit is set, the payload of the
  97. // SETTINGS frame MUST be empty. Receipt of a
  98. // SETTINGS frame with the ACK flag set and a length
  99. // field value other than 0 MUST be treated as a
  100. // connection error (Section 5.4.1) of type
  101. // FRAME_SIZE_ERROR.
  102. return nil, ConnectionError(ErrCodeFrameSize)
  103. }
  104. if fh.StreamID != 0 {
  105. // SETTINGS frames always apply to a connection,
  106. // never a single stream. The stream identifier for a
  107. // SETTINGS frame MUST be zero (0x0). If an endpoint
  108. // receives a SETTINGS frame whose stream identifier
  109. // field is anything other than 0x0, the endpoint MUST
  110. // respond with a connection error (Section 5.4.1) of
  111. // type PROTOCOL_ERROR.
  112. log.Printf("Bogus StreamID in settings: %+v", fh)
  113. return nil, ConnectionError(ErrCodeProtocol)
  114. }
  115. if fh.Length%6 != 0 {
  116. // Expecting even number of 6 byte settings.
  117. return nil, ConnectionError(ErrCodeFrameSize)
  118. }
  119. s := make(map[SettingID]uint32)
  120. nSettings := int(fh.Length / 6)
  121. var buf [4]byte
  122. for i := 0; i < nSettings; i++ {
  123. if _, err := io.ReadFull(r, buf[:2]); err != nil {
  124. return nil, err
  125. }
  126. settingID := SettingID(binary.BigEndian.Uint16(buf[:2]))
  127. if _, err := io.ReadFull(r, buf[:4]); err != nil {
  128. return nil, err
  129. }
  130. value := binary.BigEndian.Uint32(buf[:4])
  131. if knownSetting(settingID) {
  132. s[settingID] = value
  133. }
  134. }
  135. return &SettingsFrame{
  136. FrameHeader: fh,
  137. Settings: s,
  138. }, nil
  139. }
  140. type UnknownFrame struct {
  141. FrameHeader
  142. }
  143. func parseUnknownFrame(fh FrameHeader, r io.Reader) (Frame, error) {
  144. _, err := io.CopyN(ioutil.Discard, r, int64(fh.Length))
  145. return UnknownFrame{fh}, err
  146. }