refactor(handler/http): extract Authenticator, SnifferBuilder, and normalizeRequest as testable units

Extract three pure-logic components from httpHandler to eliminate I/O
coupling from auth and sniffing construction, enabling synchronous unit
tests and reducing per-request allocation in sniffAndHandle:

- Authenticator struct with AuthResult return type — auth decisions no
  longer write to the connection; callers handle response I/O. Auth
  tests drop net.Pipe/goroutines for direct return-value assertions.
- SnifferBuilder pre-built in Init and reused per-connection via Build(),
  replacing inline sniffing.Sniffer{} construction in sniffAndHandle.
- normalizeRequest extracted to util.go with NormalizedRequest type,
  collapsing 20 lines of inline URL/normalisation into a single call.
- knockMatch extracted as standalone pure function.
- clampBodySize exported as ClampBodySize for cross-package use.
- util_test.go with 22 tests covering utility functions.
- helpers_test.go consolidates shared test fakes (logger, observer, conn).
This commit is contained in:
ginuerzh
2026-05-29 00:14:44 +08:00
parent c246a1d4fa
commit 23b58ddd23
18 changed files with 685 additions and 524 deletions
+9 -1
View File
@@ -10,6 +10,7 @@ import (
"time"
"github.com/go-gost/core/logger"
stats "github.com/go-gost/core/observer/stats"
ictx "github.com/go-gost/x/internal/ctx"
"github.com/go-gost/x/internal/net/udp"
"github.com/go-gost/x/internal/util/socks"
@@ -23,7 +24,7 @@ import (
// through the UDP tunnel.
//
// If UDP relay is disabled (enableUDP=false), a 403 Forbidden is returned.
func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, ro *xrecorder.HandlerRecorderObject, log logger.Logger) error {
func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, clientID string, ro *xrecorder.HandlerRecorderObject, log logger.Logger) error {
log = log.WithFields(map[string]any{
"cmd": "udp",
})
@@ -60,6 +61,13 @@ func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, ro *xrecorde
return err
}
if h.options.Observer != nil {
pstats := h.stats.Stats(clientID)
pstats.Add(stats.KindTotalConns, 1)
pstats.Add(stats.KindCurrentConns, 1)
defer pstats.Add(stats.KindCurrentConns, -1)
}
// Dial a UDP association through the proxy chain router. The empty
// address signals that the router should create a UDP socket rather
// than connect to a specific target.