Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
125
backend/internal/api/protocol_multiplexer.go
Normal file
125
backend/internal/api/protocol_multiplexer.go
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func normalizeHTTPServeError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if errors.Is(err, net.ErrClosed) {
|
||||
return nil
|
||||
}
|
||||
if errors.Is(err, http.ErrServerClosed) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func normalizeListenerError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if errors.Is(err, net.ErrClosed) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Server) acceptMuxConnections(listener net.Listener, httpListener *muxListener) error {
|
||||
if s == nil || listener == nil {
|
||||
return net.ErrClosed
|
||||
}
|
||||
|
||||
for {
|
||||
conn, errAccept := listener.Accept()
|
||||
if errAccept != nil {
|
||||
return errAccept
|
||||
}
|
||||
if conn == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Dispatch each connection to a goroutine so that slow/idle clients
|
||||
// cannot block the accept loop. Previously, TLS handshake and
|
||||
// reader.Peek(1) were performed inline; an idle TCP connection that
|
||||
// never sent bytes would block Peek indefinitely, preventing all
|
||||
// subsequent connections from being accepted (issue #3267).
|
||||
go s.routeMuxConnection(conn, httpListener)
|
||||
}
|
||||
}
|
||||
|
||||
// routeMuxConnection performs per-connection protocol detection and routing.
|
||||
func (s *Server) routeMuxConnection(conn net.Conn, httpListener *muxListener) {
|
||||
// Set a read deadline so that idle connections that never send bytes do not
|
||||
// leak goroutines and file descriptors. The deadline is cleared once the
|
||||
// connection is successfully routed to its handler.
|
||||
const muxSniffDeadline = 10 * time.Second
|
||||
_ = conn.SetReadDeadline(time.Now().Add(muxSniffDeadline))
|
||||
|
||||
tlsConn, ok := conn.(*tls.Conn)
|
||||
if ok {
|
||||
if errHandshake := tlsConn.Handshake(); errHandshake != nil {
|
||||
if errClose := conn.Close(); errClose != nil {
|
||||
log.Errorf("failed to close connection after TLS handshake error: %v", errClose)
|
||||
}
|
||||
return
|
||||
}
|
||||
proto := strings.TrimSpace(tlsConn.ConnectionState().NegotiatedProtocol)
|
||||
if proto == "h2" || proto == "http/1.1" {
|
||||
if httpListener == nil {
|
||||
if errClose := conn.Close(); errClose != nil {
|
||||
log.Errorf("failed to close connection: %v", errClose)
|
||||
}
|
||||
return
|
||||
}
|
||||
if errPut := httpListener.Put(tlsConn); errPut != nil {
|
||||
if errClose := conn.Close(); errClose != nil {
|
||||
log.Errorf("failed to close connection after HTTP routing failure: %v", errClose)
|
||||
}
|
||||
} else {
|
||||
_ = conn.SetReadDeadline(time.Time{})
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(conn)
|
||||
prefix, errPeek := reader.Peek(1)
|
||||
if errPeek != nil {
|
||||
if errClose := conn.Close(); errClose != nil {
|
||||
log.Errorf("failed to close connection after protocol peek failure: %v", errClose)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if isRedisRESPPrefix(prefix[0]) {
|
||||
_ = conn.SetReadDeadline(time.Time{})
|
||||
s.handleRedisConnection(conn, reader)
|
||||
return
|
||||
}
|
||||
|
||||
if httpListener == nil {
|
||||
if errClose := conn.Close(); errClose != nil {
|
||||
log.Errorf("failed to close connection without HTTP listener: %v", errClose)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if errPut := httpListener.Put(&bufferedConn{Conn: conn, reader: reader}); errPut != nil {
|
||||
if errClose := conn.Close(); errClose != nil {
|
||||
log.Errorf("failed to close connection after HTTP routing failure: %v", errClose)
|
||||
}
|
||||
} else {
|
||||
_ = conn.SetReadDeadline(time.Time{})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue