aoni

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 28, 2026 License: BSD-3-Clause Imports: 61 Imported by: 0

README ΒΆ

❄️ aoni

The Ice-Cold Resilience Engine for Go HTTP & Real-Time Networks

Go Reference Go Report Card License

"In networks, chaos is the default. Let aoni be your ice-cold anchor."

πŸ‡ΊπŸ‡Έ English β€’ πŸ‡·πŸ‡Ί Русский
Why Aoni?

When integrating with unstable APIs, scraping, or working with complex proxy networks in Go, the standard net/http client often requires significant boilerplate to handle real-world challenges like proxy rotation, rate limits, legacy charsets, or TLS fingerprinting.

aoni bridges this gap. It models HTTP requests as pipeline flows processed by declarative RequestModifiers and standard Go Middlewares, leveraging generics for type-safe response decoding. It remains unwavering under network load, just like the blue oni.

go get github.com/lemon4ksan/aoni

🎯 When to Use Aoni vs. Standard Clients (e.g., Resty)

aoni is not designed to replace net/http or lightweight wrappers like resty for standard, internal corporate microservices where raw, flat throughput over direct, reliable cloud connections is the only concern.

  • Choose net/http / resty for: Internal microservices, direct cloud API integrations (AWS/S3, Stripe, Twilio), and standard high-throughput REST APIs where you fully control the destination server and the network environment.
  • Choose aoni for: Deep-packet inspection (DPI) evasion, scraping/crawling targets behind aggressive firewalls (Cloudflare, Akamai, Imperva), rotating unstable proxy networks with sticky sessions, and real-time WebSockets over HTTP/2. It is your tactical off-road armor for uncooperative and chaotic network environments.

πŸŒ€ The Pipeline Philosophy

In aoni, a request is not a static objectβ€”it is a fluid stream processed in four distinct, highly optimized phases:

flowchart LR
    %% Styling
    classDef ice fill:#f0f8ff,stroke:#00a3e0,stroke-width:1.5px,color:#003366;
    linkStyle default stroke:#00a3e0,stroke-width:2px;
    
    p1["<b>[ RequestModifiers ]</b><br><i>Decorate req</i><br>━━━━━━━━━━━━━━━━━━<br>β€’ Headers<br>β€’ URL Variables<br>β€’ Request Body"]:::ice
    p2["<b>[ HTTP Middlewares ]</b><br><i>Intercept & Wrap</i><br>━━━━━━━━━━━━━━━━━━<br>β€’ Rate Limiter<br>β€’ CircuitBreaker<br>β€’ RetryEngine"]:::ice
    p3["<b>[ Transport Layer ]</b><br><i>Execute</i><br>━━━━━━━━━━━━━━━━━━<br>β€’ HappyEyeballs<br>β€’ ProxyRotator<br>β€’ LoadBalancer"]:::ice
    p4["<b>[ Generic Decoders ]</b><br><i>Extract output</i><br>━━━━━━━━━━━━━━━━━━<br>β€’ Auto-UTF8<br>β€’ JSON/XML/YAML<br>β€’ Error Models"]:::ice
    
    p1 --> p2 --> p3 --> p4

⚑ The Contrast: Standard Library vs. Aoni

To make a JSON request through a resilient proxy pool with retries and custom error parsing, standard Go requires manual loop management, type casting, and verbose transport setup.

Here is how the two approaches compare:

Standard net/http (Manual Setup) Using aoni (Declarative & Resilient)
// πŸ›‘ Verbose, unsafe state handling
transport := &http.Transport{
    Proxy: http.ProxyURL(proxyURL),
}
client := &http.Client{Transport: transport}

var lastErr error
for i := 0; i < 3; i++ {
    req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
    resp, err := client.Do(req)
    if err != nil {
        lastErr = err
        time.Sleep(backoff)
        continue
    }
    defer resp.Body.Close()
    
    if resp.StatusCode != http.StatusOK {
        // Must manually decode error schema...
    }
    
    // Must manually decode JSON...
    err = json.NewDecoder(resp.Body).Decode(&user)
    break
}
// ❄️ Clean, immutable, pipeline-driven flow
client := aoni.NewClient(transportChain)

user, err := aoni.GetJSON[User](ctx, client, "/users/{id}",
    aoni.WithVar("id", 123),
    aoni.WithErrorModel(&apiErr),
)

πŸ“Š Feature Matrix

This matrix shows where aoni focuses its design compared to Go's default capabilities and generic wrappers:

Feature / Capability Go net/http Standard Wrapper (e.g., Resty) aoni
Generics-first Decoding βœ— (Manual) βœ— (Interface-based) βœ“ (Type-safe [T])
Parallel "Happy Eyeballs" Dialing ⚠️ (Basic) βœ— βœ“ (RFC 8305)
Active Circuit Breaking βœ— βœ— βœ“ (Native Middleware)
Polite Retry-After Parsing βœ— βœ— βœ“ (Delta-sec & RFC1123)
Non-UTF8 Charset Translation βœ— βœ— βœ“ (Automatic)
TLS Evasion (JA3/JA4) βœ— βœ— βœ“ (via uTLS & Handshake)
JA4+ Fingerprinting βœ— βœ— βœ“ (TLS & HTTP, pure Go)
Sub-millisecond Tracing ⚠️ (Verbose) βœ— βœ“ (Single-modifier)
Structured Response Unwrapping βœ— βœ— βœ“ (WithBaseResponse)
Socket.IO / Engine.IO v4 Client βœ— βœ— βœ“ (Complete v5 Spec)

🍳 Cookbook: Common Resiliency Recipes

Instead of dry features, here is how you solve common, frustrating networking challenges with aoni.

1. Transparent Proxy Rotation with Sticky Sessions
  • The Problem: You need to rotate proxies to distribute load, but specific user requests must land on the exact same proxy address to preserve their active session state.
  • The Ice-Cold Solution:
p1, _ := aoni.NewProxyClient(aoni.ProxyConfig{ProxyURL: "http://proxy1.local"})
p2, _ := aoni.NewProxyClient(aoni.ProxyConfig{ProxyURL: "http://proxy2.local"})

rotator, _ := aoni.NewProxyRotator(aoni.ProxyRotatorConfig{
    MaxFails:   3,
    RetryAfter: 30 * time.Second,
}, p1, p2)

// Lock proxy selection dynamically based on the request's session cookie
stickyRotator := rotator.WithStickySessions(func(req *http.Request) string {
    if c, err := req.Cookie("sessionid"); err == nil {
        return c.Value
    }
    return ""
})

client := aoni.NewClient(aoni.Chain(stickyRotator, rateLimiter))
2. Mitigating Long-Tail Latency via Hedging
  • The Problem: Unstable proxies or overloaded servers occasionally freeze, delaying your entire execution queue.
  • The Ice-Cold Solution: If the primary request stalls and doesn't return headers in 150ms, a backup request is dispatched in parallel, returning whichever finishes first.
data, err := aoni.GetJSON[Data](ctx, aoni.NewClient(hedgedClient), "/data", WithHedging(10*time.Millisecond))
3. Automatic Legacy Charset Translation
  • The Problem: Legacy regional APIs or crawled websites return text encoded in old charsets (e.g., Cyrillic or Asian legacy encodings), resulting in garbled characters during JSON unmarshaling.
  • The Ice-Cold Solution: aoni detects the encoding on-the-fly from the headers and transparently translates the stream to standard UTF-8 before passing it to any decoder.
manifest, err := aoni.GetJSON[Manifest](ctx, client, "/legacy-manifest",
    aoni.WithDownloadProgress(func(current, total int64) {
        fmt.Printf("Downloaded %d of %d bytes\n", current, total)
    }),
)
4. Modern WAF Evasion & JA4 Fingerprinting
  • The Problem: Modern Web Application Firewalls (WAFs like Cloudflare or Akamai) block automated requests based on TLS ClientHello fingerprints (JA3/JA4) and HTTP header ordering (JA4H).
  • The Ice-Cold Solution: aoni natively emulates modern browser TLS handshakes using uTLS and automatically aligns headers to generate a clean, completely browser-compliant fingerprint. The built-in ja4 subpackage provides pure-Go JA4/JA4H computation.
info := &aoni.TraceInfo{}

client := aoni.NewClient(nil).
    WithTLSFingerprint(aoni.BrowserChrome). // Spoofs TLS ClientHello
    WithJA4Callback(func(r ja4.JA4Report) {
        fmt.Println("Active TLS Handshake JA4:", r.JA4)
    })

user, err := aoni.GetJSON[User](ctx, client, "/profile", 
    aoni.Trace(info), 
    aoni.TraceJA4(info), // Traces both TLS (JA4) and HTTP (JA4H) fingerprints
)

fmt.Println("Handshake TLS JA4:", info.JA4.JA4)   // "t13d1516h2_8daaf6152771_e5627efa2ab1"
fmt.Println("Request HTTP JA4H:", info.JA4.JA4H)  // "ge11nn03enus_9ed1ff1f7b03_cd8dafe26982"
5. Bulletproof, Real-Time Socket.IO v5 / Engine.IO v4 Streaming
  • The Problem: Real-time web sockets on protected servers get blocked during handshake due to standard Go TLS fingerprints, or silent TCP disconnects go unnoticed.
  • The Ice-Cold Solution: aoni establishes fully authenticated, JA4-spoofed, proxy-routed Socket.IO v5 sessions over standard WebSockets or stealthy HTTP/2 Extended CONNECT tunnels. It includes automatic, jittered backoff reconnection and ping-timeout heartbeats natively.
cfg := aoni.SocketIOConfig{
    Reconnection: true,
    Namespace:    "/realtime-prices",
    Auth:         map[string]string{"token": "my-secure-token"},
}

// Automatically inherits proxy rotators, DoT, JA4, and SSRF guards from the client!
sio, err := aoni.DialSocketIO(ctx, client, "wss://api.pricedb.io", cfg)
if err != nil {
    log.Fatal(err)
}

sio.On("price_update", func(args []json.RawMessage) {
    var price Price
    _ = json.Unmarshal(args[0], &price)
    fmt.Printf("Live Price: %s -> %.2f\n", price.SKU, price.Value)
})
6. Diagnostic Tracing & Offline Debugging
  • The Problem: Tracking network bottlenecks across proxies is difficult, and recreating failing requests in terminal for manual verification takes time.
  • The Ice-Cold Solution:
var trace aoni.TraceInfo

aoni.GetJSON[User](ctx, client, "/debug",
    aoni.Trace(&trace), // Detailed DNS, TCP, and TLS metrics
    aoni.AsCurl(),      // Prints equivalent executable curl command to stderr
)

fmt.Printf("DNS: %s | TCP Connect: %s | TLS Handshake: %s | TTFB: %s\n",
    trace.DNSLookup, trace.TCPConn, trace.TLSHandshake, trace.ServerProcessing)
7. Structured API Response Unwrapping with WithBaseResponse
  • The Problem: Many APIs wrap successful data in an envelope object like {"success":true,"data":{...}} or {"status":"ok","result":{...}}. Manually unwrapping these envelopes, checking success flags, and extracting errors is repetitive boilerplate.
  • The Ice-Cold Solution: Implement the BaseResponse interface (IsSuccess, Error, SetData, UnmarshalJSON) and configure the client with WithBaseResponse. The decoder automatically decodes into your wrapper, checks the success flag, extracts errors, and unwraps the inner payload β€” all in one pass.
// 1. Define your envelope wrapper
type apiResponse struct {
	Success bool   `json:"success"`
	Message string `json:"message,omitempty"`
	target  any
}

func (r *apiResponse) IsSuccess() bool            { return r.Success }
func (r *apiResponse) Error() error               { return errors.New(r.Message) }
func (r *apiResponse) SetData(data any)           { r.target = data }
func (r *apiResponse) UnmarshalJSON(data []byte) error {
	type Alias apiResponse
	var aux Alias
	if err := json.Unmarshal(data, &aux); err != nil {
		return err
	}
	r.Success, r.Message = aux.Success, aux.Message
	if r.target != nil {
		return json.Unmarshal(data, r.target)
	}
	return nil
}

// 2. Configure the client β€” every JSON request unwraps through this envelope
client := aoni.NewClient(nil).
	WithBaseURL("https://api.example.com").
	WithBaseResponse(func() aoni.BaseResponse { return &apiResponse{} })

// 3. Use it β€” the decoder handles envelope unwrapping automatically
user, err := aoni.GetJSON[User](ctx, client, "/users/1")
// If API returns {"success":false,"message":"not found"}, err is non-nil
// If API returns {"success":true,"data":{"name":"Alice"}}, user.Name == "Alice"

🎨 Memory & Resource Footprint

While standard clients focus only on raw speed, aoni is engineered to protect your host application's resources when scaling to thousands of concurrent worker loops:

  • Static Heap Footprint: Maintains an ultra-lean runtime profile, consuming roughly ~1.2 MB of live heap memory in idle states.
  • Sync.Pool Recycled Buffers: Utilizes pooled memory slices for body streaming, JSON parsing, and multipart encoding to keep GC overhead and "GC pauses" to a minimum.
  • Leak Defense (Finalizers): Leverages runtime.SetFinalizer on critical network responses to automatically release unclosed connections and warn you about resource leaks before file descriptors are exhausted.
  • Response Bomb Protection: Enforces strict payload reading limits (e.g. 10MB) via io.LimitReader on incoming responses to prevent out-of-memory (OOM) crashes from malicious or unexpectedly massive responses.

This project is licensed under the BSD 3-Clause License. See LICENSE for full details.

Keep a cold head, stay unyielding. Just like the blue oni.

Documentation ΒΆ

Overview ΒΆ

Package aoni provides a middleware-driven HTTP and WebSocket client built on top of net/http. It is designed for unreliable networks, aggressive firewalls, rotating proxy pools, and environments where deep-packet inspection must be evaded.

Standard HTTP clients are built for stable internal services. aoni fills the gap when connections are unstable, proxies fail frequently, or transport fingerprints must match a specific browser.

Request Pipeline ΒΆ

Every outgoing request passes through four stages:

  1. RequestModifier chain - declarative header, query, and body setup.
  2. Middleware chain - rate limiting, retries, circuit breaking, hedging.
  3. Transport layer - TLS fingerprinting (uTLS), HTTP/3, proxy rotation, TCP/IP spoofing.
  4. Response decoding - automatic decompression (gzip, brotli, zstd), charset transcoding, and structured binding via Decoder.

Core Types ΒΆ

Fingerprint Evasion ΒΆ

aoni can make outbound connections appear as specific browsers:

  • Client.WithTLSFingerprint selects a uTLS ClientHello profile (Chrome, Firefox, Safari) for JA3/JA4 matching.
  • Client.WithP0fSignature sets TTL, Don't Fragment, and TCP window size to mimic an OS-level network stack.
  • [Client.WithOrderedHeaders] controls the HTTP/1.1 header serialization order. For HTTP/2, H2FramedTransport reorders HPACK-encoded HEADERS frames.
  • Client.WithH2FramedTransport injects browser-specific SETTINGS and PRIORITY frames into the HTTP/2 connection preface.

Resilience ΒΆ

  • Hedging (Client.WithHedging) sends a second request after a delay if the first has not completed, cutting tail latency.
  • [AdaptiveLimiter] dynamically adjusts concurrency based on observed RTT, similar to the Vegas TCP congestion algorithm.
  • RetryMiddleware retries failed requests with exponential backoff and respects Retry-After headers.
  • CircuitBreaker tracks per-host failures and stops sending requests until the host recovers.

Network Protocols ΒΆ

Basic Usage ΒΆ

client := aoni.NewClient(nil).
	WithBaseURL("https://api.example.com").
	WithTimeout(10 * time.Second).
	WithHeader("Accept", "application/json")

resp, err := client.Request(ctx, http.MethodGet, "/users/123")
if err != nil {
	log.Fatal(err)
}
defer resp.Body.Close()

var user User
if err := aoni.DecodeJSON(resp, &user); err != nil {
	log.Fatal(err)
}

The full example directory contains runnable programs for each feature.

Index ΒΆ

Constants ΒΆ

View Source
const DefaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

DefaultUserAgent is the default User-Agent string used for HTTP requests.

Variables ΒΆ

View Source
var (
	// ErrUnexpectedContentType indicates the response content type
	// does not match the expected format. A captive portal or
	// transparent proxy often causes this.
	ErrUnexpectedContentType = errors.New("aoni: unexpected content-type (possible captive portal or intercept)")

	// ErrCloudflareChallenge indicates a Cloudflare JS challenge or
	// CAPTCHA was detected in the response body.
	ErrCloudflareChallenge = errors.New("aoni: cloudflare challenge detected")

	// ErrResponseTooLarge indicates the response exceeded the size
	// limit configured via [Client.WithMaxResponseSize].
	ErrResponseTooLarge = errors.New("aoni: response size limit exceeded")

	// ErrSSRFBlocked indicates the request was blocked because the
	// target resolved to a private or loopback address. Returned by
	// [Client.Request] when [Client.WithSSRFGuard] is enabled.
	ErrSSRFBlocked = errors.New("aoni: request blocked by SSRF guard")
)
View Source
var (
	// ChromeH2Settings provides HTTP/2 settings matching standard Google Chrome clients.
	ChromeH2Settings = HTTP2Settings{
		HeaderTableSize:   65536,
		EnablePush:        0,
		InitialWindowSize: 6291456,
		MaxHeaderListSize: 262144,
		ConnectionFlow:    15663105,
		PriorityWeight:    255,
		PriorityExclusive: true,
	}

	// FirefoxH2Settings provides HTTP/2 settings matching standard Mozilla Firefox clients.
	FirefoxH2Settings = HTTP2Settings{
		InitialStreamID:   3,
		HeaderTableSize:   65536,
		EnablePush:        0,
		InitialWindowSize: 131072,
		MaxFrameSize:      16384,
		ConnectionFlow:    12517377,
		PriorityWeight:    41,
	}
)
View Source
var (
	// AmazonCDNHeaderPool mimics AWS CloudFront and API Gateway tracing headers.
	AmazonCDNHeaderPool = []string{
		"X-Amz-Trace-Id",
		"X-Amzn-RequestId",
		"X-Amz-Cf-Id",
	}

	// CloudflareHeaderPool mimics Cloudflare proxy and CDN headers.
	CloudflareHeaderPool = []string{
		"CF-RAY",
		"CF-Connecting-IP",
		"CF-Visitor",
		"CF-IPCountry",
	}

	// GenericCDNHeaderPool mixes multiple standard cloud and CDN diagnostics headers.
	GenericCDNHeaderPool = []string{
		"X-Request-ID",
		"X-Trace-ID",
		"X-Edge-Cache-Id",
		"X-Cloud-Trace-Context",
		"X-Correlation-ID",
	}
)

Predefined realistic header pools to mimic popular Cloud/CDN networks.

View Source
var DefaultClient = NewClient(nil)

DefaultClient is the shared default client instance used by global helper functions.

View Source
var DefaultSensitiveHeaders = []string{
	"Authorization",
	"Cookie",
	"X-Session-ID",
	"X-Access-Token",
	"X-Access-Key",
	"X-Api-Key",
	"X-Auth-Token",
}

DefaultSensitiveHeaders lists headers removed from requests during cross-origin redirects. Used by DefaultRedirectPolicy.

Functions ΒΆ

func AppendContextModifier ΒΆ added in v0.3.0

func AppendContextModifier(ctx context.Context, mods ...RequestModifier) context.Context

AppendContextModifier appends new modifiers to an existing context carrying modifiers, or creates a new one if none are present.

func CurlCommand ΒΆ

func CurlCommand(req *http.Request, body []byte) string

CurlCommand generates a shell-compatible curl command string from an http.Request and body.

func DecodeByContentType ΒΆ added in v0.3.0

func DecodeByContentType(r io.Reader, contentType string, target any) error

DecodeByContentType automatically parses the stream from r into target by selecting the most appropriate registered decoder based on the parsed MIME-type. Falls back to RawDecoder if the content type is unrecognized or raw binary is returned.

func DecodeJSON ΒΆ added in v0.3.0

func DecodeJSON[T any](r io.Reader) (T, error)

DecodeJSON is a convenience helper to directly decode a JSON stream into T.

func DecodeTo ΒΆ added in v0.3.0

func DecodeTo[T any](r io.Reader, d Decoder) (T, error)

DecodeTo decodes the data from r using the provided decoder into a newly allocated T.

func DecodeXML ΒΆ added in v0.3.0

func DecodeXML[T any](r io.Reader) (T, error)

DecodeXML is a convenience helper to directly decode an XML stream into T.

func DecodeYAML ΒΆ added in v0.3.0

func DecodeYAML[T any](r io.Reader) (T, error)

DecodeYAML is a convenience helper to directly decode a YAML stream into T.

func DefaultCircuitBreakerCondition ΒΆ

func DefaultCircuitBreakerCondition(resp *http.Response, err error) bool

DefaultCircuitBreakerCondition returns true for network errors and HTTP status codes >= 500.

func DefaultRedirectPolicy ΒΆ

func DefaultRedirectPolicy(
	maxRedirects int,
	sensitiveHeaders ...string,
) func(req *http.Request, via []*http.Request) error

DefaultRedirectPolicy returns a function suitable for http.Client.CheckRedirect. It stops after maxRedirects and strips sensitiveHeaders on cross-origin redirects. When sensitiveHeaders is empty, DefaultSensitiveHeaders is used.

func Delete ΒΆ

func Delete[Resp any](
	ctx context.Context,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, error)

Delete performs a global DELETE request using DefaultClient and decodes the JSON response body.

func DeleteJSON ΒΆ

func DeleteJSON[Resp any](
	ctx context.Context,
	c Requester,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, error)

DeleteJSON marshals the payload to JSON, executes a DELETE request, and decodes the response body. It automatically configures the request headers with Content-Type and Accept set to "application/json".

If the payload implements io.Reader, it is used directly as the request body. Otherwise, the payload is marshaled to URL-encoded form values and wrapped in a strings.Reader.

It validates the payload structure beforehand using Validate. Returns a ValidationError if validation fails.

func DeleteJSONEx ΒΆ added in v0.3.0

func DeleteJSONEx[Resp any](
	ctx context.Context,
	c Requester,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, *http.Response, error)

DeleteJSONEx is like DeleteJSON but returns both the parsed response payload and the raw *http.Response.

func DialWebSocket ΒΆ

func DialWebSocket(
	ctx context.Context,
	c *Client,
	targetURL string,
	mods ...RequestModifier,
) (net.Conn, *http.Response, error)

DialWebSocket establishes a WebSocket connection using the same uTLS/JA4 pipeline as regular HTTP requests. It respects proxy configuration, source IP rotation, SSRF guards, and Happy Eyeballs dialing.

The returned net.Conn is a full-duplex byte stream over WebSocket. For wss:// connections, the TLS handshake uses the client's configured browser fingerprint (via Client.WithTLSFingerprint), and JA4 fingerprints are computed during the handshake.

Use TraceJA4 to capture both TLS (JA4) and HTTP (JA4H) fingerprints:

info := &aoni.TraceInfo{}
wsConn, resp, err := aoni.DialWebSocket(ctx, client, "wss://example.com/ws",
    aoni.WithHeader("Origin", "https://example.com"),
    aoni.TraceJA4(info),
)
fmt.Println(info.JA4.JA4) // TLS fingerprint from the WebSocket handshake

func DialWebSocketWithConfig ΒΆ

func DialWebSocketWithConfig(
	ctx context.Context,
	c *Client,
	targetURL string,
	config DialWebSocketConfig,
	mods ...RequestModifier,
) (net.Conn, *http.Response, error)

DialWebSocketWithConfig is like DialWebSocket but allows custom buffer sizes.

func ExportCookiesJSON ΒΆ added in v0.3.0

func ExportCookiesJSON(jar http.CookieJar, u *url.URL) (string, error)

ExportCookiesJSON serializes the exported cookies for the given URL directly into a JSON string.

func GeneratePadding ΒΆ added in v0.2.0

func GeneratePadding(cfg PaddingConfig) []byte

GeneratePadding returns random padding bytes of the configured length range.

func Get ΒΆ

func Get[Resp any](ctx context.Context, path string, mods ...RequestModifier) (*Resp, error)

Get performs a global GET request using DefaultClient and decodes the JSON response body.

func GetJSON ΒΆ

func GetJSON[Resp any](
	ctx context.Context,
	c Requester,
	path string,
	mods ...RequestModifier,
) (*Resp, error)

GetJSON performs a GET request and decodes the JSON response body into a new instance of Resp. It returns an APIError if the server responds with a non-2xx status code.

func GetJSONEx ΒΆ added in v0.3.0

func GetJSONEx[Resp any](
	ctx context.Context,
	c Requester,
	path string,
	mods ...RequestModifier,
) (*Resp, *http.Response, error)

GetJSONEx is like GetJSON but returns both the parsed response payload and the raw *http.Response.

func HostRewriteRules ΒΆ added in v0.3.0

func HostRewriteRules(ctx context.Context) map[string]string

HostRewriteRules extracts and returns the active host rewrite rules map from the given context. Returns nil if no rules are configured in the context.

func ImportCookies ΒΆ

func ImportCookies(jar http.CookieJar, u *url.URL, cookies []CookieData)

ImportCookies imports cookies from the browser/automation data into http.CookieJar.

func ImportCookiesJSON ΒΆ added in v0.3.0

func ImportCookiesJSON(jar http.CookieJar, u *url.URL, jsonStr string) error

ImportCookiesJSON deserializes cookies from a JSON string and imports them into http.CookieJar.

func MirrorCookies ΒΆ added in v0.2.0

func MirrorCookies(jar http.CookieJar, sourceURL *url.URL, targetURLs []*url.URL, cookieNames ...string)

MirrorCookies copies cookies with the specified names from the sourceURL to all targetURLs within a single jar.

func NewFragmentedConn ΒΆ

func NewFragmentedConn(conn net.Conn, cfg *FragmentConfig) net.Conn

NewFragmentedConn wraps a net.Conn with fragmentation and delay settings.

func NewProxyClient ΒΆ

func NewProxyClient(cfg ProxyConfig) (*http.Client, error)

NewProxyClient creates an http.Client configured with proxy transport. It prioritizes ProxyConfig.TransportFactory, then ProxyConfig.Transport, and falls back to a default http.Transport if neither is provided.

If ProxyConfig.ProxyURL is empty, no proxy routing is applied. If ProxyConfig.Timeout is zero, a default 15-second timeout is set.

func NewStdClient ΒΆ added in v0.2.0

func NewStdClient(c *Client) *http.Client

NewStdClient returns a standard http.Client whose transport routes all requests through the configured aoni Client pipeline.

The returned client has Jar set to nil to avoid double cookie handling. The aoni ProxyIsolatedCookieJar manages cookies internally.

Usage:

client := aoni.NewClient(nil).
    WithTLSFingerprint(aoni.BrowserChrome).
    WithDoHResolver()
stdClient := aoni.NewStdClient(client)

// Use with any third-party library
restyClient.SetHTTPClient(stdClient)

func PaddingHeaderName ΒΆ added in v0.2.0

func PaddingHeaderName(cfg PaddingConfig) string

PaddingHeaderName returns a header name for padding. If HeaderPool is configured, a random entry is selected to avoid creating a static DPI fingerprint. Otherwise PaddingHeader is used, falling back to "X-Padding".

func ParseSSE ΒΆ

func ParseSSE[T any](ctx context.Context, resp *StreamResponse) (<-chan T, <-chan error)

ParseSSE parses a Server-Sent Event stream and returns a channel of parsed events and an error channel.

func Patch ΒΆ

func Patch[Resp any](
	ctx context.Context,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, error)

Patch performs a global PATCH request using DefaultClient and decodes the JSON response body.

func PatchJSON ΒΆ

func PatchJSON[Resp any](
	ctx context.Context,
	c Requester,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, error)

PatchJSON marshals the payload to JSON, executes a PATCH request, and decodes the response body. It automatically configures the request headers with Content-Type and Accept set to "application/json".

If the payload implements io.Reader, it is used directly as the request body. Otherwise, the payload is marshaled to URL-encoded form values and wrapped in a strings.Reader.

It validates the payload structure beforehand using Validate. Returns a ValidationError if validation fails.

func PatchJSONEx ΒΆ added in v0.3.0

func PatchJSONEx[Resp any](
	ctx context.Context,
	c Requester,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, *http.Response, error)

PatchJSONEx is like PatchJSON but returns both the parsed response payload and the raw *http.Response.

func Post ΒΆ

func Post[Resp any](
	ctx context.Context,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, error)

Post performs a global POST request using DefaultClient and decodes the JSON response body.

func PostFormJSON ΒΆ added in v0.3.0

func PostFormJSON[Resp any](
	ctx context.Context,
	c Requester,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, error)

PostFormJSON marshals the payload, performs a POST request with URL-encoded parameters, and decodes the resulting JSON response body into Resp.

If the payload implements io.Reader, it is used directly as the request body. Otherwise, the payload is marshaled to URL-encoded form values and wrapped in a strings.Reader.

It validates the payload structure beforehand using Validate. Returns a ValidationError if validation fails.

func PostFormJSONEx ΒΆ added in v0.3.0

func PostFormJSONEx[Resp any](
	ctx context.Context,
	c Requester,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, *http.Response, error)

PostFormJSONEx is like PostFormJSON but returns both the parsed response payload and the raw *http.Response.

func PostJSON ΒΆ

func PostJSON[Resp any](
	ctx context.Context,
	c Requester,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, error)

PostJSON marshals the payload to JSON, executes a POST request, and decodes the response body. It automatically configures the request headers with Content-Type and Accept set to "application/json".

If the payload implements io.Reader, it is used directly as the request body. Otherwise, the payload is marshaled to URL-encoded form values and wrapped in a strings.Reader.

It validates the payload structure beforehand using Validate. Returns a ValidationError if validation fails.

func PostJSONEx ΒΆ added in v0.3.0

func PostJSONEx[Resp any](
	ctx context.Context,
	c Requester,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, *http.Response, error)

PostJSONEx is like PostJSON but returns both the parsed response payload and the raw *http.Response.

func Put ΒΆ

func Put[Resp any](
	ctx context.Context,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, error)

Put performs a global PUT request using DefaultClient and decodes the JSON response body.

func PutJSON ΒΆ

func PutJSON[Resp any](
	ctx context.Context,
	c Requester,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, error)

PutJSON marshals the payload to JSON, executes a PUT request, and decodes the response body. It automatically configures the request headers with Content-Type and Accept set to "application/json".

If the payload implements io.Reader, it is used directly as the request body. Otherwise, the payload is marshaled to URL-encoded form values and wrapped in a strings.Reader.

It validates the payload structure beforehand using Validate. Returns a ValidationError if validation fails.

func PutJSONEx ΒΆ added in v0.3.0

func PutJSONEx[Resp any](
	ctx context.Context,
	c Requester,
	path string,
	payload any,
	mods ...RequestModifier,
) (*Resp, *http.Response, error)

PutJSONEx is like PutJSON but returns both the parsed response payload and the raw *http.Response.

func ReadAllBytes ΒΆ added in v0.3.0

func ReadAllBytes(rb ReplayableBody) ([]byte, error)

ReadAllBytes reads the entire content of a ReplayableBody as a byte slice, and automatically resets the body so it remains completely reusable.

func ReadAllString ΒΆ added in v0.3.0

func ReadAllString(rb ReplayableBody) (string, error)

ReadAllString reads the entire content of a ReplayableBody as a string, and automatically resets the body so it remains completely reusable. This is a high-level helper for quick logging and assertions.

func StreamChunks ΒΆ added in v0.3.0

func StreamChunks(ctx context.Context, resp *StreamResponse) (<-chan string, <-chan error)

StreamChunks reads raw data from the stream chunk-by-chunk and yields them as strings. This is a high-level helper suitable for or real-time streaming.

func StreamNDJSON ΒΆ

func StreamNDJSON[T any](ctx context.Context, resp *StreamResponse) (<-chan T, <-chan error)

StreamNDJSON reads a newline-delimited JSON stream from the StreamResponse body. It parses values concurrently in a background goroutine and pushes them to the returned channel. It automatically closes channels and connection streams when done or on context cancellation.

func StreamSSE ΒΆ

func StreamSSE[T any](
	ctx context.Context,
	c Requester,
	path string,
	mods ...RequestModifier,
) (<-chan T, <-chan error, error)

StreamSSE parses incoming Server-Sent Events from the StreamResponse body. It executes a background parsing loop and closes returned channels when done.

func StructToValues ΒΆ

func StructToValues(s any) (url.Values, error)

StructToValues encodes a struct into url.Values using "url" or "json" tags. It expands inline structs recursively and supports slices, arrays, and primitive types. Returns an error if the input is not a struct or pointer to a struct.

func UnwrapTo ΒΆ added in v0.2.0

func UnwrapTo[T any](c io.Closer) (T, bool)

UnwrapTo traverses the decorator chain c and returns the first layer that implements the generic type T, as well as true. If no matching layer is found, returns the null value of T and false.

func Validate ΒΆ

func Validate(s any) error

Validate checks struct fields for the "validate:required" tag. It returns a ValidationError for the first missing required field.

func WithContextModifier ΒΆ added in v0.2.0

func WithContextModifier(ctx context.Context, mods ...RequestModifier) context.Context

WithContextModifier returns a new context carrying the given RequestModifiers. Third-party libraries that pass context through http.Request will carry these modifiers into the aoni pipeline automatically.

Example with go-resty:

ctx := aoni.WithContextModifier(context.Background(),
    aoni.WithHeader("X-Api-Key", "secret"),
    aoni.TraceJA4(info),
)
resp, err := restyClient.R().SetContext(ctx).Get("/api/data")

Types ΒΆ

type APIError ΒΆ

type APIError struct {
	StatusCode int
	Body       []byte
	Model      any
}

APIError wraps a non-2xx HTTP response. StatusCode holds the status code, Body holds the raw response, and Model holds the deserialized error structure when WithErrorModel was used. Inspect with errors.As.

func (*APIError) Error ΒΆ

func (e *APIError) Error() string

Error returns a human-readable representation of e.

type Backend ΒΆ

type Backend struct {
	// URL is the address of the backend server.
	URL string

	// Weight is the selection weight for the [WeightedRoundRobin] strategy.
	Weight int

	*HealthTracker
	// contains filtered or unexported fields
}

Backend tracks the health and connection state of a single server in the load balancer.

type BackoffStrategy ΒΆ added in v0.3.0

type BackoffStrategy interface {
	Next() time.Duration
	Reset()
}

BackoffStrategy Defines the interface for calculating delays before reconnecting. Allows the implementation of custom attenuation strategies (exponential, linear, Fibonacci, etc.).

type BaseResponse ΒΆ

type BaseResponse interface {
	// IsSuccess reports whether the response indicates a successful operation.
	IsSuccess() bool
	// Error returns an error representation if IsSuccess returns false.
	Error() error
	// SetData sets the data into the response.
	SetData(data any)
}

BaseResponse is implemented by user-defined response wrappers that participate in GetJSON and similar generic request helpers. The decoder calls IsSuccess, SetData, and Error to route the result.

type BaseResponseProvider ΒΆ

type BaseResponseProvider interface {
	BaseResponse() BaseResponse
}

BaseResponseProvider optionally provides a BaseResponse for structured decoding. Implemented by response wrapper types used with Client.WithBaseResponse.

type BoolInt ΒΆ

type BoolInt bool

BoolInt parses booleans from integers or strings in JSON. It maps 1, "1", "true" to true and 0, "0", "false", "null" to false.

func (BoolInt) MarshalJSON ΒΆ added in v0.3.0

func (bi BoolInt) MarshalJSON() ([]byte, error)

MarshalJSON serializes BoolInt back as numeric "1" or "0" JSON representations.

func (*BoolInt) UnmarshalJSON ΒΆ

func (bi *BoolInt) UnmarshalJSON(b []byte) error

UnmarshalJSON implements json.Unmarshaler.

type BridgeError ΒΆ added in v0.3.0

type BridgeError struct {
	Op       string
	URL      string
	Err      error
	Metadata map[string]any
}

BridgeError represents an error occurring during standard-client bridging. It implements the standard error interface and can be unwrapped to retrieve the underlying client or transport errors.

func (*BridgeError) Error ΒΆ added in v0.3.0

func (e *BridgeError) Error() string

Error implements the standard error interface.

func (*BridgeError) Unwrap ΒΆ added in v0.3.0

func (e *BridgeError) Unwrap() error

Unwrap returns the underlying wrapped error.

type BrowserID ΒΆ

type BrowserID int

BrowserID selects a uTLS ClientHello profile for JA3 fingerprint emulation. Pass to Client.WithTLSFingerprint.

const (
	// BrowserNone disables TLS fingerprint emulation.
	BrowserNone BrowserID = iota
	// BrowserChrome emulates Google Chrome TLS fingerprints.
	BrowserChrome
	// BrowserFirefox emulates Mozilla Firefox TLS fingerprints.
	BrowserFirefox
	// BrowserSafari emulates Apple Safari TLS fingerprints.
	BrowserSafari
)

type ChaosConfig ΒΆ

type ChaosConfig struct {
	// FailureRate is the probability (0.0 to 1.0) of randomly returning a 503 error.
	FailureRate float64
	// LatencyMin is the minimum artificial delay duration applied to requests.
	LatencyMin time.Duration
	// LatencyMax is the maximum artificial delay duration applied to requests.
	LatencyMax time.Duration
}

ChaosConfig defines parameters for ChaosMiddleware.

type CircuitBreaker ΒΆ

type CircuitBreaker struct {
	// contains filtered or unexported fields
}

CircuitBreaker tracks per-host connection health using a sliding window. After the failure ratio within CircuitBreakerConfig.Window exceeds CircuitBreakerConfig.FailureThreshold, the circuit opens and rejects requests for CircuitBreakerConfig.Cooldown. It then enters half-open and allows a single trial request; success closes it.

func NewCircuitBreaker ΒΆ

func NewCircuitBreaker(cfg CircuitBreakerConfig) *CircuitBreaker

NewCircuitBreaker creates a CircuitBreaker with cfg. Zero fields default to 50% failure threshold, 10s window, 5 min requests, and 5s cooldown.

type CircuitBreakerConfig ΒΆ

type CircuitBreakerConfig struct {
	// FailureThreshold is the ratio of failures (0.0 to 1.0) that triggers the open state.
	FailureThreshold float64
	// Cooldown is the duration the breaker remains open before transitioning to half-open.
	Cooldown time.Duration
	// MinRequests is the minimum number of requests in a Window before threshold check is active.
	MinRequests int
	// Window is the sliding time duration over which failures are tracked.
	Window time.Duration
}

CircuitBreakerConfig tunes the thresholds for CircuitBreaker. It wraps breaker.Config with a per-host map.

type Client ΒΆ

type Client struct {
	// contains filtered or unexported fields
}

Client is an immutable, concurrency-safe HTTP client built on HTTPDoer. Every With* method returns a new clone, so the original remains usable by other goroutines. Use NewClient to create the first instance.

func NewClient ΒΆ

func NewClient(httpClient HTTPDoer) *Client

NewClient creates a Client wrapping httpClient. When httpClient is nil a default http.Client with a 15-second timeout and DefaultRedirectPolicy (10 hops) is used. The returned client has DefaultUserAgent set and a transport dialer configured for Happy Eyeballs.

func UnwrapClient ΒΆ

func UnwrapClient(r Requester) *Client

UnwrapClient strips all Unwrapper layers from r and returns the innermost Client. Returns nil if r is not a *Client and no Unwrapper chain leads to one.

func (*Client) BaseResponse ΒΆ

func (c *Client) BaseResponse() BaseResponse

BaseResponse returns a new BaseResponse wrapper if a provider is configured on the client. Returns nil if no provider is set.

func (*Client) Clone ΒΆ

func (c *Client) Clone() *Client

Clone returns a deep copy of c. The cloned client shares nothing mutable with the original - transport, cookie jar, and config structs are all independently copied.

func (*Client) CloseIdleConnections ΒΆ

func (c *Client) CloseIdleConnections()

CloseIdleConnections closes any idle keep-alive connections maintained by the client. This only works if the underlying HTTPDoer is an http.Client.

func (*Client) HTTP ΒΆ

func (c *Client) HTTP() HTTPDoer

HTTP returns the underlying HTTPDoer interface.

func (*Client) Logger ΒΆ

func (c *Client) Logger() Logger

Logger returns the logger used by the client. If no logger is set, a no-op logger is returned.

func (*Client) Request ΒΆ

func (c *Client) Request(
	ctx context.Context,
	method, path string,
	mods ...RequestModifier,
) (*http.Response, error)

Request sends an HTTP request and returns the response. path is resolved against Client.WithBaseURL when set; an empty path targets the base URL directly. Nil modifiers are ignored.

Decompression (gzip, brotli, zstd) and charset transcoding to UTF-8 are applied automatically. The response body is wrapped with a GC finalizer so that unclosed bodies eventually release the underlying connection.

Returns ErrSSRFBlocked when SSRF guarding is on and the target resolves to a private or loopback address. Returns ErrResponseTooLarge when a response size limit is configured and the body exceeds it.

func (*Client) Transport ΒΆ

func (c *Client) Transport() *http.Transport

Transport returns the underlying http.Transport of the client. Returns nil if the HTTPDoer is not an http.Client or its transport is not an http.Transport.

func (*Client) UserAgent ΒΆ

func (c *Client) UserAgent() string

UserAgent returns the User-Agent header configured on c.

func (*Client) WithAfterResponse ΒΆ

func (c *Client) WithAfterResponse(hook func(resp *http.Response, err error)) *Client

WithAfterResponse returns a clone of c that calls hook after every request, regardless of success or failure.

func (*Client) WithBaseResponse ΒΆ

func (c *Client) WithBaseResponse(provider func() BaseResponse) *Client

WithBaseResponse returns a clone of c that uses provider to create BaseResponse wrappers for structured decoding. Pass nil to clear.

func (*Client) WithBaseURL ΒΆ

func (c *Client) WithBaseURL(raw string) *Client

WithBaseURL returns a clone of c that resolves relative paths in Client.Request against raw. An empty string clears the base URL. If raw is not a valid URL, the original client is returned unchanged.

func (*Client) WithBasicAuth ΒΆ added in v0.2.0

func (c *Client) WithBasicAuth(username, password string) *Client

WithBasicAuth returns a clone of c that sends Basic authentication credentials on every request.

func (*Client) WithBearer ΒΆ added in v0.2.0

func (c *Client) WithBearer(token string) *Client

WithBearer returns a clone of c that sends token as a Bearer Authorization header on every request.

func (*Client) WithBeforeRequest ΒΆ

func (c *Client) WithBeforeRequest(hook func(req *http.Request)) *Client

WithBeforeRequest returns a clone of c that calls hook before every request. Hooks execute in registration order.

func (*Client) WithBrowserProfile ΒΆ added in v0.3.0

func (c *Client) WithBrowserProfile(browser BrowserID, os profiles.OSKey) *Client

WithBrowserProfile configures both the TLS fingerprint, matching HTTP/2 framed settings, and default browser headers (like User-Agent, Sec-Ch-Ua, and Accept orders) in a single call. This prevents fingerprint mismatches between TLS and HTTP/2 layers. Use [WithH2FramedTransport] and WithUserAgent to configure HTTP/2 settings and User-Agent separately.

func (*Client) WithConnectionPool ΒΆ

func (c *Client) WithConnectionPool(cfg ConnectionPoolConfig) *Client

WithConnectionPool returns a clone of c with the transport pool tuned to cfg. Fields left at zero keep the existing transport settings. Only effective when the underlying HTTPDoer is an http.Client with an http.Transport.

func (*Client) WithCookieJar ΒΆ

func (c *Client) WithCookieJar(jar http.CookieJar) *Client

WithCookieJar returns a clone of c that stores and sends cookies through jar. Only effective when the underlying HTTPDoer is an http.Client.

func (*Client) WithDNSCache ΒΆ

func (c *Client) WithDNSCache(ttl time.Duration) *Client

WithDNSCache returns a clone of c that caches DNS results for ttl. The cache wraps the current DNS resolver.

func (*Client) WithDNSResolver ΒΆ

func (c *Client) WithDNSResolver(resolver DNSResolver) *Client

WithDNSResolver returns a clone of c that resolves hostnames through resolver instead of the system resolver.

func (*Client) WithDoH ΒΆ added in v0.2.0

func (c *Client) WithDoH(endpoint, host string) *Client

WithDoH returns a clone of c that resolves DNS via DNS-over-HTTPS using endpoint as the resolver URL and host as the HTTP Host header. See NewDoHResolver.

func (*Client) WithDoT ΒΆ added in v0.2.0

func (c *Client) WithDoT(endpoint, host string) *Client

WithDoT returns a clone of c that resolves DNS via DNS-over-TLS using endpoint as the resolver address and host as the TLS server name. See NewDoTResolver.

func (*Client) WithDynamicHedging ΒΆ added in v0.2.0

func (c *Client) WithDynamicHedging(config *DynamicHedgingConfig) *Client

WithDynamicHedging returns a clone of c that computes the hedging delay dynamically from the p95 RTT of recent requests. When config is nil, DefaultDynamicHedgingConfig values are used.

func (*Client) WithFragmentation ΒΆ

func (c *Client) WithFragmentation(cfg FragmentConfig) *Client

WithFragmentation returns a clone of c that splits the TLS ClientHello across multiple TCP segments according to cfg. See FragmentConfig.

func (*Client) WithH2FramedTransport ΒΆ added in v0.2.0

func (c *Client) WithH2FramedTransport(settings HTTP2Settings) *Client

WithH2FramedTransport returns a clone of c that injects browser- specific SETTINGS and PRIORITY frames into the HTTP/2 connection preface. This makes the HTTP/2 fingerprint match the TLS profile set by Client.WithTLSFingerprint.

func (*Client) WithHTTP2Settings ΒΆ

func (c *Client) WithHTTP2Settings(settings HTTP2Settings) *Client

WithHTTP2Settings returns a clone of c with custom HTTP/2 connection parameters. These values are stored on the client but only take effect when Client.WithH2FramedTransport is also configured.

func (*Client) WithHTTP3 ΒΆ

func (c *Client) WithHTTP3() *Client

WithHTTP3 returns a clone of c that sends requests over HTTP/3 (QUIC). Uses DefaultQUICMigrationConfig for migration settings.

func (*Client) WithHTTP3Config ΒΆ added in v0.2.0

func (c *Client) WithHTTP3Config(config *QUICMigrationConfig) *Client

WithHTTP3Config returns a clone of c that sends requests over HTTP/3 (QUIC) with migration settings from config. When config is nil, DefaultQUICMigrationConfig values are used.

func (*Client) WithHappyEyeballs ΒΆ

func (c *Client) WithHappyEyeballs(delay time.Duration) *Client

WithHappyEyeballs returns a clone of c that staggers parallel connection attempts by delay per address. A duration <= 0 disables staggering and tries all addresses simultaneously.

func (*Client) WithHeader ΒΆ

func (c *Client) WithHeader(key, value string) *Client

WithHeader returns a clone of c with key set to value on every outgoing request. Overwrites any existing value for key.

func (*Client) WithHedging ΒΆ

func (c *Client) WithHedging(d time.Duration) *Client

WithHedging returns a clone of c that dispatches a second request after d if the first has not completed. A duration <= 0 disables hedging.

func (*Client) WithHostRewrite ΒΆ

func (c *Client) WithHostRewrite(rules map[string]string) *Client

WithHostRewrite returns a clone of c that resolves hostnames in requests according to rules (host -> ip), while keeping the original hostname for TLS SNI.

func (*Client) WithJA4Callback ΒΆ

func (c *Client) WithJA4Callback(fn func(ja4.Report)) *Client

WithJA4Callback returns a clone of c that calls fn after each TLS handshake with the ja4.Report. Requires Client.WithTLSFingerprint to be enabled.

func (*Client) WithLocalAddr ΒΆ

func (c *Client) WithLocalAddr(addr string) *Client

WithLocalAddr returns a clone of c that binds outgoing connections to addr. The local address is only used when its IP family (v4/v6) matches the target's family. Ignored when the underlying HTTPDoer is not an http.Client with an http.Transport.

func (*Client) WithLocalAddrPool ΒΆ

func (c *Client) WithLocalAddrPool(addrs []string) *Client

WithLocalAddrPool returns a clone of c that round-robins source IP addresses from addrs. Each outgoing connection binds to the next address in the pool. Invalid addresses are silently ignored.

func (*Client) WithLogger ΒΆ

func (c *Client) WithLogger(l Logger) *Client

WithLogger returns a clone of c that logs diagnostics through l.

func (*Client) WithMaxResponseSize ΒΆ

func (c *Client) WithMaxResponseSize(size int64) *Client

WithMaxResponseSize returns a clone of c that rejects response bodies larger than size bytes. A value <= 0 removes the limit.

func (*Client) WithModifiers ΒΆ

func (c *Client) WithModifiers(mods ...RequestModifier) *Client

WithModifiers returns a clone of c that applies mods to every outgoing request before the middleware chain.

func (*Client) WithMultiReadBody ΒΆ

func (c *Client) WithMultiReadBody(threshold int64) *Client

WithMultiReadBody returns a clone of c that caches response bodies smaller than threshold bytes so they can be re-read. A value <= 0 disables caching.

func (*Client) WithOrigin ΒΆ

func (c *Client) WithOrigin(origin string) *Client

WithOrigin returns a clone of c that sends origin as the Origin header on every request.

func (*Client) WithP0fSignature ΒΆ

func (c *Client) WithP0fSignature(sig *p0f.Signature) *Client

WithP0fSignature returns a clone of c that spoofs TCP/IP fields (TTL, Don't Fragment, window size) to match sig. The spoofing is applied via Dialer.Control before the SYN packet is sent, making the connection appear as the OS described by sig to passive fingerprinters such as p0f.

func (*Client) WithPacketPadding ΒΆ added in v0.2.0

func (c *Client) WithPacketPadding(cfg PaddingConfig) *Client

WithPacketPadding returns a clone of c that constrains TCP MSS and adds random padding headers to disrupt DPI length analysis. See PaddingConfig for available fields.

func (*Client) WithProfileH2Settings ΒΆ added in v0.2.0

func (c *Client) WithProfileH2Settings(s profiles.H2Settings) *Client

WithProfileH2Settings returns a clone of c with HTTP/2 settings extracted from s. See H2SettingsFromProfile.

func (*Client) WithProxy ΒΆ added in v0.2.0

func (c *Client) WithProxy(proxyURL *url.URL) *Client

WithProxy returns a clone of c configured to route requests through proxyURL. Supported schemes: http, socks5, socks5h (for remote DNS resolution). When proxyURL is nil, proxy routing is disabled.

func (*Client) WithProxyAwareSessionCache ΒΆ added in v0.2.0

func (c *Client) WithProxyAwareSessionCache() *Client

WithProxyAwareSessionCache returns a clone of c that resumes TLS sessions via a ProxyAwareSessionCache. The cache is invalidated automatically when the proxy or source IP changes, preventing servers from correlating sessions across different exit nodes.

func (*Client) WithProxyDNS ΒΆ added in v0.2.0

func (c *Client) WithProxyDNS() *Client

WithProxyDNS returns a clone of c that resolves hostnames through the configured SOCKS5 or HTTP CONNECT proxy instead of the local system resolver. This prevents the local ISP from observing DNS queries.

func (*Client) WithProxyIsolatedCookieJar ΒΆ

func (c *Client) WithProxyIsolatedCookieJar(jar *ProxyIsolatedCookieJar) *Client

WithProxyIsolatedCookieJar returns a clone of c that stores cookies per proxy URL in jar, preventing cross-proxy session leakage. See ProxyIsolatedCookieJar.

func (*Client) WithRedirectLimit ΒΆ

func (c *Client) WithRedirectLimit(max int) *Client

WithRedirectLimit returns a clone of c that stops following redirects after max. A value of 0 disables redirects entirely. A negative value restores Go's default behavior (10 hops).

func (*Client) WithSSRFGuard ΒΆ

func (c *Client) WithSSRFGuard() *Client

WithSSRFGuard returns a clone of c that blocks requests resolving to private or loopback IP addresses. Returns ErrSSRFBlocked from Client.Request when triggered.

func (*Client) WithTLSFingerprint ΒΆ

func (c *Client) WithTLSFingerprint(browser BrowserID) *Client

WithTLSFingerprint returns a clone of c that uses uTLS to emulate a browser's TLS ClientHello. BrowserNone disables emulation. Only effective when the underlying HTTPDoer is an http.Client with an http.Transport.

func (*Client) WithTimeout ΒΆ

func (c *Client) WithTimeout(d time.Duration) *Client

WithTimeout returns a clone of c whose requests time out after d. Only works when the underlying HTTPDoer is an http.Client. A duration <= 0 means no timeout.

func (*Client) WithUserAgent ΒΆ

func (c *Client) WithUserAgent(ua string) *Client

WithUserAgent returns a clone of c that sends ua as the User-Agent header on every request.

type ClientWithProxy ΒΆ

type ClientWithProxy struct {
	Client   HTTPDoer
	ProxyURL string
}

ClientWithProxy pairs an HTTPDoer with a proxy URL.

type ConnectionPoolConfig ΒΆ

type ConnectionPoolConfig struct {
	// MaxIdleConns is the maximum number of idle connections across all hosts.
	MaxIdleConns int
	// MaxIdleConnsPerHost is the maximum number of idle connections kept per host.
	MaxIdleConnsPerHost int
	// MaxConnsPerHost is the maximum total number of connections allowed per host.
	MaxConnsPerHost int
	// IdleConnTimeout is the maximum duration an idle connection is kept open.
	IdleConnTimeout time.Duration
	// ResponseHeaderTimeout is the maximum duration to wait for reading response headers.
	ResponseHeaderTimeout time.Duration
}

ConnectionPoolConfig tunes the http.Transport connection pool. Apply it with Client.WithConnectionPool.

type CookieData ΒΆ

type CookieData struct {
	Name     string    `json:"name"`
	Value    string    `json:"value"`
	Domain   string    `json:"domain"`
	Path     string    `json:"path"`
	Expires  time.Time `json:"expires"`
	HTTPOnly bool      `json:"httpOnly"`
	Secure   bool      `json:"secure"`
}

CookieData holds the data for a cookie in a JSON-serializable structure compatible with standard browser automation tools.

func ExportCookies ΒΆ

func ExportCookies(jar http.CookieJar, u *url.URL) []CookieData

ExportCookies prepares cookies for loading into Playwright, Chromedp, or other automation engines.

type DNSError ΒΆ added in v0.3.0

type DNSError struct {
	// Host is the domain name that was queried for resolution.
	Host string
	// Resolver is the type of the resolver that failed (e.g., "DoH", "DoT", "InMemoryCache").
	Resolver string
	// Endpoint is the network address of the DNS server queried, if applicable.
	Endpoint string
	// Err is the underlying cause of the DNS resolution failure.
	Err error
	// IsTimeout indicates whether the failure was caused by a network timeout.
	IsTimeout bool
}

DNSError represents an error occurring during DNS resolution in the aoni package. It implements the standard error interface and can be unwrapped to retrieve the underlying network or protocol error.

func (*DNSError) Error ΒΆ added in v0.3.0

func (e *DNSError) Error() string

Error implements the standard error interface.

func (*DNSError) Temporary ΒΆ added in v0.3.0

func (e *DNSError) Temporary() bool

Temporary reports whether the error is temporary. This is required to satisfy the net.Error interface.

func (*DNSError) Timeout ΒΆ added in v0.3.0

func (e *DNSError) Timeout() bool

Timeout reports whether the error was caused by a network timeout. This allows DNSError to satisfy the net.Error interface if needed.

func (*DNSError) Unwrap ΒΆ added in v0.3.0

func (e *DNSError) Unwrap() error

Unwrap returns the underlying wrapped error.

type DNSResolver ΒΆ

type DNSResolver interface {
	LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)
}

DNSResolver resolves hostnames to IP addresses.

type Decoder ΒΆ

type Decoder interface {
	// Decode reads data from r and unmarshals it into target.
	Decode(r io.Reader, target any) error
}

Decoder decodes HTTP response bodies into target structures. Implementations include JSONDecoder, XMLDecoder, YAMLDecoder, and RawDecoder.

var JSONDecoder Decoder = DecoderFunc(func(r io.Reader, target any) error {
	return json.NewDecoder(r).Decode(target)
})

JSONDecoder parses the response body as JSON into target.

var RawDecoder Decoder = rawDecoder{}

RawDecoder reads the entire response body into a byte slice. The target must be a *[]byte.

var XMLDecoder Decoder = DecoderFunc(func(r io.Reader, target any) error {
	return xml.NewDecoder(r).Decode(target)
})

XMLDecoder parses the response body as XML into target.

var YAMLDecoder Decoder = DecoderFunc(func(r io.Reader, target any) error {
	return yaml.NewDecoder(r).Decode(target)
})

YAMLDecoder parses the response body as YAML into target.

func LimitDecoder ΒΆ added in v0.3.0

func LimitDecoder(d Decoder, maxBytes int64) Decoder

LimitDecoder wraps an existing decoder, ensuring that no more than maxBytes are read from the input stream during the decoding process. This provides protection against memory exhaustion attacks or oversized payloads.

func NewJSONDecoder ΒΆ added in v0.3.0

func NewJSONDecoder(cfg JSONDecoderConfig) Decoder

NewJSONDecoder creates a custom Decoder configured with the specified parameters.

type DecoderFunc ΒΆ

type DecoderFunc func(r io.Reader, target any) error

DecoderFunc adapts a function to the Decoder interface.

func (DecoderFunc) Decode ΒΆ

func (f DecoderFunc) Decode(r io.Reader, target any) error

Decode executes the underlying function to parse the reader into the target.

type DialWebSocketConfig ΒΆ

type DialWebSocketConfig struct {
	// ReadBufferSize sets the gorilla WebSocket read buffer (default 4096).
	ReadBufferSize int
	// WriteBufferSize sets the gorilla WebSocket write buffer (default 4096).
	WriteBufferSize int
}

DialWebSocketConfig holds optional configuration for DialWebSocket.

type DoHResolver ΒΆ

type DoHResolver struct {
	Endpoint string // IP-based URL, e.g. "https://1.1.1.1/dns-query"
	Host     string // Host header override, e.g. "cloudflare-dns.com"
	// contains filtered or unexported fields
}

DoHResolver resolves DNS via HTTPS, supporting both A and AAAA records. Uses an isolated http.Client that connects directly to the DoH server by IP, bypassing the system resolver entirely to avoid circular DNS lookups.

func NewDoHResolver ΒΆ

func NewDoHResolver(endpoint, host string) *DoHResolver

NewDoHResolver creates a DoHResolver that queries the given IP-based endpoint. The endpoint should be an IP-based URL (e.g. "https://1.1.1.1/dns-query"), and host is the Host header value (e.g. "cloudflare-dns.com").

func (*DoHResolver) LookupIPAddr ΒΆ

func (r *DoHResolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)

LookupIPAddr queries both A and AAAA records via DoH.

type DoTResolver ΒΆ

type DoTResolver struct {
	Endpoint  string // e.g. "1.1.1.1:853"
	Host      string // TLS SNI, e.g. "cloudflare-dns.com"
	Timeout   time.Duration
	TLSConfig *tls.Config
}

DoTResolver resolves DNS over TLS, querying both A and AAAA records. Uses github.com/miekg/dns for reliable DNS packet construction and parsing. If TLSConfig is nil, a default config is used with TLS 1.2 minimum version.

func NewDoTResolver ΒΆ

func NewDoTResolver(endpoint, host string) *DoTResolver

NewDoTResolver creates a DoTResolver with the specified server and TLS hostname.

func (*DoTResolver) LookupIPAddr ΒΆ

func (d *DoTResolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)

LookupIPAddr queries both A and AAAA records over TLS.

type DoerFunc ΒΆ

type DoerFunc func(req *http.Request) (*http.Response, error)

DoerFunc adapts a function to the HTTPDoer interface.

func (DoerFunc) Do ΒΆ

func (f DoerFunc) Do(req *http.Request) (*http.Response, error)

Do calls f(req).

type DynamicHedgingConfig ΒΆ added in v0.2.0

type DynamicHedgingConfig struct {
	// Tracker is the shared RTT tracker for measuring network latency.
	Tracker *RTTTracker
	// Percentile is the RTT percentile to use for delay calculation (default: 95).
	Percentile float64
	// MinDelay is the minimum hedging delay regardless of RTT (default: 50ms).
	MinDelay time.Duration
	// MaxDelay is the maximum hedging delay cap (default: 2s).
	MaxDelay time.Duration
	// Multiplier scales the percentile RTT to compute the delay (default: 1.5).
	// The dynamic delay = min(MaxDelay, max(MinDelay, p95 * Multiplier)).
	Multiplier float64
}

DynamicHedgingConfig configures the dynamic hedging delay calculation.

func DefaultDynamicHedgingConfig ΒΆ added in v0.2.0

func DefaultDynamicHedgingConfig() DynamicHedgingConfig

DefaultDynamicHedgingConfig returns sensible defaults for dynamic hedging.

func (DynamicHedgingConfig) ComputeDelay ΒΆ added in v0.2.0

func (c DynamicHedgingConfig) ComputeDelay() time.Duration

ComputeDelay calculates the dynamic hedging delay based on observed RTT data. If the tracker has insufficient samples (< 10), it returns MinDelay.

type FallbackFunc ΒΆ

type FallbackFunc func(req *http.Request, origErr error) (*http.Response, error)

FallbackFunc provides an alternate response when a request fails.

func FallbackJSON ΒΆ

func FallbackJSON(statusCode int, data any) FallbackFunc

FallbackJSON returns a FallbackFunc that responds with data serialized as JSON and the given statusCode.

func FallbackString ΒΆ added in v0.3.0

func FallbackString(statusCode int, text string) FallbackFunc

FallbackString returns a FallbackFunc that responds with plain text and the given statusCode.

type FallbackResolver ΒΆ added in v0.3.0

type FallbackResolver struct {
	// contains filtered or unexported fields
}

FallbackResolver tries to resolve hostnames using a list of resolvers sequentially. If a resolver fails, it falls back to the next one.

func NewFallbackResolver ΒΆ added in v0.3.0

func NewFallbackResolver(resolvers ...DNSResolver) *FallbackResolver

NewFallbackResolver creates a new FallbackResolver with the given prioritized resolvers.

func (*FallbackResolver) LookupIPAddr ΒΆ added in v0.3.0

func (r *FallbackResolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)

LookupIPAddr implements the DNSResolver interface by trying resolvers sequentially.

type FastRaceResolver ΒΆ added in v0.3.0

type FastRaceResolver struct {
	// contains filtered or unexported fields
}

FastRaceResolver executes multiple DNS resolutions concurrently and returns the fastest successful result, canceling all other pending queries.

func NewFastRaceResolver ΒΆ added in v0.3.0

func NewFastRaceResolver(resolvers ...DNSResolver) *FastRaceResolver

NewFastRaceResolver instantiates a concurrent FastRaceResolver.

func (*FastRaceResolver) LookupIPAddr ΒΆ added in v0.3.0

func (r *FastRaceResolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)

LookupIPAddr resolves the host by racing all configured resolvers in parallel.

type Float64String ΒΆ

type Float64String float64

Float64String parses float64 values from string representations in JSON.

func (Float64String) MarshalJSON ΒΆ added in v0.3.0

func (f Float64String) MarshalJSON() ([]byte, error)

MarshalJSON serializes the Float64String back as a JSON string representation.

func (*Float64String) UnmarshalJSON ΒΆ

func (f *Float64String) UnmarshalJSON(b []byte) error

UnmarshalJSON parses JSON byte data into the Float64String target.

type FragmentConfig ΒΆ

type FragmentConfig struct {
	ChunkSize int

	// LimitBytes specifies the maximum number of bytes to subject to fragmentation.
	// Once LimitBytes is exceeded, subsequent writes pass through seamlessly.
	// Set to -1 to fragment the entire stream.
	LimitBytes int64

	MinChunkSize int
	MaxChunkSize int

	MaxDelay time.Duration
	MinDelay time.Duration
}

FragmentConfig specifies the chunk size and inter-chunk delay for connection fragmentation.

type H2FramedTransport ΒΆ added in v0.2.0

type H2FramedTransport struct {
	*http.Transport
	// contains filtered or unexported fields
}

H2FramedTransport wraps an *http.Transport to apply HTTP/2 frame impersonation. When DialTLSContext is called, the returned connection is wrapped in [h2framedConn] so that the initial SETTINGS and PRIORITY frames match the target browser fingerprint. If orderedKeys is set, HEADERS frames are also reordered.

func NewH2FramedTransport ΒΆ added in v0.2.0

func NewH2FramedTransport(base *http.Transport, settings HTTP2Settings, orderedKeys ...string) *H2FramedTransport

NewH2FramedTransport creates an H2FramedTransport from an existing transport and HTTP/2 settings. The transport's DialTLSContext is replaced to wrap connections with browser-specific HTTP/2 frame injection.

type HTTP2Settings ΒΆ

type HTTP2Settings struct {
	HeaderTableSize      uint32
	EnablePush           uint32
	MaxConcurrentStreams uint32
	InitialWindowSize    uint32
	MaxFrameSize         uint32
	MaxHeaderListSize    uint32
	ConnectionFlow       uint32
	InitialStreamID      uint32
	PriorityStreamDep    uint32
	PriorityExclusive    bool
	PriorityWeight       uint8
}

HTTP2Settings holds the full set of HTTP/2 connection parameters for browser-grade frame impersonation. Each field maps directly to an HTTP/2 SETTINGS frame parameter or PRIORITY frame value.

func H2SettingsFromProfile ΒΆ added in v0.2.0

func H2SettingsFromProfile(s profiles.H2Settings) HTTP2Settings

H2SettingsFromProfile populates HTTP2Settings from a profiles.H2Settings.

func ParseHTTP2Settings ΒΆ added in v0.3.0

func ParseHTTP2Settings(jsonStr string) (HTTP2Settings, error)

ParseHTTP2Settings parses HTTP/2 settings from a JSON-encoded string. It supports snake_case, camelCase, and PascalCase field names, making it extremely convenient to import settings captured from Wireshark, browser developer tools, or TLS bypass scripts.

type HTTPDoer ΒΆ

type HTTPDoer interface {
	Do(req *http.Request) (*http.Response, error)
}

HTTPDoer executes an http.Request and returns a response. http.Client satisfies this interface. Pass a DoerFunc to adapt a plain function.

func Chain ΒΆ

func Chain(doer HTTPDoer, middlewares ...Middleware) HTTPDoer

Chain wraps doer with middlewares from left to right: the first middleware in the slice executes first. Returns doer unmodified when middlewares is empty.

type HealthStatus ΒΆ added in v0.3.0

type HealthStatus int

HealthStatus represents the detailed state of a tracked endpoint.

const (
	// StatusHealthy indicates the endpoint is fully functional with zero consecutive failures.
	StatusHealthy HealthStatus = iota
	// StatusDegraded indicates the endpoint is still functional but has experienced some failures.
	StatusDegraded
	// StatusUnhealthy indicates the endpoint has exceeded max failures and is currently in cooldown.
	StatusUnhealthy
	// StatusRecovering indicates the cooldown has elapsed and the endpoint is ready for a trial request.
	StatusRecovering
)

func (HealthStatus) String ΒΆ added in v0.3.0

func (s HealthStatus) String() string

String returns a human-readable representation of the HealthStatus.

type HealthTracker ΒΆ added in v0.2.0

type HealthTracker struct {
	// contains filtered or unexported fields
}

HealthTracker tracks the health state of a single endpoint (proxy or backend) using consecutive failure counting with automatic recovery after a cooldown.

func NewHealthTracker ΒΆ added in v0.2.0

func NewHealthTracker(
	name string,
	maxFails uint32,
	retryAfter time.Duration,
	onUnhealthy func(string, uint32, time.Duration),
	onRecovered func(string),
) *HealthTracker

NewHealthTracker creates a HealthTracker with the given parameters. onUnhealthy and onRecovered are called when the state changes; they may be nil.

func (*HealthTracker) CooldownRemaining ΒΆ added in v0.3.0

func (h *HealthTracker) CooldownRemaining() time.Duration

CooldownRemaining returns the time remaining in the cooldown phase. Returns 0 if the endpoint is healthy, recovering, or has no active cooldown.

func (*HealthTracker) FailCount ΒΆ added in v0.3.0

func (h *HealthTracker) FailCount() uint32

FailCount returns the current number of consecutive failures.

func (*HealthTracker) IsAvailable ΒΆ added in v0.2.0

func (h *HealthTracker) IsAvailable() bool

IsAvailable reports whether the endpoint is reachable. An unhealthy endpoint becomes available again after its recovery time elapses.

func (*HealthTracker) MarkFailed ΒΆ added in v0.2.0

func (h *HealthTracker) MarkFailed()

MarkFailed records a failure. When consecutive failures reach maxFails, the endpoint is marked unhealthy until the recovery time elapses.

func (*HealthTracker) MarkSuccess ΒΆ added in v0.2.0

func (h *HealthTracker) MarkSuccess()

MarkSuccess resets the failure counter and marks the endpoint as healthy.

func (*HealthTracker) Reset ΒΆ added in v0.3.0

func (h *HealthTracker) Reset()

Reset clears all failure counters and restores the endpoint to StatusHealthy immediately. If the endpoint was previously unhealthy, it triggers the onRecovered callback if configured.

func (*HealthTracker) Status ΒΆ added in v0.3.0

func (h *HealthTracker) Status() HealthStatus

Status evaluates and returns the precise current status of the endpoint.

type HostRewriteConfig ΒΆ

type HostRewriteConfig struct {
	Rules map[string]string
}

HostRewriteConfig holds the configuration for host rewrite.

type InMemoryDNSCache ΒΆ

type InMemoryDNSCache struct {
	// contains filtered or unexported fields
}

InMemoryDNSCache caches DNS results in memory for the configured TTL.

func NewInMemoryDNSCache ΒΆ

func NewInMemoryDNSCache(ttl time.Duration, r DNSResolver) *InMemoryDNSCache

NewInMemoryDNSCache creates a new InMemoryDNSCache with the given TTL and resolver. A background goroutine periodically evicts expired entries.

func (*InMemoryDNSCache) Close ΒΆ added in v0.2.0

func (c *InMemoryDNSCache) Close()

Close stops the background eviction goroutine.

func (*InMemoryDNSCache) LookupIPAddr ΒΆ

func (c *InMemoryDNSCache) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)

LookupIPAddr looks up the IP addresses for the given host using the cache or resolver.

type Int64String ΒΆ

type Int64String int64

Int64String parses int64 values from string representations in JSON. It safely handles raw integers, JSON null, or empty strings.

func (Int64String) MarshalJSON ΒΆ added in v0.3.0

func (i Int64String) MarshalJSON() ([]byte, error)

MarshalJSON serializes the Int64String back as a JSON string representation.

func (*Int64String) UnmarshalJSON ΒΆ

func (i *Int64String) UnmarshalJSON(b []byte) error

UnmarshalJSON parses JSON byte data into the Int64String target.

type JSONDecoderConfig ΒΆ added in v0.3.0

type JSONDecoderConfig struct {
	// DisallowUnknownFields causes the decoder to return an error if the destination
	// struct has no matching field for a key in the JSON payload.
	DisallowUnknownFields bool
	// UseNumber causes the decoder to unmarshal numbers into json.Number instead of float64.
	UseNumber bool
}

JSONDecoderConfig holds configuration parameters for creating a custom JSON decoder.

type JitterStrategy ΒΆ

type JitterStrategy int

JitterStrategy selects the algorithm for computing retry delay noise.

const (
	// JitterEqual adds +/- 10% random noise to the exponential backoff.
	JitterEqual JitterStrategy = iota
	// JitterFull picks a random duration between zero and the backoff value.
	JitterFull
)

type LoadBalancer ΒΆ

type LoadBalancer struct {
	// contains filtered or unexported fields
}

LoadBalancer distributes requests across multiple backend servers. It implements the HTTPDoer interface and can be passed to NewClient. Use NewLoadBalancer to initialize new instances.

func NewLoadBalancer ΒΆ

func NewLoadBalancer(cfg LoadBalancerConfig, backends ...string) (*LoadBalancer, error)

NewLoadBalancer initializes a new LoadBalancer with the given backends. It returns an error if the backends slice is empty. If MaxFails or RetryAfter configuration options are zero, they default to 3 and 30 seconds respectively.

func (*LoadBalancer) Close ΒΆ

func (lb *LoadBalancer) Close() error

Close stops background health check routines.

func (*LoadBalancer) Do ΒΆ

func (lb *LoadBalancer) Do(req *http.Request) (*http.Response, error)

Do executes the HTTP request across healthy backends based on the configured strategy. It clones the original request and overwrites its Scheme and Host to target the chosen backend.

If the chosen backend fails health checks, it is marked as failed. The load balancer then retries other available backends sequentially. If all backends fail, it returns an error wrapping the last encountered failure.

func (*LoadBalancer) Prewarm ΒΆ

func (lb *LoadBalancer) Prewarm(ctx context.Context)

Prewarm opens TCP/TLS connections to all registered backends by executing concurrent HEAD requests to each backend URL.

func (*LoadBalancer) Reset ΒΆ added in v0.3.0

func (lb *LoadBalancer) Reset()

Reset clears all failure counters and restores all backends to healthy states immediately.

func (*LoadBalancer) SetWeight ΒΆ added in v0.3.0

func (lb *LoadBalancer) SetWeight(backendURL string, weight int) bool

SetWeight updates the selection weight of a specific backend. Returns true if the backend was found and updated, false otherwise.

func (*LoadBalancer) Stats ΒΆ added in v0.3.0

func (lb *LoadBalancer) Stats() LoadBalancerStats

Stats evaluates and returns current health statistics of the registered backends.

func (*LoadBalancer) UpdateBackends ΒΆ

func (lb *LoadBalancer) UpdateBackends(backends ...string)

UpdateBackends replaces the entire set of active backends. It resets the selection counter to zero. If the backends slice is empty, the method returns early and makes no changes.

func (*LoadBalancer) WithClients ΒΆ

func (lb *LoadBalancer) WithClients(clients ...HTTPDoer) *LoadBalancer

WithClients applies custom HTTPDoer clients to the corresponding backends. The clients are matched to backends by slice index order. If the number of clients is different from backends, any excess clients are ignored.

type LoadBalancerConfig ΒΆ

type LoadBalancerConfig struct {
	// Strategy determines the selection algorithm for choosing a backend.
	Strategy LoadBalancingStrategy
	// MaxFails is the consecutive failure threshold before a backend is marked unhealthy.
	MaxFails uint32
	// RetryAfter is the offline cooldown duration for an unhealthy backend.
	RetryAfter time.Duration
	// HealthCheckURL is the server endpoint probed by background health checks.
	HealthCheckURL string
	// HealthCheckInterval is the period between sequential background health checks.
	HealthCheckInterval time.Duration
}

LoadBalancerConfig defines the tuning and policy settings for a LoadBalancer.

type LoadBalancerStats ΒΆ added in v0.3.0

type LoadBalancerStats struct {
	TotalBackends     int
	HealthyBackends   int
	UnhealthyBackends int
}

LoadBalancerStats provides real-time state metrics for the balanced pool.

type LoadBalancingStrategy ΒΆ

type LoadBalancingStrategy int

LoadBalancingStrategy defines the selection algorithm for backends.

const (
	// RoundRobin selects backends sequentially in a cyclic order.
	RoundRobin LoadBalancingStrategy = iota
	// Random selects backends randomly for each request.
	Random
	// WeightedRoundRobin selects backends based on their assigned weights.
	WeightedRoundRobin
)

type Logger ΒΆ

type Logger interface {
	Debug(msg string, args ...any)
	DebugContext(ctx context.Context, msg string, args ...any)
	Info(msg string, args ...any)
	InfoContext(ctx context.Context, msg string, args ...any)
	Warn(msg string, args ...any)
	WarnContext(ctx context.Context, msg string, args ...any)
	Error(msg string, args ...any)
	ErrorContext(ctx context.Context, msg string, args ...any)
}

Logger is an interface for logging messages.

type Middleware ΒΆ

type Middleware func(next HTTPDoer) HTTPDoer

Middleware wraps an HTTPDoer with additional request/response processing logic. Pass to Chain to compose multiple layers.

func AdaptiveLimitMiddleware ΒΆ

func AdaptiveLimitMiddleware(limiter *limiter.AdaptiveLimiter) Middleware

AdaptiveLimitMiddleware returns a Middleware that gates requests through limiter. Each request acquires a slot before execution and releases it afterward with the observed RTT.

func ChaosMiddleware ΒΆ

func ChaosMiddleware(cfg ChaosConfig) Middleware

ChaosMiddleware returns a Middleware that injects random latency and 503 errors. Useful for testing retry and circuit breaker logic.

func CircuitBreakerMiddleware ΒΆ

func CircuitBreakerMiddleware(cb *CircuitBreaker, isFailure func(*http.Response, error) bool) Middleware

CircuitBreakerMiddleware returns a Middleware that gates requests through cb per host. When the circuit is open the request fails immediately with an error. isFailure determines which responses count as failures; nil uses DefaultCircuitBreakerCondition.

The circuit breaker uses a sliding window: failures are tracked over CircuitBreakerConfig.Window and compared against CircuitBreakerConfig.FailureThreshold ratio.

func FallbackMiddleware ΒΆ

func FallbackMiddleware() Middleware

FallbackMiddleware returns a Middleware that invokes the FallbackFunc registered via WithFallback when the request fails with any error.

func FallbackMiddlewareEx ΒΆ

func FallbackMiddlewareEx(isFailure func(*http.Response, error) bool) Middleware

FallbackMiddlewareEx is like FallbackMiddleware but uses isFailure to decide which responses trigger the fallback. When isFailure is nil, any non-nil error triggers it.

func RateLimitMiddleware ΒΆ

func RateLimitMiddleware(rps float64, burst int) Middleware

RateLimitMiddleware returns a Middleware that blocks when the request rate exceeds rps with burst tolerance. The limiter uses a token bucket algorithm from golang.org/x/time/rate.

func RecoveryMiddleware ΒΆ

func RecoveryMiddleware(onPanic func(any)) Middleware

RecoveryMiddleware catches panics during request execution, calls onPanic with the recovered value (if non-nil), and returns an error.

func RetryMiddleware ΒΆ

func RetryMiddleware(opts RetryOptions, condition RetryCondition) Middleware

RetryMiddleware returns a Middleware that retries requests matching condition up to opts.MaxRetries times. The request body is buffered in memory so it can be replayed. The middleware respects the Retry-After header when present and falls back to exponential backoff with jitter.

type NamespaceSocket ΒΆ added in v0.2.0

type NamespaceSocket struct {
	// contains filtered or unexported fields
}

NamespaceSocket is a namespace-scoped event emitter. Obtain via SocketIOConn.OnNamespace.

func (*NamespaceSocket) Emit ΒΆ added in v0.2.0

func (ns *NamespaceSocket) Emit(event string, args ...any) error

Emit sends a Socket.IO event on this namespace. If the last argument is a func(args []json.RawMessage), it is used as an ACK callback.

func (*NamespaceSocket) EmitVolatile ΒΆ added in v0.2.0

func (ns *NamespaceSocket) EmitVolatile(event string, args ...any) error

EmitVolatile sends an event only if currently connected; silently drops otherwise.

func (*NamespaceSocket) EmitWithAck ΒΆ added in v0.2.0

func (ns *NamespaceSocket) EmitWithAck(ctx context.Context, event string, args ...any) ([]json.RawMessage, error)

EmitWithAck sends an event and blocks until the server acknowledges it or ctx expires.

func (*NamespaceSocket) On ΒΆ added in v0.2.0

func (ns *NamespaceSocket) On(event string, handler func(args []json.RawMessage))

On registers a handler for a specific event on this namespace.

func (*NamespaceSocket) OnAny ΒΆ added in v0.3.0

func (ns *NamespaceSocket) OnAny(handler func(event string, args []json.RawMessage))

OnAny registers a catch-all event listener on this specific namespace that intercepts all incoming Socket.IO events for the namespace.

type NoResponse ΒΆ

type NoResponse struct{}

NoResponse is a sentinel type used to indicate a request that does not return a response body.

type PaddingConfig ΒΆ added in v0.3.0

type PaddingConfig struct {
	// MaxSegmentSize sets the TCP Maximum Segment Size (MSS) at the socket level.
	// This forces TCP to fragment data into smaller packets, breaking static
	// packet length signatures used by DPI systems. Set to 0 to disable.
	// Typical values: 256-512 for strong fragmentation, 1024 for moderate.
	MaxSegmentSize int

	// MinPaddingBytes is the minimum number of random padding bytes added
	// to the start of the request body. A random value between MinPaddingBytes
	// and MaxPaddingBytes is chosen per request. Set both to 0 to disable padding.
	MinPaddingBytes int

	// MaxPaddingBytes is the maximum number of random padding bytes added.
	MaxPaddingBytes int

	// PaddingHeader is the name of a custom header used to carry padding data.
	// If empty and HeaderPool is empty, a default name "X-Padding" is used.
	// Ignored when HeaderPool is non-empty.
	PaddingHeader string

	// HeaderPool is a list of header names used to carry padding data.
	// On each request a random name is picked from this pool, making the
	// padding header indistinguishable from legitimate CDN or cloud tracing
	// headers. When non-empty this field takes precedence over PaddingHeader.
	HeaderPool []string
}

PaddingConfig controls MTU fragmentation and packet padding to disrupt DPI signature analysis of packet length patterns.

type ProgressFunc ΒΆ

type ProgressFunc func(current, total int64)

ProgressFunc is called periodically during response body reads. current is the bytes read so far; total is the Content-Length value or -1 if unknown.

type ProxyAwareSessionCache ΒΆ added in v0.2.0

type ProxyAwareSessionCache struct {
	// contains filtered or unexported fields
}

ProxyAwareSessionCache wraps the uTLS utls.ClientSessionCache and automatically invalidates cached TLS session tickets when the active proxy or source IP changes. This prevents server-side tracking of a client across different exit IPs via session ticket correlation.

func NewProxyAwareSessionCache ΒΆ added in v0.2.0

func NewProxyAwareSessionCache() *ProxyAwareSessionCache

NewProxyAwareSessionCache creates a new ProxyAwareSessionCache.

func (*ProxyAwareSessionCache) Clear ΒΆ added in v0.3.0

func (c *ProxyAwareSessionCache) Clear()

Clear manually flushes all currently cached TLS sessions.

func (*ProxyAwareSessionCache) CurrentProxyKey ΒΆ added in v0.2.0

func (c *ProxyAwareSessionCache) CurrentProxyKey() string

CurrentProxyKey returns the currently active proxy key.

func (*ProxyAwareSessionCache) Get ΒΆ added in v0.2.0

func (c *ProxyAwareSessionCache) Get(serverName string) (*utls.ClientSessionState, bool)

Get retrieves a cached session for the given server name. If the session was cached under a different proxy key, it returns nil to force a fresh handshake.

func (*ProxyAwareSessionCache) Put ΒΆ added in v0.2.0

func (c *ProxyAwareSessionCache) Put(serverName string, session *utls.ClientSessionState)

Put stores a TLS session ticket.

func (*ProxyAwareSessionCache) SetProxyKey ΒΆ added in v0.2.0

func (c *ProxyAwareSessionCache) SetProxyKey(key string)

SetProxyKey invalidates all cached sessions and starts a fresh session cache for the given proxy key (typically the proxy address or source IP). This ensures that when the proxy changes, no session tickets from the previous proxy are reused, preventing session correlation tracking.

type ProxyConfig ΒΆ

type ProxyConfig struct {
	// ProxyURL is the address of the proxy server (e.g. http://user:pass@ip:port).
	ProxyURL string
	// Timeout is the overall request timeout.
	Timeout time.Duration
	// InsecureSkipVerify controls whether SSL/TLS certificate verification is bypassed.
	InsecureSkipVerify bool
	// Transport overrides the default transport settings.
	Transport http.RoundTripper
	// TransportFactory creates a custom [http.RoundTripper].
	TransportFactory func(ProxyConfig) (http.RoundTripper, error)
}

ProxyConfig configures a proxy-supported HTTP client.

type ProxyIsolatedCookieJar ΒΆ

type ProxyIsolatedCookieJar struct {
	// contains filtered or unexported fields
}

ProxyIsolatedCookieJar is an isolated cookie jar that stores cookies per proxy URL. It is safe for concurrent use by multiple goroutines.

Cookie isolation works for direct requests: the proxy URL is extracted from the request context and used to select the correct per-proxy jar.

Limitation: during HTTP redirects, the standard library's http.Client calls SetCookies/Cookies without passing the request context. In this case the jar falls back to the default (empty-key) jar. This means per-proxy cookie isolation does not apply to redirect responses. In practice this is rarely an issue because proxy servers typically do not return redirects, and cookies from the target server arrive in the initial response before any redirect.

func NewProxyIsolatedCookieJar ΒΆ

func NewProxyIsolatedCookieJar() *ProxyIsolatedCookieJar

NewProxyIsolatedCookieJar creates a new ProxyIsolatedCookieJar.

func (*ProxyIsolatedCookieJar) Cookies ΒΆ

func (p *ProxyIsolatedCookieJar) Cookies(u *url.URL) []*http.Cookie

Cookies implements the http.CookieJar interface. For direct requests, uses the proxy URL from the request context. For redirects (no context available), falls back to the default jar.

func (*ProxyIsolatedCookieJar) CookiesForProxy ΒΆ added in v0.3.0

func (p *ProxyIsolatedCookieJar) CookiesForProxy(proxyURL string, u *url.URL) []*http.Cookie

CookiesForProxy manually retrieves cookies for a specific proxy URL.

func (*ProxyIsolatedCookieJar) GetJar ΒΆ added in v0.3.0

GetJar returns the cookie jar for the given context, creating it if necessary.

func (*ProxyIsolatedCookieJar) GetJarForProxy ΒΆ added in v0.3.0

func (p *ProxyIsolatedCookieJar) GetJarForProxy(proxyURL string) http.CookieJar

GetJarForProxy returns the specific http.CookieJar associated with the given proxy URL. This is a high-level helper to manage proxy cookies programmatically.

func (*ProxyIsolatedCookieJar) SetCookies ΒΆ

func (p *ProxyIsolatedCookieJar) SetCookies(u *url.URL, cookies []*http.Cookie)

SetCookies implements the http.CookieJar interface. For direct requests, uses the proxy URL from the request context. For redirects (no context available), falls back to the default jar.

func (*ProxyIsolatedCookieJar) SetCookiesForProxy ΒΆ added in v0.3.0

func (p *ProxyIsolatedCookieJar) SetCookiesForProxy(proxyURL string, u *url.URL, cookies []*http.Cookie)

SetCookiesForProxy manually stores cookies for a specific proxy URL.

type ProxyRotator ΒΆ

type ProxyRotator struct {
	// contains filtered or unexported fields
}

ProxyRotator distributes HTTP requests across a pool of proxy clients. It implements HTTPDoer and supports sticky routing, health monitoring, and dynamic pool replacement.

Create instances with NewProxyRotator.

func NewProxyRotator ΒΆ

func NewProxyRotator(config ProxyRotatorConfig, clients ...ClientWithProxy) (*ProxyRotator, error)

NewProxyRotator creates a ProxyRotator from the given config and clients. It returns an error if clients is empty. Default ProxyRotatorConfig.MaxFails is 3; default ProxyRotatorConfig.RetryAfter is 30 seconds.

func NewProxyRotatorFromStrings ΒΆ added in v0.3.0

func NewProxyRotatorFromStrings(config ProxyRotatorConfig, proxyURLs ...string) (*ProxyRotator, error)

NewProxyRotatorFromStrings creates a ProxyRotator from a list of raw proxy URL strings. It automatically instantiates standard http.Clients configured with the respective proxies. This is a high-level helper to easily set up a rotating pool from proxy list configurations.

func (*ProxyRotator) Close ΒΆ

func (r *ProxyRotator) Close() error

Close stops background routines and closes idle connections.

func (*ProxyRotator) Do ΒΆ

func (r *ProxyRotator) Do(req *http.Request) (*http.Response, error)

Do performs an HTTP request using the next available client in the pool. It attempts sticky routing first, then falls back to round-robin selection. If a client faults, it is marked unhealthy. Returns an error if all clients fail.

func (*ProxyRotator) Prewarm ΒΆ

func (r *ProxyRotator) Prewarm(ctx context.Context, targetURL string)

Prewarm opens TCP/TLS connections to targetURL through all proxy clients. It sends concurrent HEAD requests to pre-populate transport connection pools.

func (*ProxyRotator) Reset ΒΆ added in v0.3.0

func (r *ProxyRotator) Reset()

Reset clears failure states and restores all registered proxy clients to a healthy state.

func (*ProxyRotator) Stats ΒΆ added in v0.3.0

func (r *ProxyRotator) Stats() ProxyRotatorStats

Stats evaluates and returns current health statistics of the registered proxy clients.

func (*ProxyRotator) UpdateClients ΒΆ

func (r *ProxyRotator) UpdateClients(clients ...ClientWithProxy)

UpdateClients replaces the active pool and resets all session mappings.

func (*ProxyRotator) WithStickySessions ΒΆ

func (r *ProxyRotator) WithStickySessions(f StickyKeyFunc) *ProxyRotator

WithStickySessions returns a copy of r configured with the given key extractor.

type ProxyRotatorConfig ΒΆ

type ProxyRotatorConfig struct {
	// MaxFails is the consecutive error limit before a client is marked unhealthy.
	MaxFails uint32
	// RetryAfter is the duration for which an unhealthy client is kept offline.
	RetryAfter time.Duration
	// HealthCheckURL is the endpoint probed during background health checks.
	HealthCheckURL string
	// HealthCheckInterval sets the frequency of background health checks.
	HealthCheckInterval time.Duration
}

ProxyRotatorConfig configures health-checking and recovery for a ProxyRotator.

type ProxyRotatorStats ΒΆ added in v0.3.0

type ProxyRotatorStats struct {
	TotalProxies     int
	HealthyProxies   int
	UnhealthyProxies int
}

ProxyRotatorStats provides real-time state metrics for the rotating proxy pool.

type ProxyRoutedDNSResolver ΒΆ added in v0.2.0

type ProxyRoutedDNSResolver struct {
	// contains filtered or unexported fields
}

ProxyRoutedDNSResolver sends DNS queries through a proxy connection to prevent leaks.

func NewProxyRoutedDNSResolver ΒΆ added in v0.2.0

func NewProxyRoutedDNSResolver(
	resolver DNSResolver,
	proxyDial func(ctx context.Context, network, addr string) (net.Conn, error),
) *ProxyRoutedDNSResolver

NewProxyRoutedDNSResolver creates a ProxyRoutedDNSResolver that routes DNS queries through the given proxy dial function.

func (*ProxyRoutedDNSResolver) LookupIPAddr ΒΆ added in v0.2.0

func (r *ProxyRoutedDNSResolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)

LookupIPAddr resolves the host by delegating to the proxy-routed resolver.

type QUICMigrationConfig ΒΆ added in v0.2.0

type QUICMigrationConfig struct {
	// EnableMigration enables QUIC Connection Migration (default: true).
	// When enabled, the client can survive IP address changes without renegotiating.
	EnableMigration bool
	// KeepAlivePeriod sends periodic keepalive packets to maintain the connection
	// during network transitions. Set to 0 to disable (default: 15s).
	KeepAlivePeriod time.Duration
	// MaxIdleTimeout is the maximum duration without network activity before
	// the connection is closed. Longer values allow more time for migration
	// but consume resources (default: 30s).
	MaxIdleTimeout time.Duration
	// DisablePathMTUDiscovery disables Path MTU Discovery during migration.
	// Disable if the network path is unreliable (default: false).
	DisablePathMTUDiscovery bool
	// InitialPacketSize sets the initial QUIC packet size (default: 1200).
	// Lower values improve compatibility with restrictive networks.
	InitialPacketSize uint16
}

QUICMigrationConfig controls QUIC Connection Migration for HTTP/3. Migration lets a QUIC connection survive network interface changes (e.g. Wi-Fi to cellular) by tracking connection IDs instead of IP:port tuples. See DefaultQUICMigrationConfig.

func DefaultQUICMigrationConfig ΒΆ added in v0.2.0

func DefaultQUICMigrationConfig() QUICMigrationConfig

DefaultQUICMigrationConfig returns a QUICMigrationConfig with production-ready defaults.

type RTTTracker ΒΆ added in v0.2.0

type RTTTracker struct {
	// contains filtered or unexported fields
}

RTTTracker maintains a sliding window of RTT measurements and computes percentile-based values (p95, p99) for dynamic hedging delay calculation. It is safe for concurrent use.

func NewRTTTracker ΒΆ added in v0.2.0

func NewRTTTracker(capacity int) *RTTTracker

NewRTTTracker creates an RTTTracker with the given sample window capacity. A larger capacity provides more stable estimates but reacts slower to changes. A capacity of 100 is recommended for most use cases.

func (*RTTTracker) AverageRTT ΒΆ added in v0.3.0

func (t *RTTTracker) AverageRTT() time.Duration

AverageRTT returns the simple mathematical average (mean) of all recorded RTT samples. Returns 0 if no samples are recorded.

func (*RTTTracker) Count ΒΆ added in v0.2.0

func (t *RTTTracker) Count() int

Count returns the number of recorded samples.

func (*RTTTracker) MaxRTT ΒΆ added in v0.3.0

func (t *RTTTracker) MaxRTT() time.Duration

MaxRTT returns the maximum observed RTT within the current sliding window. Returns 0 if no samples are recorded.

func (*RTTTracker) MinRTT ΒΆ added in v0.2.0

func (t *RTTTracker) MinRTT() time.Duration

MinRTT returns the minimum observed RTT.

func (*RTTTracker) P95 ΒΆ added in v0.2.0

func (t *RTTTracker) P95() time.Duration

P95 returns the 95th percentile RTT.

func (*RTTTracker) P99 ΒΆ added in v0.2.0

func (t *RTTTracker) P99() time.Duration

P99 returns the 99th percentile RTT.

func (*RTTTracker) Percentile ΒΆ added in v0.2.0

func (t *RTTTracker) Percentile(p float64) time.Duration

Percentile returns the given percentile (0-100) of recorded RTT samples. Returns 0 if no samples are recorded.

func (*RTTTracker) Record ΒΆ added in v0.2.0

func (t *RTTTracker) Record(rtt time.Duration)

Record adds an RTT measurement to the tracker.

func (*RTTTracker) Reset ΒΆ added in v0.3.0

func (t *RTTTracker) Reset()

Reset clears all recorded RTT samples and resets the metrics.

func (*RTTTracker) SmoothedRTT ΒΆ added in v0.2.0

func (t *RTTTracker) SmoothedRTT() time.Duration

SmoothedRTT returns the exponentially smoothed RTT (EWMA).

type ReplayableBody ΒΆ

type ReplayableBody interface {
	io.ReadCloser
	Reset()
}

ReplayableBody represents a response stream that can be reset to the beginning for re-reading (for example, after previewing or logging).

func AsReplayable ΒΆ

func AsReplayable(rc io.ReadCloser) ReplayableBody

AsReplayable turns any io.ReadCloser into a ReplayableBody. If there's already a high-performance buffer (multiReadBody) under the hood, it will return it. If not, it will transparently create a lightweight in-memory buffer for repeated reading.

type RequestModifier ΒΆ

type RequestModifier = generic.Option[*http.Request]

RequestModifier represents a function that alters an http.Request before execution.

func AppendHostRewrite ΒΆ added in v0.3.0

func AppendHostRewrite(rules map[string]string) RequestModifier

AppendHostRewrite returns a RequestModifier that appends new host rewrite rules to the existing HostRewriteConfig in the request context, or creates a new one if none are present.

func AsCurl ΒΆ

func AsCurl() RequestModifier

AsCurl returns a RequestModifier that dumps the equivalent curl command to stderr.

func CaptureResponse ΒΆ

func CaptureResponse(target **http.Response) RequestModifier

CaptureResponse stores the final http.Response pointer in target after the request completes. Useful for inspecting headers or status codes in middleware hooks.

func ContextModifiers ΒΆ added in v0.2.0

func ContextModifiers(ctx context.Context) []RequestModifier

ContextModifiers extracts the RequestModifiers previously stored via WithContextModifier. Returns nil if none are present.

func Debug ΒΆ

func Debug() RequestModifier

Debug returns a RequestModifier that tags the request for verbose logging. The Client must have a Logger set via Client.WithLogger for output to appear.

func Trace ΒΆ

func Trace(target *TraceInfo) RequestModifier

Trace returns a RequestModifier that registers a connection tracer on the active request. Timing metrics are populated inside the provided TraceInfo structure.

func TraceContext ΒΆ added in v0.3.0

func TraceContext() RequestModifier

TraceContext returns a RequestModifier that attaches a new TraceInfo to the request context. This allows developers to retrieve network timing and JA4/JA4H fingerprints using ResponseTrace after the request finishes.

func TraceJA4 ΒΆ

func TraceJA4(target *TraceInfo) RequestModifier

TraceJA4 returns a RequestModifier that populates the JA4 field of the provided TraceInfo. It sets up a shared store in the request context so that Client.WithTLSFingerprint can write the TLS fingerprint during the handshake, and computes the HTTP fingerprint from request headers.

The JA4 report is fully populated after the request completes. The TLS fingerprint (JA4) requires Client.WithTLSFingerprint to be enabled.

Use this modifier alongside Trace for complete timing and fingerprint data:

info := &aoni.TraceInfo{}
client.Get(ctx, "/path", aoni.Trace(info), aoni.TraceJA4(info))
// After request: info.JA4 contains both JA4 and JA4H

func WithALPN ΒΆ

func WithALPN(protocols []string) RequestModifier

WithALPN returns a RequestModifier that sets custom ALPN protocols.

func WithAccept ΒΆ

func WithAccept(accept string) RequestModifier

WithAccept overrides the standard Accept header field.

func WithBasicAuth ΒΆ

func WithBasicAuth(username, password string) RequestModifier

WithBasicAuth applies Basic Authorization credentials.

func WithBearer ΒΆ

func WithBearer(token string) RequestModifier

WithBearer applies a Bearer Token authorization header.

func WithBody ΒΆ

func WithBody(r io.Reader) RequestModifier

WithBody replaces the request body stream with the provided reader.

func WithContentType ΒΆ

func WithContentType(ct string) RequestModifier

WithContentType overrides the standard Content-Type header field.

func WithCookie ΒΆ

func WithCookie(c *http.Cookie) RequestModifier

WithCookie attaches a single cookie to the request.

func WithCookies ΒΆ

func WithCookies(kv map[string]string) RequestModifier

WithCookies attaches multiple cookies from a key-value map.

func WithDecoder ΒΆ

func WithDecoder(d Decoder) RequestModifier

WithDecoder overrides the response Decoder for this request. The client-level decoder set via Client.WithBaseResponse is ignored when this modifier is present.

func WithDownloadProgress ΒΆ

func WithDownloadProgress(onProgress ProgressFunc) RequestModifier

WithDownloadProgress registers onProgress to be called during response body reads. The callback fires with the bytes-read total and the Content-Length value.

func WithErrorModel ΒΆ

func WithErrorModel(target any) RequestModifier

WithErrorModel tells Client.Request to deserialize non-2xx response bodies into target. Inspect the result with errors.As against APIError.

func WithFallback ΒΆ

func WithFallback(f FallbackFunc) RequestModifier

WithFallback returns a RequestModifier that registers f as the fallback for this request. See FallbackMiddleware.

func WithForceHTTP1 ΒΆ

func WithForceHTTP1() RequestModifier

WithForceHTTP1 returns a RequestModifier that advertises only http/1.1 in ALPN, preventing the server from upgrading to HTTP/2.

func WithForceHTTP2 ΒΆ

func WithForceHTTP2() RequestModifier

WithForceHTTP2 returns a RequestModifier that advertises only h2 in ALPN, forcing the server to use HTTP/2.

func WithFragmentation ΒΆ

func WithFragmentation(cfg FragmentConfig) RequestModifier

WithFragmentation returns a RequestModifier that sets fragmentation configuration on the request context.

func WithHeader ΒΆ

func WithHeader(key, value string) RequestModifier

WithHeader sets the key header field to the given value.

func WithHedging ΒΆ

func WithHedging(delay time.Duration) RequestModifier

WithHedging overrides the client-level hedging delay for this request. A duration <= 0 disables hedging for the request.

func WithHostRewrite ΒΆ

func WithHostRewrite(rules map[string]string) RequestModifier

WithHostRewrite returns a RequestModifier that rewrites the host header based on the provided rules.

func WithJSONBody ΒΆ

func WithJSONBody(payload any) RequestModifier

WithJSONBody serializes payload as JSON, sets the request body, and adds a Content-Type: application/json header. Marshaling errors are stored in the request context and retrievable via the body error hook.

func WithJSONDecoder ΒΆ added in v0.3.0

func WithJSONDecoder() RequestModifier

WithJSONDecoder returns a RequestModifier that uses JSONDecoder.

func WithMultiReadBody ΒΆ

func WithMultiReadBody(threshold int64) RequestModifier

WithMultiReadBody returns a RequestModifier that overrides the body caching threshold for a single request. Responses smaller than threshold are buffered in memory so the body can be read multiple times. A value <= 0 disables caching for the request.

func WithMultipart ΒΆ

func WithMultipart(fields map[string]string, files map[string]io.Reader) RequestModifier

WithMultipart builds a multipart/form-data body from fields and files, sets Content-Length and Content-Type (with boundary). Encoding errors are stored in the request context and retrievable via the body error hook (same as WithJSONBody).

func WithOrderedHeaders ΒΆ

func WithOrderedHeaders(order []string) RequestModifier

WithOrderedHeaders sets the header serialization order for this HTTP/1.1 request. For HTTP/2, use H2FramedTransport instead.

func WithOrigin ΒΆ

func WithOrigin(origin string) RequestModifier

WithOrigin overrides the standard Origin header field.

func WithP0fSignature ΒΆ

func WithP0fSignature(sig *p0f.Signature) RequestModifier

WithP0fSignature returns a RequestModifier that stores a p0f signature in the request context. When used with Client.WithP0fSignature, the TCP/IP fields (TTL, DF, window size) are spoofed to match the specified OS.

func WithPadding ΒΆ added in v0.3.0

func WithPadding(cfg PaddingConfig) RequestModifier

WithPadding returns a RequestModifier that adds random packet padding headers to the request matching the given PaddingConfig. This is a high-level helper to apply individual padding settings per request.

func WithQuery ΒΆ

func WithQuery(query any) RequestModifier

WithQuery encodes a struct or map as URL query parameters and appends them to the request URL. It safely checks for validation errors using Validate and serialization failures. Any encountered errors are saved to the request context via queryErrorCtxKey. Existing query parameters in the URL are preserved and merged with the new values.

func WithRawDecoder ΒΆ added in v0.3.0

func WithRawDecoder() RequestModifier

WithRawDecoder returns a RequestModifier that uses RawDecoder.

func WithStreamingMultipart ΒΆ

func WithStreamingMultipart(fields map[string]string, files map[string]io.Reader) RequestModifier

WithStreamingMultipart builds a multipart/form-data body using an io.Pipe so that file data is streamed rather than buffered in memory. Content-Length is not set because the total size is unknown until writing completes.

func WithUploadProgress ΒΆ

func WithUploadProgress(onProgress ProgressFunc) RequestModifier

WithUploadProgress wraps the request body with a [progressReader] that calls onProgress during reads. The total parameter is Content-Length or -1 when unknown.

func WithUserAgent ΒΆ

func WithUserAgent(ua string) RequestModifier

WithUserAgent overrides the standard User-Agent header field.

func WithVar ΒΆ

func WithVar(key string, value any) RequestModifier

WithVar replaces a single placeholder (e.g. "{key}") in the path with an escaped value.

func WithVars ΒΆ

func WithVars(pairs ...any) RequestModifier

WithVars replaces multiple placeholder keys in the path with their respective values. It accepts alternating key-value arguments. If the argument list has an odd length, it returns early and performs no replacements.

func WithXMLDecoder ΒΆ added in v0.3.0

func WithXMLDecoder() RequestModifier

WithXMLDecoder returns a RequestModifier that uses XMLDecoder.

func WithYAMLDecoder ΒΆ added in v0.3.0

func WithYAMLDecoder() RequestModifier

WithYAMLDecoder returns a RequestModifier that uses YAMLDecoder.

type Requester ΒΆ

type Requester interface {
	Request(
		ctx context.Context,
		method, path string,
		mods ...RequestModifier,
	) (*http.Response, error)
}

Requester sends an HTTP request and returns the response. Client is the primary implementation. Relative paths are resolved against the base URL. Request modifiers are applied before execution.

type RetryCondition ΒΆ

type RetryCondition func(resp *http.Response, err error) bool

RetryCondition reports whether a failed request should be retried.

func And ΒΆ added in v0.3.0

func And(conditions ...RetryCondition) RetryCondition

And combines multiple RetryCondition functions into a single condition that returns true if ALL of the underlying conditions return true.

func Or ΒΆ added in v0.3.0

func Or(conditions ...RetryCondition) RetryCondition

Or combines multiple RetryCondition functions into a single condition that returns true if ANY of the underlying conditions return true.

func ProxyRetryCondition ΒΆ

func ProxyRetryCondition(rotator *ProxyRotator) RetryCondition

ProxyRetryCondition returns a RetryCondition that retries when rotator considers the response or error a proxy fault.

func RetryOnErr ΒΆ

func RetryOnErr() RetryCondition

RetryOnErr returns a RetryCondition that retries on any non-nil error.

func RetryOnGatewayErrors ΒΆ

func RetryOnGatewayErrors() RetryCondition

RetryOnGatewayErrors returns a RetryCondition that retries on HTTP 502, 503, and 504 status codes.

func RetryOnRateLimit ΒΆ

func RetryOnRateLimit() RetryCondition

RetryOnRateLimit returns a RetryCondition that retries on HTTP 429.

func RetryOnTransientErrors ΒΆ

func RetryOnTransientErrors() RetryCondition

RetryOnTransientErrors returns a RetryCondition that retries on network errors, connection resets, and broken pipes.

type RetryOptions ΒΆ

type RetryOptions struct {
	// MaxRetries is the total number of attempts (1 = no retries).
	MaxRetries uint32

	// Backoff is the delay before the first retry. Subsequent retries
	// use exponential backoff starting from this value.
	Backoff time.Duration

	// JitterStrategy selects the noise algorithm applied to each delay.
	JitterStrategy JitterStrategy

	// OnRetry is an optional callback executed before each sleep during retry attempts.
	// Provides the attempt count (1-based), the causing error or nil, and the planned backoff delay.
	OnRetry func(attempt uint32, err error, delay time.Duration)
}

RetryOptions configures RetryMiddleware.

type SSEEvent ΒΆ

type SSEEvent struct {
	// Event is the event identifier string.
	Event string
	// Data is the data payload buffer string.
	Data string
	// ID is the unique event tracking ID.
	ID string
	// Retry is the reconnection timeout value in milliseconds.
	Retry int
}

SSEEvent holds the parsed fields of a Server-Sent Event.

type SocketIOConfig ΒΆ added in v0.2.0

type SocketIOConfig struct {
	// Reconnection controls automatic reconnection on unexpected disconnect.
	Reconnection bool
	// ReconnectionAttempts is the maximum number of reconnection attempts.
	// 0 means unlimited.
	ReconnectionAttempts int
	// ReconnectionDelay is the initial delay before the first reconnection attempt.
	// Default: 1s.
	ReconnectionDelay time.Duration
	// ReconnectionDelayMax is the upper bound for reconnection delay.
	// Default: 30s.
	ReconnectionDelayMax time.Duration
	// JitterFactor controls random delay variation (0..1). Default: 0.5.
	JitterFactor float64

	// Backoff allows you to set a custom algorithm for calculating delays.
	// If nil, the standard exponential backoff is used.
	Backoff BackoffStrategy

	// ConnectTimeout is the timeout for the full connection handshake (WS + EIO + SIO).
	// Default: 20s.
	ConnectTimeout time.Duration
	// PingTimeout is the maximum time to wait for a pong after sending a ping.
	// Default: 20s.
	PingTimeout time.Duration

	// Namespace is the Socket.IO namespace to connect to. Default: "/".
	Namespace string
	// Auth is the authentication payload sent in the SIO CONNECT packet.
	Auth any
}

SocketIOConfig holds all configurable parameters for a Socket.IO connection. Zero values mean "use default". Passing a zero-valued config is safe.

type SocketIOConn ΒΆ added in v0.2.0

type SocketIOConn struct {
	// contains filtered or unexported fields
}

SocketIOConn provides support for working with Socket.IO v5 / Engine.IO v4 servers. Supports event-based communication, namespace multiplexing, acknowledgements, binary data, and automatic reconnection.

func DialSocketIO ΒΆ added in v0.2.0

func DialSocketIO(
	ctx context.Context,
	c *Client,
	targetURL string,
	config SocketIOConfig,
	mods ...RequestModifier,
) (*SocketIOConn, error)

DialSocketIO connects to a Socket.IO v5 server via the aoni WebSocket pipeline, performs the Engine.IO v4 handshake and Socket.IO v5 CONNECT, and starts background workers for heartbeats and packet reading.

func NewSocketIOConn ΒΆ added in v0.3.0

func NewSocketIOConn(ctx context.Context, conn net.Conn, config SocketIOConfig) (*SocketIOConn, error)

NewSocketIOConn initializes the Engine.IO v4 and Socket.IO v5 protocols over any existing net.Conn network connection.

func (*SocketIOConn) Close ΒΆ added in v0.2.0

func (s *SocketIOConn) Close() error

Close sends a Socket.IO DISCONNECT and Engine.IO CLOSE, then shuts down the connection. Reconnection is suppressed.

func (*SocketIOConn) Connected ΒΆ added in v0.2.0

func (s *SocketIOConn) Connected() bool

Connected reports whether the connection is currently open.

func (*SocketIOConn) Emit ΒΆ added in v0.2.0

func (s *SocketIOConn) Emit(event string, args ...any) error

Emit sends a Socket.IO event on the default namespace. If the last argument is func(args []json.RawMessage), it is used as an ACK callback.

func (*SocketIOConn) EmitVolatile ΒΆ added in v0.2.0

func (s *SocketIOConn) EmitVolatile(event string, args ...any) error

EmitVolatile sends an event only if currently connected; silently drops otherwise.

func (*SocketIOConn) EmitWithAck ΒΆ added in v0.2.0

func (s *SocketIOConn) EmitWithAck(ctx context.Context, event string, args ...any) ([]json.RawMessage, error)

EmitWithAck sends an event on the default namespace and blocks until the server acknowledges it or ctx expires.

func (*SocketIOConn) On ΒΆ added in v0.2.0

func (s *SocketIOConn) On(event string, handler func(args []json.RawMessage))

On registers a handler for a specific Socket.IO event on the default namespace.

func (*SocketIOConn) OnAny ΒΆ added in v0.3.0

func (s *SocketIOConn) OnAny(handler func(event string, args []json.RawMessage))

OnAny registers a catch-all event listener on the default namespace that intercepts all incoming Socket.IO events.

func (*SocketIOConn) OnClose ΒΆ added in v0.2.0

func (s *SocketIOConn) OnClose(handler func())

OnClose sets the callback invoked when the connection closes.

func (*SocketIOConn) OnNamespace ΒΆ added in v0.2.0

func (s *SocketIOConn) OnNamespace(nsp string) *NamespaceSocket

OnNamespace returns a NamespaceSocket scoped to the given namespace.

func (*SocketIOConn) OnReconnectFailed ΒΆ added in v0.2.0

func (s *SocketIOConn) OnReconnectFailed(handler func())

OnReconnectFailed sets the callback invoked when all reconnection attempts are exhausted.

func (*SocketIOConn) OnReconnected ΒΆ added in v0.2.0

func (s *SocketIOConn) OnReconnected(handler func())

OnReconnected sets the callback invoked after a successful reconnection.

func (*SocketIOConn) OnReconnecting ΒΆ added in v0.2.0

func (s *SocketIOConn) OnReconnecting(handler func(attempt int))

OnReconnecting sets the callback invoked before each reconnection attempt.

func (*SocketIOConn) ReconnectionAttempts ΒΆ added in v0.3.0

func (s *SocketIOConn) ReconnectionAttempts() int

ReconnectionAttempts returns the current consecutive reconnection attempt count.

func (*SocketIOConn) SID ΒΆ added in v0.2.0

func (s *SocketIOConn) SID() string

SID returns the server-assigned session ID.

type SourceIPRotator ΒΆ

type SourceIPRotator struct {
	// contains filtered or unexported fields
}

SourceIPRotator is a struct that holds a pool of source IP addresses and rotates between them.

func NewSourceIPRotator ΒΆ

func NewSourceIPRotator(addrs []string) (*SourceIPRotator, error)

NewSourceIPRotator creates a new SourceIPRotator with the given IP addresses.

func (*SourceIPRotator) IPs ΒΆ added in v0.3.0

func (r *SourceIPRotator) IPs() []net.IP

IPs returns a safe copy of the current IP pool addresses.

func (*SourceIPRotator) Next ΒΆ

func (r *SourceIPRotator) Next() net.IP

Next returns the next IP address in the pool and rotates to the next one.

func (*SourceIPRotator) NextForFamily ΒΆ added in v0.3.0

func (r *SourceIPRotator) NextForFamily(isIPv4 bool) net.IP

NextForFamily returns the next IP address in the pool that matches the requested IP family (IPv4 if isIPv4 is true, IPv6 otherwise). Returns nil if no matching IP address family is found in the current pool.

func (*SourceIPRotator) Size ΒΆ added in v0.3.0

func (r *SourceIPRotator) Size() int

Size returns the total number of IP addresses currently registered in the pool.

func (*SourceIPRotator) UpdatePool ΒΆ added in v0.3.0

func (r *SourceIPRotator) UpdatePool(addrs []string) error

UpdatePool dynamically replaces the IP addresses in the pool on the fly. Resets the rotation index to 0. Returns an error if the new list is empty or invalid.

type StaticResolver ΒΆ added in v0.3.0

type StaticResolver struct {
	// contains filtered or unexported fields
}

StaticResolver allows overriding DNS lookups with static IP mappings. If a queried host is not registered in the static map, it delegates the lookup to the next fallback resolver.

func NewStaticResolver ΒΆ added in v0.3.0

func NewStaticResolver(mapping map[string][]string, delegate DNSResolver) *StaticResolver

NewStaticResolver creates a new StaticResolver with the given IP mapping and delegate.

func (*StaticResolver) LookupIPAddr ΒΆ added in v0.3.0

func (r *StaticResolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)

LookupIPAddr implements the DNSResolver interface.

type StdlibResolver ΒΆ

type StdlibResolver struct {
	Resolver *net.Resolver
}

StdlibResolver delegates DNS resolution to the system resolver via net.Resolver.

func NewStdlibResolver ΒΆ

func NewStdlibResolver() *StdlibResolver

NewStdlibResolver creates a StdlibResolver with the default resolver.

func (*StdlibResolver) LookupIPAddr ΒΆ

func (r *StdlibResolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)

LookupIPAddr delegates to the underlying net.Resolver.

type StickyKeyFunc ΒΆ

type StickyKeyFunc func(req *http.Request) string

StickyKeyFunc extracts a session identifier from a request for sticky routing. Return an empty string to fall back to round-robin rotation.

func StickyKeyFromCookie ΒΆ added in v0.2.0

func StickyKeyFromCookie(cookieName string) StickyKeyFunc

StickyKeyFromCookie returns a function to extract the key from a specific cookie.

func StickyKeyFromHeader ΒΆ added in v0.2.0

func StickyKeyFromHeader(headerName string) StickyKeyFunc

StickyKeyFromHeader returns a function to extract the key from the HTTP header.

type StreamResponse ΒΆ

type StreamResponse struct {
	// contains filtered or unexported fields
}

StreamResponse wraps an http.Response and manages connection reading streams. Callers are responsible for calling StreamResponse.Close after read operations complete.

func Stream ΒΆ

func Stream(
	ctx context.Context,
	c Requester,
	path string,
	mods ...RequestModifier,
) (*StreamResponse, error)

Stream executes a GET request and returns the resulting connection body as StreamResponse. Callers must ensure the returned stream is closed when done.

func StreamWithBody ΒΆ

func StreamWithBody(
	ctx context.Context,
	c Requester,
	method, path string,
	body io.Reader,
	mods ...RequestModifier,
) (*StreamResponse, error)

StreamWithBody executes an HTTP request with the provided body and returns a raw StreamResponse.

func (*StreamResponse) Close ΒΆ

func (s *StreamResponse) Close() error

Close closes the underlying network response body stream.

func (*StreamResponse) ContentLength ΒΆ

func (s *StreamResponse) ContentLength() int64

ContentLength returns the response body content length, or -1 if unknown.

func (*StreamResponse) ContentType ΒΆ

func (s *StreamResponse) ContentType() string

ContentType returns the Content-Type header field value.

func (*StreamResponse) Read ΒΆ

func (s *StreamResponse) Read(p []byte) (n int, err error)

Read reads connection body data into p.

func (*StreamResponse) Response ΒΆ

func (s *StreamResponse) Response() *http.Response

Response returns the underlying raw http.Response structure.

func (*StreamResponse) StatusCode ΒΆ

func (s *StreamResponse) StatusCode() int

StatusCode returns the HTTP status code of the response.

type TraceInfo ΒΆ

type TraceInfo struct {
	// DNSLookup records the time spent resolving the server's IP address.
	DNSLookup time.Duration

	// TCPConn records the time spent establishing the TCP connection.
	TCPConn time.Duration

	// TLSHandshake records the time spent completing the SSL/TLS handshake.
	TLSHandshake time.Duration

	// ServerProcessing records the time from connection establishment to receiving the first response byte.
	ServerProcessing time.Duration

	// ContentTransfer records the time spent transferring the response body data.
	ContentTransfer time.Duration

	// Total records the total execution time for the request.
	Total time.Duration

	// RequestSize records the request payload size in bytes.
	RequestSize int64

	// ResponseSize records the response payload size in bytes.
	ResponseSize int64

	// RemoteAddr holds the IP address and port of the remote server connected to.
	RemoteAddr string

	// JA4 holds the JA4 fingerprints computed during the request.
	// Populated only when [TraceJA4] is used as a request modifier.
	JA4 *ja4.Report
}

TraceInfo records network layer timing metrics for a request. Timing fields are fully populated only after the response body is completely read.

func ResponseTrace ΒΆ added in v0.3.0

func ResponseTrace(resp *http.Response) *TraceInfo

ResponseTrace extracts the TraceInfo previously captured via TraceContext. Returns nil if no trace was registered on the request.

func (*TraceInfo) Start ΒΆ added in v0.3.0

func (t *TraceInfo) Start() func(resp *http.Response)

Start begins tracking total and content transfer timings. It returns a completion function that should be called once the response body has been completely read and closed.

type Transport ΒΆ added in v0.3.0

type Transport struct {

	// BeforeRoundTrip is an optional lifecycle hook executed immediately before
	// the request is dispatched through the aoni engine.
	// It receives the cloned, pre-configured [Client] and the original request,
	// and must return the final [Client] to be used. This allows flexible,
	// dynamic transport-level adjustments (such as adding headers, configuring
	// authentication, or overriding client settings dynamically).
	BeforeRoundTrip func(cloned *Client, origReq *http.Request) *Client
	// contains filtered or unexported fields
}

Transport implements http.RoundTripper by routing requests through a configured aoni Client pipeline.

Custom X-Aoni Headers ΒΆ

Transport supports declarative configuration of outbound requests via specialized request headers. This provides a clean way to integrate advanced transport features (like TLS fingerprints, proxy routing, or security policies) into standard HTTP clients or third-party SDKs (such as pocketbase-go, Supabase, or Resty) that allow header customization but lack direct access to context modifiers.

These internal headers are parsed dynamically during RoundTrip, applied to the cloned request's Client configuration, and fully stripped from the outgoing request. The remote server will never see these configuration headers.

Supported headers:

  • X-Aoni-Proxy: Sets the proxy URL for the current request. Format: A standard URL string (e.g. "http://user:pass@127.0.0.1:8080" or "socks5://127.0.0.1:1080").

  • X-Aoni-TLS-Fingerprint: Selects a uTLS browser client profile to bypass passive TLS fingerprinting. Values: "chrome", "firefox", "safari", "none".

  • X-Aoni-Timeout: Sets a request-specific timeout. Format: A duration string parsable by time.ParseDuration (e.g. "10s", "500ms").

  • X-Aoni-SSRF-Guard: Protects the application by blocking connection attempts to private and loopback IPs. Values: "true", "1".

  • X-Aoni-Max-Response-Size: Protects against decompression bombs by setting a maximum response body size limit. Format: Integer size in bytes (e.g. "1048576" for 1 MB).

func NewTransport ΒΆ added in v0.3.0

func NewTransport(c *Client) *Transport

NewTransport returns a new http.RoundTripper (specifically *Transport) configured to route all requests through the provided aoni Client. This allows developers to integrate aoni's advanced transport features into existing http.Client instances simply by swapping the Transport field.

func (*Transport) RoundTrip ΒΆ added in v0.3.0

func (t *Transport) RoundTrip(origReq *http.Request) (*http.Response, error)

RoundTrip extracts modifiers from the request context, applies them to the request, and delegates to the full aoni pipeline (SSRF guard, Happy Eyeballs, uTLS/JA4, middleware, proxy rotation, decompression, etc.).

In accordance with standard http.RoundTripper requirements, it returns errors wrapped as *url.Error.

type Uint64String ΒΆ

type Uint64String uint64

Uint64String parses uint64 values from string representations in JSON. It safely handles raw integers, JSON null, or empty strings.

func (Uint64String) MarshalJSON ΒΆ added in v0.3.0

func (u Uint64String) MarshalJSON() ([]byte, error)

MarshalJSON serializes the Uint64String back as a JSON string representation.

func (*Uint64String) UnmarshalJSON ΒΆ

func (u *Uint64String) UnmarshalJSON(b []byte) error

UnmarshalJSON parses JSON byte data into the Uint64String target.

type UnixTimestamp ΒΆ

type UnixTimestamp time.Time

UnixTimestamp parses Unix timestamps from strings or numbers in JSON.

func (UnixTimestamp) MarshalJSON ΒΆ added in v0.3.0

func (t UnixTimestamp) MarshalJSON() ([]byte, error)

MarshalJSON serializes the UnixTimestamp back as a numeric Unix epoch timestamp.

func (UnixTimestamp) Time ΒΆ

func (t UnixTimestamp) Time() time.Time

Time returns the time.Time value.

func (*UnixTimestamp) UnmarshalJSON ΒΆ

func (t *UnixTimestamp) UnmarshalJSON(b []byte) error

UnmarshalJSON implements json.Unmarshaler.

type Unwrapper ΒΆ

type Unwrapper interface {
	Unwrap() Requester
}

Unwrapper allows nested decorators to be peeled away to reach the underlying Requester. Client does not implement this interface; wrapper types returned by NewStdClient or Chain do.

type ValidationError ΒΆ

type ValidationError struct {
	Field string
}

ValidationError reports that a required field was missing or invalid during request validation. Inspect with errors.As to access Field.

func (*ValidationError) Error ΒΆ

func (e *ValidationError) Error() string

Error returns a human-readable description of the validation failure.

type WebSocketConn ΒΆ added in v0.3.0

type WebSocketConn interface {
	net.Conn
	// ReadMessage считываСт ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅ сообщСниС ΠΈΠ· соСдинСния, возвращая Π΅Π³ΠΎ Ρ‚ΠΈΠΏ
	// (TextMessage ΠΈΠ»ΠΈ BinaryMessage) ΠΈ ΠΏΠΎΠ»Π΅Π·Π½ΡƒΡŽ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ.
	ReadMessage() (messageType int, p []byte, err error)
	// WriteMessage отправляСт сообщСниС ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° (TextMessage ΠΈΠ»ΠΈ BinaryMessage).
	WriteMessage(messageType int, data []byte) error
	// UnderlyingConn Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π½ΠΈΠ·ΠΊΠΎΡƒΡ€ΠΎΠ²Π½Π΅Π²Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ соСдинСния (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, *websocket.Conn ΠΈΠ»ΠΈ http2 stream).
	UnderlyingConn() any
	// CloseChan Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΊΠ°Π½Π°Π», Π·Π°ΠΊΡ€Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉΡΡ ΠΏΡ€ΠΈ Ρ€Π°Π·Ρ€Ρ‹Π²Π΅ соСдинСния.
	CloseChan() <-chan struct{}
}

WebSocketConn represents an active WebSocket connection. It extends the net.Conn interface, allowing the connection to be used with standard Go abstractions, while simultaneously providing direct access to reading/writing typed WebSocket messages (Text/Binary), receiving the low-level socket and monitoring channel closure.

Directories ΒΆ

Path Synopsis
examples
01_basic_get command
Example: Basic GET request with typed JSON response.
Example: Basic GET request with typed JSON response.
02_path_and_query command
Example: Path variables and query parameters.
Example: Path variables and query parameters.
03_post_json command
Example: POST with JSON body and custom error model.
Example: POST with JSON body and custom error model.
04_headers_auth command
Example: Bearer token, Basic auth, and custom headers.
Example: Bearer token, Basic auth, and custom headers.
05_error_handling command
Example: Error handling with APIError, ErrCloudflareChallenge, and status codes.
Example: Error handling with APIError, ErrCloudflareChallenge, and status codes.
06_proxy_rotation command
Example: Proxy rotation with sticky sessions and retry middleware.
Example: Proxy rotation with sticky sessions and retry middleware.
07_retry_middleware command
Example: Retry middleware with RetryOptions and retry conditions.
Example: Retry middleware with RetryOptions and retry conditions.
08_circuit_breaker command
Example: Circuit breaker middleware.
Example: Circuit breaker middleware.
09_tracing command
Example: Request tracing and curl command generation.
Example: Request tracing and curl command generation.
10_streaming command
Example: Streaming responses with Stream, StreamSSE, and StreamNDJSON.
Example: Streaming responses with Stream, StreamSSE, and StreamNDJSON.
11_ja4_fingerprint command
Example: JA4 fingerprinting with TLS impersonation.
Example: JA4 fingerprinting with TLS impersonation.
12_websocket command
Example: WebSocket connection and binary message round-trip.
Example: WebSocket connection and binary message round-trip.
13_tls_evasion command
Example: Full TLS evasion stack.
Example: Full TLS evasion stack.
14_load_balancer command
Example: Load balancer with weighted round-robin strategy.
Example: Load balancer with weighted round-robin strategy.
15_browser_impersonation command
Example: Browser impersonation with Chrome and Firefox profiles.
Example: Browser impersonation with Chrome and Firefox profiles.
16_p0f_fingerprint command
Example: p0f fingerprinting
Example: p0f fingerprinting
17_socketio command
Example: Socket.IO client
Example: Socket.IO client
Package ja4 implements JA4+ network fingerprinting algorithms in pure Go.
Package ja4 implements JA4+ network fingerprinting algorithms in pure Go.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL