frameheader.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // Copyright 2019 The gRPC Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package http2interop
  15. import (
  16. "encoding/binary"
  17. "fmt"
  18. "io"
  19. )
  20. type FrameHeader struct {
  21. Length int
  22. Type FrameType
  23. Flags byte
  24. Reserved Reserved
  25. StreamID
  26. }
  27. type Reserved bool
  28. func (r Reserved) String() string {
  29. if r {
  30. return "R"
  31. }
  32. return ""
  33. }
  34. func (fh *FrameHeader) Parse(r io.Reader) error {
  35. buf := make([]byte, 9)
  36. if _, err := io.ReadFull(r, buf); err != nil {
  37. return err
  38. }
  39. return fh.UnmarshalBinary(buf)
  40. }
  41. func (fh *FrameHeader) UnmarshalBinary(b []byte) error {
  42. if len(b) != 9 {
  43. return fmt.Errorf("Invalid frame header length %d", len(b))
  44. }
  45. *fh = FrameHeader{
  46. Length: int(b[0])<<16 | int(b[1])<<8 | int(b[2]),
  47. Type: FrameType(b[3]),
  48. Flags: b[4],
  49. Reserved: Reserved(b[5]>>7 == 1),
  50. StreamID: StreamID(binary.BigEndian.Uint32(b[5:9]) & 0x7fffffff),
  51. }
  52. return nil
  53. }
  54. func (fh *FrameHeader) MarshalBinary() ([]byte, error) {
  55. buf := make([]byte, 9, 9+fh.Length)
  56. if fh.Length > 0xFFFFFF || fh.Length < 0 {
  57. return nil, fmt.Errorf("Invalid frame header length: %d", fh.Length)
  58. }
  59. if fh.StreamID < 0 {
  60. return nil, fmt.Errorf("Invalid Stream ID: %v", fh.StreamID)
  61. }
  62. buf[0], buf[1], buf[2] = byte(fh.Length>>16), byte(fh.Length>>8), byte(fh.Length)
  63. buf[3] = byte(fh.Type)
  64. buf[4] = fh.Flags
  65. var res uint32
  66. if fh.Reserved {
  67. res = 0x80000000
  68. }
  69. binary.BigEndian.PutUint32(buf[5:], uint32(fh.StreamID)|res)
  70. return buf, nil
  71. }
  72. type StreamID int32
  73. type FrameType byte
  74. func (ft FrameType) String() string {
  75. switch ft {
  76. case DataFrameType:
  77. return "DATA"
  78. case HeadersFrameType:
  79. return "HEADERS"
  80. case PriorityFrameType:
  81. return "PRIORITY"
  82. case ResetStreamFrameType:
  83. return "RST_STREAM"
  84. case SettingsFrameType:
  85. return "SETTINGS"
  86. case PushPromiseFrameType:
  87. return "PUSH_PROMISE"
  88. case PingFrameType:
  89. return "PING"
  90. case GoAwayFrameType:
  91. return "GOAWAY"
  92. case WindowUpdateFrameType:
  93. return "WINDOW_UPDATE"
  94. case ContinuationFrameType:
  95. return "CONTINUATION"
  96. case HTTP1FrameType:
  97. return "HTTP/1.? (Bad)"
  98. default:
  99. return fmt.Sprintf("UNKNOWN(%d)", byte(ft))
  100. }
  101. }
  102. // Types
  103. const (
  104. DataFrameType FrameType = 0
  105. HeadersFrameType FrameType = 1
  106. PriorityFrameType FrameType = 2
  107. ResetStreamFrameType FrameType = 3
  108. SettingsFrameType FrameType = 4
  109. PushPromiseFrameType FrameType = 5
  110. PingFrameType FrameType = 6
  111. GoAwayFrameType FrameType = 7
  112. WindowUpdateFrameType FrameType = 8
  113. ContinuationFrameType FrameType = 9
  114. // HTTP1FrameType is not a real type, but rather a convenient way to check if the response
  115. // is an http response. The type of a frame header is the 4th byte, which in an http1
  116. // response will be "HTTP/1.1 200 OK" or something like that. The character for "P" is 80.
  117. HTTP1FrameType FrameType = 80
  118. )