fix: add backgroundRead for plain http inbound (#952)

https://github.com/golang/go/blob/go1.21.5/src/net/http/server.go#L682
This commit is contained in:
hunshcn 2024-01-02 13:45:40 +08:00 committed by GitHub
parent 1d3e9f4889
commit 4ee267ca7e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,10 +1,14 @@
package http package http
import ( import (
"context"
"fmt" "fmt"
"io"
"net" "net"
"net/http" "net/http"
"strings" "strings"
"sync"
_ "unsafe"
"github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/adapter/inbound"
"github.com/metacubex/mihomo/common/lru" "github.com/metacubex/mihomo/common/lru"
@ -14,9 +18,18 @@ import (
"github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/log"
) )
//go:linkname registerOnHitEOF net/http.registerOnHitEOF
func registerOnHitEOF(rc io.ReadCloser, fn func())
//go:linkname requestBodyRemains net/http.requestBodyRemains
func requestBodyRemains(rc io.ReadCloser) bool
func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], additions ...inbound.Addition) { func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], additions ...inbound.Addition) {
client := newClient(c, tunnel, additions...) client := newClient(c, tunnel, additions...)
defer client.CloseIdleConnections() defer client.CloseIdleConnections()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
peekMutex := sync.Mutex{}
conn := N.NewBufferedConn(c) conn := N.NewBufferedConn(c)
@ -24,7 +37,9 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
trusted := cache == nil // disable authenticate if lru is nil trusted := cache == nil // disable authenticate if lru is nil
for keepAlive { for keepAlive {
peekMutex.Lock()
request, err := ReadRequest(conn.Reader()) request, err := ReadRequest(conn.Reader())
peekMutex.Unlock()
if err != nil { if err != nil {
break break
} }
@ -72,6 +87,23 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
if request.URL.Scheme == "" || request.URL.Host == "" { if request.URL.Scheme == "" || request.URL.Host == "" {
resp = responseWith(request, http.StatusBadRequest) resp = responseWith(request, http.StatusBadRequest)
} else { } else {
request = request.WithContext(ctx)
startBackgroundRead := func() {
go func() {
peekMutex.Lock()
defer peekMutex.Unlock()
_, err := conn.Peek(1)
if err != nil {
cancel()
}
}()
}
if requestBodyRemains(request.Body) {
registerOnHitEOF(request.Body, startBackgroundRead)
} else {
startBackgroundRead()
}
resp, err = client.Do(request) resp, err = client.Do(request)
if err != nil { if err != nil {
resp = responseWith(request, http.StatusBadGateway) resp = responseWith(request, http.StatusBadGateway)