diff options
Diffstat (limited to 'vendor/golang.org/x/net/http2/h2c/h2c.go')
-rw-r--r-- | vendor/golang.org/x/net/http2/h2c/h2c.go | 240 |
1 files changed, 0 insertions, 240 deletions
diff --git a/vendor/golang.org/x/net/http2/h2c/h2c.go b/vendor/golang.org/x/net/http2/h2c/h2c.go deleted file mode 100644 index 2d6bf861b..000000000 --- a/vendor/golang.org/x/net/http2/h2c/h2c.go +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package h2c implements the unencrypted "h2c" form of HTTP/2. -// -// The h2c protocol is the non-TLS version of HTTP/2 which is not available from -// net/http or golang.org/x/net/http2. -package h2c - -import ( - "bufio" - "bytes" - "encoding/base64" - "errors" - "fmt" - "io" - "log" - "net" - "net/http" - "net/textproto" - "os" - "strings" - - "golang.org/x/net/http/httpguts" - "golang.org/x/net/http2" -) - -var ( - http2VerboseLogs bool -) - -func init() { - e := os.Getenv("GODEBUG") - if strings.Contains(e, "http2debug=1") || strings.Contains(e, "http2debug=2") { - http2VerboseLogs = true - } -} - -// h2cHandler is a Handler which implements h2c by hijacking the HTTP/1 traffic -// that should be h2c traffic. There are two ways to begin a h2c connection -// (RFC 7540 Section 3.2 and 3.4): (1) Starting with Prior Knowledge - this -// works by starting an h2c connection with a string of bytes that is valid -// HTTP/1, but unlikely to occur in practice and (2) Upgrading from HTTP/1 to -// h2c - this works by using the HTTP/1 Upgrade header to request an upgrade to -// h2c. When either of those situations occur we hijack the HTTP/1 connection, -// convert it to an HTTP/2 connection and pass the net.Conn to http2.ServeConn. -type h2cHandler struct { - Handler http.Handler - s *http2.Server -} - -// NewHandler returns an http.Handler that wraps h, intercepting any h2c -// traffic. If a request is an h2c connection, it's hijacked and redirected to -// s.ServeConn. Otherwise the returned Handler just forwards requests to h. This -// works because h2c is designed to be parseable as valid HTTP/1, but ignored by -// any HTTP server that does not handle h2c. Therefore we leverage the HTTP/1 -// compatible parts of the Go http library to parse and recognize h2c requests. -// Once a request is recognized as h2c, we hijack the connection and convert it -// to an HTTP/2 connection which is understandable to s.ServeConn. (s.ServeConn -// understands HTTP/2 except for the h2c part of it.) -// -// The first request on an h2c connection is read entirely into memory before -// the Handler is called. To limit the memory consumed by this request, wrap -// the result of NewHandler in an http.MaxBytesHandler. -func NewHandler(h http.Handler, s *http2.Server) http.Handler { - return &h2cHandler{ - Handler: h, - s: s, - } -} - -// extractServer extracts existing http.Server instance from http.Request or create an empty http.Server -func extractServer(r *http.Request) *http.Server { - server, ok := r.Context().Value(http.ServerContextKey).(*http.Server) - if ok { - return server - } - return new(http.Server) -} - -// ServeHTTP implement the h2c support that is enabled by h2c.GetH2CHandler. -func (s h2cHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - // Handle h2c with prior knowledge (RFC 7540 Section 3.4) - if r.Method == "PRI" && len(r.Header) == 0 && r.URL.Path == "*" && r.Proto == "HTTP/2.0" { - if http2VerboseLogs { - log.Print("h2c: attempting h2c with prior knowledge.") - } - conn, err := initH2CWithPriorKnowledge(w) - if err != nil { - if http2VerboseLogs { - log.Printf("h2c: error h2c with prior knowledge: %v", err) - } - return - } - defer conn.Close() - s.s.ServeConn(conn, &http2.ServeConnOpts{ - Context: r.Context(), - BaseConfig: extractServer(r), - Handler: s.Handler, - SawClientPreface: true, - }) - return - } - // Handle Upgrade to h2c (RFC 7540 Section 3.2) - if isH2CUpgrade(r.Header) { - conn, settings, err := h2cUpgrade(w, r) - if err != nil { - if http2VerboseLogs { - log.Printf("h2c: error h2c upgrade: %v", err) - } - w.WriteHeader(http.StatusInternalServerError) - return - } - defer conn.Close() - s.s.ServeConn(conn, &http2.ServeConnOpts{ - Context: r.Context(), - BaseConfig: extractServer(r), - Handler: s.Handler, - UpgradeRequest: r, - Settings: settings, - }) - return - } - s.Handler.ServeHTTP(w, r) - return -} - -// initH2CWithPriorKnowledge implements creating a h2c connection with prior -// knowledge (Section 3.4) and creates a net.Conn suitable for http2.ServeConn. -// All we have to do is look for the client preface that is suppose to be part -// of the body, and reforward the client preface on the net.Conn this function -// creates. -func initH2CWithPriorKnowledge(w http.ResponseWriter) (net.Conn, error) { - hijacker, ok := w.(http.Hijacker) - if !ok { - return nil, errors.New("h2c: connection does not support Hijack") - } - conn, rw, err := hijacker.Hijack() - if err != nil { - return nil, err - } - - const expectedBody = "SM\r\n\r\n" - - buf := make([]byte, len(expectedBody)) - n, err := io.ReadFull(rw, buf) - if err != nil { - return nil, fmt.Errorf("h2c: error reading client preface: %s", err) - } - - if string(buf[:n]) == expectedBody { - return newBufConn(conn, rw), nil - } - - conn.Close() - return nil, errors.New("h2c: invalid client preface") -} - -// h2cUpgrade establishes a h2c connection using the HTTP/1 upgrade (Section 3.2). -func h2cUpgrade(w http.ResponseWriter, r *http.Request) (_ net.Conn, settings []byte, err error) { - settings, err = getH2Settings(r.Header) - if err != nil { - return nil, nil, err - } - hijacker, ok := w.(http.Hijacker) - if !ok { - return nil, nil, errors.New("h2c: connection does not support Hijack") - } - - body, err := io.ReadAll(r.Body) - if err != nil { - return nil, nil, err - } - r.Body = io.NopCloser(bytes.NewBuffer(body)) - - conn, rw, err := hijacker.Hijack() - if err != nil { - return nil, nil, err - } - - rw.Write([]byte("HTTP/1.1 101 Switching Protocols\r\n" + - "Connection: Upgrade\r\n" + - "Upgrade: h2c\r\n\r\n")) - return newBufConn(conn, rw), settings, nil -} - -// isH2CUpgrade returns true if the header properly request an upgrade to h2c -// as specified by Section 3.2. -func isH2CUpgrade(h http.Header) bool { - return httpguts.HeaderValuesContainsToken(h[textproto.CanonicalMIMEHeaderKey("Upgrade")], "h2c") && - httpguts.HeaderValuesContainsToken(h[textproto.CanonicalMIMEHeaderKey("Connection")], "HTTP2-Settings") -} - -// getH2Settings returns the settings in the HTTP2-Settings header. -func getH2Settings(h http.Header) ([]byte, error) { - vals, ok := h[textproto.CanonicalMIMEHeaderKey("HTTP2-Settings")] - if !ok { - return nil, errors.New("missing HTTP2-Settings header") - } - if len(vals) != 1 { - return nil, fmt.Errorf("expected 1 HTTP2-Settings. Got: %v", vals) - } - settings, err := base64.RawURLEncoding.DecodeString(vals[0]) - if err != nil { - return nil, err - } - return settings, nil -} - -func newBufConn(conn net.Conn, rw *bufio.ReadWriter) net.Conn { - rw.Flush() - if rw.Reader.Buffered() == 0 { - // If there's no buffered data to be read, - // we can just discard the bufio.ReadWriter. - return conn - } - return &bufConn{conn, rw.Reader} -} - -// bufConn wraps a net.Conn, but reads drain the bufio.Reader first. -type bufConn struct { - net.Conn - *bufio.Reader -} - -func (c *bufConn) Read(p []byte) (int, error) { - if c.Reader == nil { - return c.Conn.Read(p) - } - n := c.Reader.Buffered() - if n == 0 { - c.Reader = nil - return c.Conn.Read(p) - } - if n < len(p) { - p = p[:n] - } - return c.Reader.Read(p) -} |