mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 05:12:25 -05:00 
			
		
		
		
	* 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>
		
			
				
	
	
		
			385 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			385 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2014 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 http2 implements the HTTP/2 protocol.
 | |
| //
 | |
| // This package is low-level and intended to be used directly by very
 | |
| // few people. Most users will use it indirectly through the automatic
 | |
| // use by the net/http package (from Go 1.6 and later).
 | |
| // For use in earlier Go versions see ConfigureServer. (Transport support
 | |
| // requires Go 1.6 or later)
 | |
| //
 | |
| // See https://http2.github.io/ for more information on HTTP/2.
 | |
| //
 | |
| // See https://http2.golang.org/ for a test server running this code.
 | |
| package http2 // import "golang.org/x/net/http2"
 | |
| 
 | |
| import (
 | |
| 	"bufio"
 | |
| 	"crypto/tls"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"net/http"
 | |
| 	"os"
 | |
| 	"sort"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"sync"
 | |
| 
 | |
| 	"golang.org/x/net/http/httpguts"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	VerboseLogs    bool
 | |
| 	logFrameWrites bool
 | |
| 	logFrameReads  bool
 | |
| 	inTests        bool
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	e := os.Getenv("GODEBUG")
 | |
| 	if strings.Contains(e, "http2debug=1") {
 | |
| 		VerboseLogs = true
 | |
| 	}
 | |
| 	if strings.Contains(e, "http2debug=2") {
 | |
| 		VerboseLogs = true
 | |
| 		logFrameWrites = true
 | |
| 		logFrameReads = true
 | |
| 	}
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	// ClientPreface is the string that must be sent by new
 | |
| 	// connections from clients.
 | |
| 	ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
 | |
| 
 | |
| 	// SETTINGS_MAX_FRAME_SIZE default
 | |
| 	// https://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2
 | |
| 	initialMaxFrameSize = 16384
 | |
| 
 | |
| 	// NextProtoTLS is the NPN/ALPN protocol negotiated during
 | |
| 	// HTTP/2's TLS setup.
 | |
| 	NextProtoTLS = "h2"
 | |
| 
 | |
| 	// https://httpwg.org/specs/rfc7540.html#SettingValues
 | |
| 	initialHeaderTableSize = 4096
 | |
| 
 | |
| 	initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
 | |
| 
 | |
| 	defaultMaxReadFrameSize = 1 << 20
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	clientPreface = []byte(ClientPreface)
 | |
| )
 | |
| 
 | |
| type streamState int
 | |
| 
 | |
| // HTTP/2 stream states.
 | |
| //
 | |
| // See http://tools.ietf.org/html/rfc7540#section-5.1.
 | |
| //
 | |
| // For simplicity, the server code merges "reserved (local)" into
 | |
| // "half-closed (remote)". This is one less state transition to track.
 | |
| // The only downside is that we send PUSH_PROMISEs slightly less
 | |
| // liberally than allowable. More discussion here:
 | |
| // https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html
 | |
| //
 | |
| // "reserved (remote)" is omitted since the client code does not
 | |
| // support server push.
 | |
| const (
 | |
| 	stateIdle streamState = iota
 | |
| 	stateOpen
 | |
| 	stateHalfClosedLocal
 | |
| 	stateHalfClosedRemote
 | |
| 	stateClosed
 | |
| )
 | |
| 
 | |
| var stateName = [...]string{
 | |
| 	stateIdle:             "Idle",
 | |
| 	stateOpen:             "Open",
 | |
| 	stateHalfClosedLocal:  "HalfClosedLocal",
 | |
| 	stateHalfClosedRemote: "HalfClosedRemote",
 | |
| 	stateClosed:           "Closed",
 | |
| }
 | |
| 
 | |
| func (st streamState) String() string {
 | |
| 	return stateName[st]
 | |
| }
 | |
| 
 | |
| // Setting is a setting parameter: which setting it is, and its value.
 | |
| type Setting struct {
 | |
| 	// ID is which setting is being set.
 | |
| 	// See https://httpwg.org/specs/rfc7540.html#SettingFormat
 | |
| 	ID SettingID
 | |
| 
 | |
| 	// Val is the value.
 | |
| 	Val uint32
 | |
| }
 | |
| 
 | |
| func (s Setting) String() string {
 | |
| 	return fmt.Sprintf("[%v = %d]", s.ID, s.Val)
 | |
| }
 | |
| 
 | |
| // Valid reports whether the setting is valid.
 | |
| func (s Setting) Valid() error {
 | |
| 	// Limits and error codes from 6.5.2 Defined SETTINGS Parameters
 | |
| 	switch s.ID {
 | |
| 	case SettingEnablePush:
 | |
| 		if s.Val != 1 && s.Val != 0 {
 | |
| 			return ConnectionError(ErrCodeProtocol)
 | |
| 		}
 | |
| 	case SettingInitialWindowSize:
 | |
| 		if s.Val > 1<<31-1 {
 | |
| 			return ConnectionError(ErrCodeFlowControl)
 | |
| 		}
 | |
| 	case SettingMaxFrameSize:
 | |
| 		if s.Val < 16384 || s.Val > 1<<24-1 {
 | |
| 			return ConnectionError(ErrCodeProtocol)
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // A SettingID is an HTTP/2 setting as defined in
 | |
| // https://httpwg.org/specs/rfc7540.html#iana-settings
 | |
| type SettingID uint16
 | |
| 
 | |
| const (
 | |
| 	SettingHeaderTableSize      SettingID = 0x1
 | |
| 	SettingEnablePush           SettingID = 0x2
 | |
| 	SettingMaxConcurrentStreams SettingID = 0x3
 | |
| 	SettingInitialWindowSize    SettingID = 0x4
 | |
| 	SettingMaxFrameSize         SettingID = 0x5
 | |
| 	SettingMaxHeaderListSize    SettingID = 0x6
 | |
| )
 | |
| 
 | |
| var settingName = map[SettingID]string{
 | |
| 	SettingHeaderTableSize:      "HEADER_TABLE_SIZE",
 | |
| 	SettingEnablePush:           "ENABLE_PUSH",
 | |
| 	SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
 | |
| 	SettingInitialWindowSize:    "INITIAL_WINDOW_SIZE",
 | |
| 	SettingMaxFrameSize:         "MAX_FRAME_SIZE",
 | |
| 	SettingMaxHeaderListSize:    "MAX_HEADER_LIST_SIZE",
 | |
| }
 | |
| 
 | |
| func (s SettingID) String() string {
 | |
| 	if v, ok := settingName[s]; ok {
 | |
| 		return v
 | |
| 	}
 | |
| 	return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s))
 | |
| }
 | |
| 
 | |
| // validWireHeaderFieldName reports whether v is a valid header field
 | |
| // name (key). See httpguts.ValidHeaderName for the base rules.
 | |
| //
 | |
| // Further, http2 says:
 | |
| //
 | |
| //	"Just as in HTTP/1.x, header field names are strings of ASCII
 | |
| //	characters that are compared in a case-insensitive
 | |
| //	fashion. However, header field names MUST be converted to
 | |
| //	lowercase prior to their encoding in HTTP/2. "
 | |
| func validWireHeaderFieldName(v string) bool {
 | |
| 	if len(v) == 0 {
 | |
| 		return false
 | |
| 	}
 | |
| 	for _, r := range v {
 | |
| 		if !httpguts.IsTokenRune(r) {
 | |
| 			return false
 | |
| 		}
 | |
| 		if 'A' <= r && r <= 'Z' {
 | |
| 			return false
 | |
| 		}
 | |
| 	}
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| func httpCodeString(code int) string {
 | |
| 	switch code {
 | |
| 	case 200:
 | |
| 		return "200"
 | |
| 	case 404:
 | |
| 		return "404"
 | |
| 	}
 | |
| 	return strconv.Itoa(code)
 | |
| }
 | |
| 
 | |
| // from pkg io
 | |
| type stringWriter interface {
 | |
| 	WriteString(s string) (n int, err error)
 | |
| }
 | |
| 
 | |
| // A gate lets two goroutines coordinate their activities.
 | |
| type gate chan struct{}
 | |
| 
 | |
| func (g gate) Done() { g <- struct{}{} }
 | |
| func (g gate) Wait() { <-g }
 | |
| 
 | |
| // A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed).
 | |
| type closeWaiter chan struct{}
 | |
| 
 | |
| // Init makes a closeWaiter usable.
 | |
| // It exists because so a closeWaiter value can be placed inside a
 | |
| // larger struct and have the Mutex and Cond's memory in the same
 | |
| // allocation.
 | |
| func (cw *closeWaiter) Init() {
 | |
| 	*cw = make(chan struct{})
 | |
| }
 | |
| 
 | |
| // Close marks the closeWaiter as closed and unblocks any waiters.
 | |
| func (cw closeWaiter) Close() {
 | |
| 	close(cw)
 | |
| }
 | |
| 
 | |
| // Wait waits for the closeWaiter to become closed.
 | |
| func (cw closeWaiter) Wait() {
 | |
| 	<-cw
 | |
| }
 | |
| 
 | |
| // bufferedWriter is a buffered writer that writes to w.
 | |
| // Its buffered writer is lazily allocated as needed, to minimize
 | |
| // idle memory usage with many connections.
 | |
| type bufferedWriter struct {
 | |
| 	_  incomparable
 | |
| 	w  io.Writer     // immutable
 | |
| 	bw *bufio.Writer // non-nil when data is buffered
 | |
| }
 | |
| 
 | |
| func newBufferedWriter(w io.Writer) *bufferedWriter {
 | |
| 	return &bufferedWriter{w: w}
 | |
| }
 | |
| 
 | |
| // bufWriterPoolBufferSize is the size of bufio.Writer's
 | |
| // buffers created using bufWriterPool.
 | |
| //
 | |
| // TODO: pick a less arbitrary value? this is a bit under
 | |
| // (3 x typical 1500 byte MTU) at least. Other than that,
 | |
| // not much thought went into it.
 | |
| const bufWriterPoolBufferSize = 4 << 10
 | |
| 
 | |
| var bufWriterPool = sync.Pool{
 | |
| 	New: func() interface{} {
 | |
| 		return bufio.NewWriterSize(nil, bufWriterPoolBufferSize)
 | |
| 	},
 | |
| }
 | |
| 
 | |
| func (w *bufferedWriter) Available() int {
 | |
| 	if w.bw == nil {
 | |
| 		return bufWriterPoolBufferSize
 | |
| 	}
 | |
| 	return w.bw.Available()
 | |
| }
 | |
| 
 | |
| func (w *bufferedWriter) Write(p []byte) (n int, err error) {
 | |
| 	if w.bw == nil {
 | |
| 		bw := bufWriterPool.Get().(*bufio.Writer)
 | |
| 		bw.Reset(w.w)
 | |
| 		w.bw = bw
 | |
| 	}
 | |
| 	return w.bw.Write(p)
 | |
| }
 | |
| 
 | |
| func (w *bufferedWriter) Flush() error {
 | |
| 	bw := w.bw
 | |
| 	if bw == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	err := bw.Flush()
 | |
| 	bw.Reset(nil)
 | |
| 	bufWriterPool.Put(bw)
 | |
| 	w.bw = nil
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| func mustUint31(v int32) uint32 {
 | |
| 	if v < 0 || v > 2147483647 {
 | |
| 		panic("out of range")
 | |
| 	}
 | |
| 	return uint32(v)
 | |
| }
 | |
| 
 | |
| // bodyAllowedForStatus reports whether a given response status code
 | |
| // permits a body. See RFC 7230, section 3.3.
 | |
| func bodyAllowedForStatus(status int) bool {
 | |
| 	switch {
 | |
| 	case status >= 100 && status <= 199:
 | |
| 		return false
 | |
| 	case status == 204:
 | |
| 		return false
 | |
| 	case status == 304:
 | |
| 		return false
 | |
| 	}
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| type httpError struct {
 | |
| 	_       incomparable
 | |
| 	msg     string
 | |
| 	timeout bool
 | |
| }
 | |
| 
 | |
| func (e *httpError) Error() string   { return e.msg }
 | |
| func (e *httpError) Timeout() bool   { return e.timeout }
 | |
| func (e *httpError) Temporary() bool { return true }
 | |
| 
 | |
| var errTimeout error = &httpError{msg: "http2: timeout awaiting response headers", timeout: true}
 | |
| 
 | |
| type connectionStater interface {
 | |
| 	ConnectionState() tls.ConnectionState
 | |
| }
 | |
| 
 | |
| var sorterPool = sync.Pool{New: func() interface{} { return new(sorter) }}
 | |
| 
 | |
| type sorter struct {
 | |
| 	v []string // owned by sorter
 | |
| }
 | |
| 
 | |
| func (s *sorter) Len() int           { return len(s.v) }
 | |
| func (s *sorter) Swap(i, j int)      { s.v[i], s.v[j] = s.v[j], s.v[i] }
 | |
| func (s *sorter) Less(i, j int) bool { return s.v[i] < s.v[j] }
 | |
| 
 | |
| // Keys returns the sorted keys of h.
 | |
| //
 | |
| // The returned slice is only valid until s used again or returned to
 | |
| // its pool.
 | |
| func (s *sorter) Keys(h http.Header) []string {
 | |
| 	keys := s.v[:0]
 | |
| 	for k := range h {
 | |
| 		keys = append(keys, k)
 | |
| 	}
 | |
| 	s.v = keys
 | |
| 	sort.Sort(s)
 | |
| 	return keys
 | |
| }
 | |
| 
 | |
| func (s *sorter) SortStrings(ss []string) {
 | |
| 	// Our sorter works on s.v, which sorter owns, so
 | |
| 	// stash it away while we sort the user's buffer.
 | |
| 	save := s.v
 | |
| 	s.v = ss
 | |
| 	sort.Sort(s)
 | |
| 	s.v = save
 | |
| }
 | |
| 
 | |
| // validPseudoPath reports whether v is a valid :path pseudo-header
 | |
| // value. It must be either:
 | |
| //
 | |
| //   - a non-empty string starting with '/'
 | |
| //   - the string '*', for OPTIONS requests.
 | |
| //
 | |
| // For now this is only used a quick check for deciding when to clean
 | |
| // up Opaque URLs before sending requests from the Transport.
 | |
| // See golang.org/issue/16847
 | |
| //
 | |
| // We used to enforce that the path also didn't start with "//", but
 | |
| // Google's GFE accepts such paths and Chrome sends them, so ignore
 | |
| // that part of the spec. See golang.org/issue/19103.
 | |
| func validPseudoPath(v string) bool {
 | |
| 	return (len(v) > 0 && v[0] == '/') || v == "*"
 | |
| }
 | |
| 
 | |
| // incomparable is a zero-width, non-comparable type. Adding it to a struct
 | |
| // makes that struct also non-comparable, and generally doesn't add
 | |
| // any size (as long as it's first).
 | |
| type incomparable [0]func()
 |