h2c.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package h2c implements the unencrypted "h2c" form of HTTP/2.
  5. //
  6. // The h2c protocol is the non-TLS version of HTTP/2 which is not available from
  7. // net/http or golang.org/x/net/http2.
  8. package h2c
  9. import (
  10. "bufio"
  11. "bytes"
  12. "encoding/base64"
  13. "errors"
  14. "fmt"
  15. "io"
  16. "log"
  17. "net"
  18. "net/http"
  19. "net/textproto"
  20. "os"
  21. "strings"
  22. "golang.org/x/net/http/httpguts"
  23. "golang.org/x/net/http2"
  24. )
  25. var (
  26. http2VerboseLogs bool
  27. )
  28. func init() {
  29. e := os.Getenv("GODEBUG")
  30. if strings.Contains(e, "http2debug=1") || strings.Contains(e, "http2debug=2") {
  31. http2VerboseLogs = true
  32. }
  33. }
  34. // h2cHandler is a Handler which implements h2c by hijacking the HTTP/1 traffic
  35. // that should be h2c traffic. There are two ways to begin a h2c connection
  36. // (RFC 7540 Section 3.2 and 3.4): (1) Starting with Prior Knowledge - this
  37. // works by starting an h2c connection with a string of bytes that is valid
  38. // HTTP/1, but unlikely to occur in practice and (2) Upgrading from HTTP/1 to
  39. // h2c - this works by using the HTTP/1 Upgrade header to request an upgrade to
  40. // h2c. When either of those situations occur we hijack the HTTP/1 connection,
  41. // convert it to a HTTP/2 connection and pass the net.Conn to http2.ServeConn.
  42. type h2cHandler struct {
  43. Handler http.Handler
  44. s *http2.Server
  45. }
  46. // NewHandler returns an http.Handler that wraps h, intercepting any h2c
  47. // traffic. If a request is an h2c connection, it's hijacked and redirected to
  48. // s.ServeConn. Otherwise the returned Handler just forwards requests to h. This
  49. // works because h2c is designed to be parseable as valid HTTP/1, but ignored by
  50. // any HTTP server that does not handle h2c. Therefore we leverage the HTTP/1
  51. // compatible parts of the Go http library to parse and recognize h2c requests.
  52. // Once a request is recognized as h2c, we hijack the connection and convert it
  53. // to an HTTP/2 connection which is understandable to s.ServeConn. (s.ServeConn
  54. // understands HTTP/2 except for the h2c part of it.)
  55. //
  56. // The first request on an h2c connection is read entirely into memory before
  57. // the Handler is called. To limit the memory consumed by this request, wrap
  58. // the result of NewHandler in an http.MaxBytesHandler.
  59. func NewHandler(h http.Handler, s *http2.Server) http.Handler {
  60. return &h2cHandler{
  61. Handler: h,
  62. s: s,
  63. }
  64. }
  65. // ServeHTTP implement the h2c support that is enabled by h2c.GetH2CHandler.
  66. func (s h2cHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  67. // Handle h2c with prior knowledge (RFC 7540 Section 3.4)
  68. if r.Method == "PRI" && len(r.Header) == 0 && r.URL.Path == "*" && r.Proto == "HTTP/2.0" {
  69. if http2VerboseLogs {
  70. log.Print("h2c: attempting h2c with prior knowledge.")
  71. }
  72. conn, err := initH2CWithPriorKnowledge(w)
  73. if err != nil {
  74. if http2VerboseLogs {
  75. log.Printf("h2c: error h2c with prior knowledge: %v", err)
  76. }
  77. return
  78. }
  79. defer conn.Close()
  80. s.s.ServeConn(conn, &http2.ServeConnOpts{
  81. Context: r.Context(),
  82. Handler: s.Handler,
  83. SawClientPreface: true,
  84. })
  85. return
  86. }
  87. // Handle Upgrade to h2c (RFC 7540 Section 3.2)
  88. if isH2CUpgrade(r.Header) {
  89. conn, settings, err := h2cUpgrade(w, r)
  90. if err != nil {
  91. if http2VerboseLogs {
  92. log.Printf("h2c: error h2c upgrade: %v", err)
  93. }
  94. return
  95. }
  96. defer conn.Close()
  97. s.s.ServeConn(conn, &http2.ServeConnOpts{
  98. Context: r.Context(),
  99. Handler: s.Handler,
  100. UpgradeRequest: r,
  101. Settings: settings,
  102. })
  103. return
  104. }
  105. s.Handler.ServeHTTP(w, r)
  106. return
  107. }
  108. // initH2CWithPriorKnowledge implements creating a h2c connection with prior
  109. // knowledge (Section 3.4) and creates a net.Conn suitable for http2.ServeConn.
  110. // All we have to do is look for the client preface that is suppose to be part
  111. // of the body, and reforward the client preface on the net.Conn this function
  112. // creates.
  113. func initH2CWithPriorKnowledge(w http.ResponseWriter) (net.Conn, error) {
  114. hijacker, ok := w.(http.Hijacker)
  115. if !ok {
  116. return nil, errors.New("h2c: connection does not support Hijack")
  117. }
  118. conn, rw, err := hijacker.Hijack()
  119. if err != nil {
  120. return nil, err
  121. }
  122. const expectedBody = "SM\r\n\r\n"
  123. buf := make([]byte, len(expectedBody))
  124. n, err := io.ReadFull(rw, buf)
  125. if err != nil {
  126. return nil, fmt.Errorf("h2c: error reading client preface: %s", err)
  127. }
  128. if string(buf[:n]) == expectedBody {
  129. return newBufConn(conn, rw), nil
  130. }
  131. conn.Close()
  132. return nil, errors.New("h2c: invalid client preface")
  133. }
  134. // h2cUpgrade establishes a h2c connection using the HTTP/1 upgrade (Section 3.2).
  135. func h2cUpgrade(w http.ResponseWriter, r *http.Request) (_ net.Conn, settings []byte, err error) {
  136. settings, err = getH2Settings(r.Header)
  137. if err != nil {
  138. return nil, nil, err
  139. }
  140. hijacker, ok := w.(http.Hijacker)
  141. if !ok {
  142. return nil, nil, errors.New("h2c: connection does not support Hijack")
  143. }
  144. body, _ := io.ReadAll(r.Body)
  145. r.Body = io.NopCloser(bytes.NewBuffer(body))
  146. conn, rw, err := hijacker.Hijack()
  147. if err != nil {
  148. return nil, nil, err
  149. }
  150. rw.Write([]byte("HTTP/1.1 101 Switching Protocols\r\n" +
  151. "Connection: Upgrade\r\n" +
  152. "Upgrade: h2c\r\n\r\n"))
  153. return newBufConn(conn, rw), settings, nil
  154. }
  155. // isH2CUpgrade returns true if the header properly request an upgrade to h2c
  156. // as specified by Section 3.2.
  157. func isH2CUpgrade(h http.Header) bool {
  158. return httpguts.HeaderValuesContainsToken(h[textproto.CanonicalMIMEHeaderKey("Upgrade")], "h2c") &&
  159. httpguts.HeaderValuesContainsToken(h[textproto.CanonicalMIMEHeaderKey("Connection")], "HTTP2-Settings")
  160. }
  161. // getH2Settings returns the settings in the HTTP2-Settings header.
  162. func getH2Settings(h http.Header) ([]byte, error) {
  163. vals, ok := h[textproto.CanonicalMIMEHeaderKey("HTTP2-Settings")]
  164. if !ok {
  165. return nil, errors.New("missing HTTP2-Settings header")
  166. }
  167. if len(vals) != 1 {
  168. return nil, fmt.Errorf("expected 1 HTTP2-Settings. Got: %v", vals)
  169. }
  170. settings, err := base64.RawURLEncoding.DecodeString(vals[0])
  171. if err != nil {
  172. return nil, err
  173. }
  174. return settings, nil
  175. }
  176. func newBufConn(conn net.Conn, rw *bufio.ReadWriter) net.Conn {
  177. rw.Flush()
  178. if rw.Reader.Buffered() == 0 {
  179. // If there's no buffered data to be read,
  180. // we can just discard the bufio.ReadWriter.
  181. return conn
  182. }
  183. return &bufConn{conn, rw.Reader}
  184. }
  185. // bufConn wraps a net.Conn, but reads drain the bufio.Reader first.
  186. type bufConn struct {
  187. net.Conn
  188. *bufio.Reader
  189. }
  190. func (c *bufConn) Read(p []byte) (int, error) {
  191. if c.Reader == nil {
  192. return c.Conn.Read(p)
  193. }
  194. n := c.Reader.Buffered()
  195. if n == 0 {
  196. c.Reader = nil
  197. return c.Conn.Read(p)
  198. }
  199. if n < len(p) {
  200. p = p[:n]
  201. }
  202. return c.Reader.Read(p)
  203. }