check / check (push) Waiting to run
The new package internal/providers builds the cache, the fetcher, the processor, the image service, the session manager and the encrypted URL generator from the config. pixad's fx graph provides them with providers.Constructors(), and handlers.New receives them built. The server tests build the same graph, with only the fetcher's dial function replaced. 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, and internal/providers works out the default cache_max_bytes. 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. Model: opus-5-5
77 lines
2.1 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|