Watch
1
0
Fork
You've already forked pkg-proxy
1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-11-09 15:49:16 -05:00
pkg-proxy/internal/server/relay_test.go
2026-09-26 15:44:28 +05:30

102 lines
3.4 KiB
Go

package server
import (
"io"
"log/slog"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/git-pkgs/proxy/internal/handler"
"github.com/go-chi/chi/v5/middleware"
)
// Small bodies normally acquire Content-Length when the handler returns. Late,
// undeclared trailers need a flush through the production responseWriter first.
func TestRelayLateTrailersThroughMiddleware(t *testing.T) {
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_, _ = io.WriteString(w, "small body")
if err := http.NewResponseController(w).Flush(); err != nil {
t.Error(err)
}
w.Header().Set(http.TrailerPrefix+"X-Late", "verified")
}))
defer upstream.Close()
for _, protocol := range []string{"http1", "http2"} {
t.Run(protocol, func(t *testing.T) {
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
s := &Server{logger: logger}
proxy := &handler.Proxy{Logger: logger, HTTPClient: upstream.Client()}
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
proxy.ProxyUpstream(w, r, upstream.URL, nil)
})
downstream := httptest.NewUnstartedServer(s.LoggerMiddleware(middleware.Recoverer(h)))
wantProto := 1
if protocol == "http2" {
downstream.EnableHTTP2 = true
downstream.StartTLS()
wantProto = 2
} else {
downstream.Start()
}
defer downstream.Close()
resp, err := downstream.Client().Get(downstream.URL)
if err != nil {
t.Fatal(err)
}
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(resp.Body)
if err != nil || string(body) != "small body" || resp.ProtoMajor != wantProto {
t.Fatalf("unexpected response: protocol=%s body=%q error=%v", resp.Proto, body, err)
}
if resp.Trailer.Get("X-Late") != "verified" || resp.Header.Get("X-Late") != "" {
t.Fatalf("late trailer lost or sent as a header: headers=%v trailers=%v", resp.Header, resp.Trailer)
}
})
}
}
func TestRelayAbortThroughMiddleware(t *testing.T) {
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_, _ = io.WriteString(w, strings.Repeat("x", 64*1024))
if err := http.NewResponseController(w).Flush(); err != nil {
t.Error(err)
}
// End the upstream chunked body without its terminating chunk.
panic(http.ErrAbortHandler)
}))
defer upstream.Close()
for _, protocol := range []string{"http1", "http2"} {
t.Run(protocol, func(t *testing.T) {
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
s := &Server{logger: logger}
proxy := &handler.Proxy{Logger: logger, HTTPClient: upstream.Client()}
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
proxy.ProxyUpstream(w, r, upstream.URL, nil)
})
downstream := httptest.NewUnstartedServer(s.LoggerMiddleware(middleware.Recoverer(h)))
wantProto := 1
if protocol == "http2" {
downstream.EnableHTTP2 = true
downstream.StartTLS()
wantProto = 2
} else {
downstream.Start()
}
defer downstream.Close()
resp, err := downstream.Client().Get(downstream.URL)
if err != nil {
t.Fatal(err)
}
defer func() { _ = resp.Body.Close() }()
_, err = io.ReadAll(resp.Body)
if err == nil {
t.Error("truncated upstream was delivered as a complete response")
}
if resp.StatusCode != http.StatusOK || resp.ProtoMajor != wantProto {
t.Fatalf("unexpected response: status=%d protocol=%s", resp.StatusCode, resp.Proto)
}
})
}
}