mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-05-14 14:08:04 +08:00
71 lines
1.8 KiB
Go
71 lines
1.8 KiB
Go
|
package gun
|
||
|
|
||
|
import (
|
||
|
"io"
|
||
|
"net"
|
||
|
"net/http"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
N "github.com/metacubex/mihomo/common/net"
|
||
|
C "github.com/metacubex/mihomo/constant"
|
||
|
|
||
|
"golang.org/x/net/http2"
|
||
|
"golang.org/x/net/http2/h2c"
|
||
|
)
|
||
|
|
||
|
const idleTimeout = 30 * time.Second
|
||
|
|
||
|
type ServerOption struct {
|
||
|
ServiceName string
|
||
|
ConnHandler func(conn net.Conn)
|
||
|
HttpHandler http.Handler
|
||
|
}
|
||
|
|
||
|
func NewServerHandler(options ServerOption) http.Handler {
|
||
|
path := "/" + options.ServiceName + "/Tun"
|
||
|
connHandler := options.ConnHandler
|
||
|
httpHandler := options.HttpHandler
|
||
|
if httpHandler == nil {
|
||
|
httpHandler = http.NewServeMux()
|
||
|
}
|
||
|
// using h2c.NewHandler to ensure we can work in plain http2
|
||
|
// and some tls conn is not *tls.Conn (like *reality.Conn)
|
||
|
return h2c.NewHandler(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||
|
if request.URL.Path == path &&
|
||
|
request.Method == http.MethodPost &&
|
||
|
strings.HasPrefix(request.Header.Get("Content-Type"), "application/grpc") {
|
||
|
|
||
|
writer.Header().Set("Content-Type", "application/grpc")
|
||
|
writer.Header().Set("TE", "trailers")
|
||
|
writer.WriteHeader(http.StatusOK)
|
||
|
|
||
|
conn := &Conn{
|
||
|
initFn: func() (io.ReadCloser, error) {
|
||
|
return request.Body, nil
|
||
|
},
|
||
|
writer: writer,
|
||
|
flusher: writer.(http.Flusher),
|
||
|
}
|
||
|
if request.RemoteAddr != "" {
|
||
|
metadata := C.Metadata{}
|
||
|
if err := metadata.SetRemoteAddress(request.RemoteAddr); err == nil {
|
||
|
conn.remoteAddr = net.TCPAddrFromAddrPort(metadata.AddrPort())
|
||
|
}
|
||
|
}
|
||
|
if addr, ok := request.Context().Value(http.LocalAddrContextKey).(net.Addr); ok {
|
||
|
conn.localAddr = addr
|
||
|
}
|
||
|
|
||
|
// gun.Conn can't correct handle ReadDeadline
|
||
|
// so call N.NewDeadlineConn to add a safe wrapper
|
||
|
connHandler(N.NewDeadlineConn(conn))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
httpHandler.ServeHTTP(writer, request)
|
||
|
}), &http2.Server{
|
||
|
IdleTimeout: idleTimeout,
|
||
|
})
|
||
|
}
|