forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/golang.org/x/net/http2/h2c/h2c.go

411 lines
7.1 KiB
Go
Raw Normal View History

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