diff options
| author | 2022-09-28 18:30:40 +0100 | |
|---|---|---|
| committer | 2022-09-28 18:30:40 +0100 | |
| commit | a156188b3eb5cb3da44aa1b7452265f5fa38a607 (patch) | |
| tree | 7097fa48d56fbabc7c2c8750b1f3bc9321d71c0f /vendor/golang.org/x/net/http2/h2c | |
| parent | [bugfix] Fix emphasis being added to emoji shortcodes with markdown parsing (... (diff) | |
| download | gotosocial-a156188b3eb5cb3da44aa1b7452265f5fa38a607.tar.xz | |
[chore] update dependencies, bump to Go 1.19.1 (#826)
* update dependencies, bump Go version to 1.19
* bump test image Go version
* update golangci-lint
* update gotosocial-drone-build
* sign
* linting, go fmt
* update swagger docs
* update swagger docs
* whitespace
* update contributing.md
* fuckin whoopsie doopsie
* linterino, linteroni
* fix followrequest test not starting processor
* fix other api/client tests not starting processor
* fix remaining tests where processor not started
* bump go-runners version
* don't check last-webfingered-at, processor may have updated this
* update swagger command
* update bun to latest version
* fix embed to work the same as before with new bun
Signed-off-by: kim <grufwub@gmail.com>
Co-authored-by: tsmethurst <tobi.smethurst@protonmail.com>
Diffstat (limited to 'vendor/golang.org/x/net/http2/h2c')
| -rw-r--r-- | vendor/golang.org/x/net/http2/h2c/h2c.go | 225 | 
1 files changed, 225 insertions, 0 deletions
diff --git a/vendor/golang.org/x/net/http2/h2c/h2c.go b/vendor/golang.org/x/net/http2/h2c/h2c.go new file mode 100644 index 000000000..c3df711d9 --- /dev/null +++ b/vendor/golang.org/x/net/http2/h2c/h2c.go @@ -0,0 +1,225 @@ +// 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 a 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, +	} +} + +// 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(), +			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) +			} +			return +		} +		defer conn.Close() +		s.s.ServeConn(conn, &http2.ServeConnOpts{ +			Context:        r.Context(), +			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, _ := io.ReadAll(r.Body) +	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) +}  | 
