Files
pixa/internal/httpfetcher/dial_context_internal_test.go
T
sneak 27493568fd
check / check (push) Canceled after 0s
Build the image pipeline in pixad's fx graph (closes #313)
internal/app now provides the cache, the fetcher, the processor, the
image service, the session manager and the encrypted URL generator, and
handlers.New receives them built. database.New opens the database, so
these parts can read it while fx builds them; the cache's stop hook
still runs before the database's.

Each setting's default is declared in internal/config, the default
cache_max_bytes included, which internal/app works out before it builds
the cache. The cache's MaxBytes is the one value for the disk cache
limit, and 0 turns the disk cache off. The fetcher and the processor
take explicit values. The server tests build the pipeline themselves,
as they cannot import internal/app.

Model: opus-5-5
2026-10-26 10:31:44 +00:00

77 lines
2.1 KiB
Go

package httpfetcher
import (
"errors"
"net"
"testing"
"time"
)
// TestNewUsesCheckedDialerWithoutDialContext checks that a fetcher built
// without DialContext, as pixa builds it, refuses to connect to a local
// server.
func TestNewUsesCheckedDialerWithoutDialContext(t *testing.T) {
t.Parallel()
srv := startUpstream(t)
transport := transportOf(t, New(&Config{
Timeout: 30 * time.Second,
MaxResponseSize: 50 << 20,
MaxConnectionsPerHost: 20,
MaxConnections: 64,
}))
addr := srv.Listener.Addr().String()
_, err := transport.DialContext(testContext(t), "tcp", addr)
if !errors.Is(err, ErrSSRFBlocked) {
t.Fatalf("DialContext(%s) error = %v, want ErrSSRFBlocked", addr, err)
}
}
// TestDialContextReplacesOnlyTheDialer checks that a fetcher built with
// DialContext connects through it, while the URL check still refuses a
// loopback URL and the redirect check a redirect to a link-local address.
func TestDialContextReplacesOnlyTheDialer(t *testing.T) {
t.Parallel()
srv := startUpstream(t)
dialer := &recordingDialer{target: srv.Listener.Addr().String()}
f := New(&Config{
Timeout: 30 * time.Second,
MaxResponseSize: 50 << 20,
AllowHTTP: true,
MaxConnectionsPerHost: 20,
MaxConnections: 64,
DialContext: dialer.dialContext,
})
if body := fetchBody(t, f, "/image"); body != imagePayload {
t.Errorf("body = %q, want %q", body, imagePayload)
}
_, err := f.Fetch(testContext(t), "http://127.0.0.1/image")
if !errors.Is(err, ErrSSRFBlocked) {
t.Errorf("Fetch(loopback URL) error = %v, want ErrSSRFBlocked", err)
}
_, err = f.Fetch(testContext(t), upstreamURL("/redirect/private"))
if !errors.Is(err, ErrSSRFBlocked) {
t.Errorf("Fetch(/redirect/private) error = %v, want ErrSSRFBlocked", err)
}
// The upstream server is reached through DialContext, and nothing else
// is asked of it.
dialed := dialer.dialedAddrs()
if len(dialed) == 0 {
t.Error("DialContext was never called")
}
for _, addr := range dialed {
if addr != net.JoinHostPort(testPublicHost, "80") {
t.Errorf("DialContext was asked to connect to %s", addr)
}
}
}