# enetx/surf README

# SURF - Advanced Go HTTP Client

**Repo:** enetx/surf
**Language:** Go (100%)
**License:** MIT
**Stars:** 1.7k (88 forks)
**Required Go version:** 1.25+

SURF is an advanced HTTP client library for Go featuring Chrome/Firefox browser impersonation, HTTP/3 with QUIC fingerprinting, JA3/JA4 TLS emulation, and anti-bot bypass capabilities for web automation and scraping.

## Key Features

### Browser Impersonation
- Mimics Chrome v145 and Firefox v148 fingerprints accurately
- Cross-platform: Windows, macOS, Linux, Android, iOS
- Automatic header ordering and browser-specific values
- WebKit form boundary generation matching real browsers

### Advanced TLS & Security
- Custom JA3/JA4 fingerprint configuration via HelloID and HelloSpec
- Full HTTP/3 over QUIC support with complete browser fingerprinting
- HTTP/2 with customizable SETTINGS frames and window sizes
- DNS-over-TLS (DoT)
- Proxy: HTTP, HTTPS, SOCKS4, SOCKS5 with UDP for HTTP/3
- Certificate pinning

### Performance & Reliability
- Connection pooling with singleton pattern
- Configurable automatic retry logic
- Response body caching
- Streaming support (large responses + SSE)
- Automatic decompression (gzip, deflate, brotli, zstd)

### Developer Experience
- Standard library compatibility (converts to `*net/http.Client`)
- Fluent, chainable API
- Extensible middleware system with priority support
- Strong typing with generics via enetx/g
- Comprehensive debug mode
- Full context.Context integration

## Installation

```bash
go get -u github.com/enetx/surf
```

## Usage

### Basic GET
```go
resp := surf.NewClient().Get("https://api.github.com/users/github").Do()
if resp.IsErr() {
    log.Fatal(resp.Err())
}
fmt.Println(resp.Ok().Body.String().Unwrap())
```

### Browser Impersonation
```go
client := surf.NewClient().Builder().Impersonate().Chrome().Build().Unwrap()

client := surf.NewClient().Builder().Impersonate().RandomOS().Firefox().Build().Unwrap()

client := surf.NewClient().Builder().Impersonate().IOS().Chrome().Build().Unwrap()
```

### HTTP/3
```go
client := surf.NewClient().Builder().
    Impersonate().Chrome().
    ForceHTTP3().
    Build().Unwrap()

resp := client.Get("https://cloudflare-quic.com/").Do()
fmt.Printf("Protocol: %s\n", resp.Ok().Proto) // HTTP/3.0
```

### Custom JA3
```go
client := surf.NewClient().Builder().JA().Chrome().Build().Unwrap()
client := surf.NewClient().Builder().JA().Randomized().Build().Unwrap()
```

### HTTP/2 Settings
```go
client := surf.NewClient().Builder().
    HTTP2Settings().
    HeaderTableSize(65536).
    EnablePush(0).
    InitialWindowSize(6291456).
    Set().
    Build().Unwrap()
```

### Proxies
```go
client := surf.NewClient().Builder().Proxy("http://proxy.example.com:8080").Build().Unwrap()

// SOCKS5 UDP for HTTP/3
client := surf.NewClient().Builder().
    Proxy("socks5://127.0.0.1:1080").
    ForceHTTP3().
    Build().Unwrap()
```

### Sessions
```go
client := surf.NewClient().Builder().Session().Build().Unwrap()
client.Post("https://example.com/login").Body(credentials).Do()
resp := client.Get("https://example.com/dashboard").Do()
```

### Middleware
```go
client := surf.NewClient().Builder().
    With(func(req *surf.Request) error {
        req.AddHeaders("X-Custom-Header", "value")
        return nil
    }).
    Build().Unwrap()
```

### Multipart Upload
```go
mp := surf.NewMultipart().
    Field("description", "Multiple files").
    File("document", g.NewFile("/path/to/doc.pdf")).
    FileBytes("data", "data.json", g.Bytes(`{"key": "value"}`)).
    FileString("text", "note.txt", "Hello, World!")

resp := surf.NewClient().Post("https://api.example.com/upload").Multipart(mp).Do()
```

### Streaming + SSE
```go
resp := surf.NewClient().Get("https://example.com/large-file").Do()
stream := resp.Ok().Body.Stream()
defer stream.Close()
scanner := bufio.NewScanner(stream)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}

// SSE
resp.Ok().Body.SSE(func(event *sse.Event) bool {
    fmt.Printf("Event: %s, Data: %s\n", event.Event, event.Data)
    return true
})
```

### Standard library compatibility
```go
surfClient := surf.NewClient().Builder().Impersonate().Chrome().Session().Build().Unwrap()
stdClient := surfClient.Std()
resp, err := stdClient.Get("https://api.example.com")
```

Preserved when using Std(): JA3/TLS fingerprinting, HTTP/2/3 settings, browser headers, ordered headers, cookies/sessions, proxy, custom headers, timeout, redirect policies, request/response middleware.

Lost when using Std(): retry logic, response body caching, remote address tracking, request timing.

### Other features
- H2C (HTTP/2 Cleartext): `.H2C()`
- Custom DNS: `.DNS("8.8.8.8:53")`
- DNS-over-TLS: `.DNSOverTLS().Cloudflare()`
- Unix sockets: `.UnixSocket("/var/run/docker.sock")`
- Interface binding: `.InterfaceAddr("192.168.1.100")`
- Raw HTTP requests: `client.Raw(rawRequest, "https").Do()`
- Retry: `.Retry(3, 2*time.Second)`
- Body caching: `.CacheBody()`

## Architecture

- **Result type pattern**: operations return `g.Result[T]`; explicit error handling without panic.
- **Middleware system**: request, response, and client-level with priority-based ordering.
- **Fluent builder**: method chaining for client construction.
- **Connection pooling**: singleton pattern for connection reuse.
- **Compatibility layer**: convertable to `*net/http.Client` retaining most features.
- **Fingerprinting foundation**: built on uTLS (refraction-networking) for JA3/JA4, quic-go for QUIC.

## HTTP/3 & QUIC

- Complete QUIC fingerprinting matching Chrome/Firefox
- Header ordering preserved for browser-like sequences
- SOCKS5 UDP proxy support for HTTP/3
- Automatic fallback to HTTP/2 with HTTP proxies
- DNS integration with custom DNS and DoT
- JA4QUIC support with Initial Packet + TLS ClientHello

## Dependencies

- **enetx/http**: enhanced HTTP functionality
- **quic-go**: HTTP/3 & QUIC
- **uTLS** (refraction-networking): TLS fingerprinting
- **enetx/g**: generic utilities, Result type
