mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-05-23 18:38:09 +08:00
69 lines
1.7 KiB
Go
69 lines
1.7 KiB
Go
package tls
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
|
|
N "github.com/metacubex/mihomo/common/net"
|
|
"github.com/metacubex/mihomo/log"
|
|
|
|
"golang.org/x/net/http2"
|
|
)
|
|
|
|
func extractTlsHandshakeTimeoutFromServer(s *http.Server) time.Duration {
|
|
var ret time.Duration
|
|
for _, v := range [...]time.Duration{
|
|
s.ReadHeaderTimeout,
|
|
s.ReadTimeout,
|
|
s.WriteTimeout,
|
|
} {
|
|
if v <= 0 {
|
|
continue
|
|
}
|
|
if ret == 0 || v < ret {
|
|
ret = v
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// NewListenerForHttps returns a net.Listener for (*http.Server).Serve()
|
|
// the "func (c *conn) serve(ctx context.Context)" in http\server.go
|
|
// only do tls handshake and check NegotiatedProtocol with std's *tls.Conn
|
|
// so we do the same logic to let http2 (not h2c) work fine
|
|
func NewListenerForHttps(l net.Listener, httpServer *http.Server, tlsConfig *Config) net.Listener {
|
|
http2Server := &http2.Server{}
|
|
_ = http2.ConfigureServer(httpServer, http2Server)
|
|
return N.NewHandleContextListener(context.Background(), l, func(ctx context.Context, conn net.Conn) (net.Conn, error) {
|
|
c := Server(conn, tlsConfig)
|
|
|
|
tlsTO := extractTlsHandshakeTimeoutFromServer(httpServer)
|
|
if tlsTO > 0 {
|
|
dl := time.Now().Add(tlsTO)
|
|
_ = conn.SetReadDeadline(dl)
|
|
_ = conn.SetWriteDeadline(dl)
|
|
}
|
|
|
|
err := c.HandshakeContext(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Restore Conn-level deadlines.
|
|
if tlsTO > 0 {
|
|
_ = conn.SetReadDeadline(time.Time{})
|
|
_ = conn.SetWriteDeadline(time.Time{})
|
|
}
|
|
|
|
if c.ConnectionState().NegotiatedProtocol == http2.NextProtoTLS {
|
|
http2Server.ServeConn(c, &http2.ServeConnOpts{BaseConfig: httpServer})
|
|
return nil, net.ErrClosed
|
|
}
|
|
return c, nil
|
|
}, func(a any) {
|
|
log.Errorln("https server panic: %s", a)
|
|
})
|
|
}
|