{"id":30929973,"url":"https://github.com/enetx/surf","last_synced_at":"2026-02-22T16:25:19.449Z","repository":{"id":312614278,"uuid":"1047442186","full_name":"enetx/surf","owner":"enetx","description":"SURF - Advanced Go HTTP client with Chrome/Firefox browser impersonation, HTTP/3 with QUIC fingerprinting, JA3/JA4 TLS emulation, and anti-bot bypass for web automation and scraping.","archived":false,"fork":false,"pushed_at":"2026-02-17T19:46:30.000Z","size":564,"stargazers_count":1320,"open_issues_count":0,"forks_count":69,"subscribers_count":10,"default_branch":"main","last_synced_at":"2026-02-17T22:40:43.916Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://enetx.surf","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/enetx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-30T12:33:32.000Z","updated_at":"2026-02-17T20:12:06.000Z","dependencies_parsed_at":"2025-08-31T23:29:49.801Z","dependency_job_id":"986f9ed8-b61c-443c-acbe-478dab6c6086","html_url":"https://github.com/enetx/surf","commit_stats":null,"previous_names":["enetx/surf"],"tags_count":85,"template":false,"template_full_name":null,"purl":"pkg:github/enetx/surf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enetx%2Fsurf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enetx%2Fsurf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enetx%2Fsurf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enetx%2Fsurf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/enetx","download_url":"https://codeload.github.com/enetx/surf/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enetx%2Fsurf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29718348,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-22T15:10:41.462Z","status":"ssl_error","status_checked_at":"2026-02-22T15:10:04.636Z","response_time":110,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-10T10:01:47.259Z","updated_at":"2026-02-22T16:25:19.434Z","avatar_url":"https://github.com/enetx.png","language":"Go","funding_links":[],"categories":["Go","Networking","网络信息服务","网络"],"sub_categories":["HTTP Clients","网络协议","HTTP客户端"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/65846651/233453773-33f38b64-0adc-41b4-8e13-a49c89bf9db6.png\"\u003e\n\u003c/p\u003e\n\n\u003ch1\u003eSurf - Advanced HTTP Client for Go\u003c/h1\u003e\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/enetx/surf.svg)](https://pkg.go.dev/github.com/enetx/surf)\n[![Go Report Card](https://goreportcard.com/badge/github.com/enetx/surf)](https://goreportcard.com/report/github.com/enetx/surf)\n[![Coverage Status](https://coveralls.io/repos/github/enetx/surf/badge.svg?branch=main\u0026service=github)](https://coveralls.io/github/enetx/surf?branch=main)\n[![Go](https://github.com/enetx/surf/actions/workflows/go.yml/badge.svg)](https://github.com/enetx/surf/actions/workflows/go.yml)\n[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/enetx/surf)\n\n\u003cp\u003eSurf is a powerful, feature-rich HTTP client library for Go that makes working with HTTP requests intuitive and enjoyable. With advanced features like browser impersonation, JA3/JA4 fingerprinting, and comprehensive middleware support, Surf provides everything you need for modern web interactions.\u003c/p\u003e\n\n## ✨ Key Features\n\n### 🎭 **Browser Impersonation**\n- **Chrome \u0026 Firefox Support**: Accurately mimic Chrome v145 and Firefox v147 browser fingerprints\n- **Platform Diversity**: Impersonate Windows, macOS, Linux, Android, and iOS devices\n- **TLS Fingerprinting**: Full JA3/JA4 fingerprint customization for enhanced privacy\n- **Automatic Headers**: Proper header ordering and browser-specific values\n- **WebKit Form Boundaries**: Accurate multipart form boundary generation matching real browsers\n\n### 🔒 **Advanced TLS \u0026 Security**\n- **Custom JA3/JA4**: Configure precise TLS fingerprints with `HelloID` and `HelloSpec`\n- **HTTP/3 Support**: Full HTTP/3 over QUIC with complete browser-specific fingerprinting\n- **HTTP/2 \u0026 HTTP/3**: Full HTTP/2 support with customizable settings (SETTINGS frame, window size, priority)\n- **Ordered Headers**: Browser-accurate header ordering for perfect fingerprint evasion\n- **Certificate Pinning**: Custom TLS certificate validation\n- **DNS-over-TLS**: Enhanced privacy with DoT support\n- **Proxy Support**: HTTP, HTTPS, SOCKS4 and SOCKS5 proxy configurations with UDP support for HTTP/3\n\n### 🚀 **Performance \u0026 Reliability**\n- **Connection Pooling**: Efficient connection reuse with singleton pattern\n- **Automatic Retries**: Configurable retry logic with custom status codes\n- **Response Caching**: Built-in body caching for repeated access\n- **Streaming Support**: Efficient handling of large responses and SSE\n- **Compression**: Automatic decompression of gzip, deflate, brotli, and zstd responses\n- **Keep-Alive**: Persistent connections with configurable parameters\n\n### 🛠️ **Developer Experience**\n- **Standard Library Compatible**: Convert to `net/http.Client` for third-party library integration\n- **Fluent API**: Chainable methods for elegant code\n- **Middleware System**: Extensible request/response/client middleware with priority support\n- **Type Safety**: Strong typing with generics support via [enetx/g](https://github.com/enetx/g)\n- **Debug Mode**: Comprehensive request/response debugging\n- **Error Handling**: Result type pattern for better error management\n- **Context Support**: Full context.Context integration for cancellation and timeouts\n\n## 📦 Installation\n\n```bash\ngo get -u github.com/enetx/surf\n```\n\n**Required Go version:** 1.24+\n\n## 🔄 Standard Library Compatibility\n\nSurf provides seamless integration with Go's standard `net/http` package, allowing you to use Surf's advanced features with any library that expects a standard `*http.Client`.\n\n```go\n// Create a Surf client with advanced features\nsurfClient := surf.NewClient().\n    Builder().\n    Impersonate().Chrome().\n    Session().\n    Build().\n    Unwrap()\n\n// Convert to standard net/http.Client\nstdClient := surfClient.Std()\n\n// Use with any third-party library\n// Example: AWS SDK, Google APIs, OpenAI client, etc.\nresp, err := stdClient.Get(\"https://api.example.com\")\n```\n\n**Preserved Features When Using Std():**\n- ✅ JA3/TLS fingerprinting\n- ✅ HTTP/2, HTTP/3 settings \u0026\u0026 fingerprinting\n- ✅ Browser impersonation headers\n- ✅ Ordered headers\n- ✅ Cookies and sessions\n- ✅ Proxy configuration\n- ✅ Custom headers and User-Agent\n- ✅ Timeout settings\n- ✅ Redirect policies\n- ✅ Request/Response middleware\n\n**Limitations with Std():**\n- ❌ Retry logic (implement at application level)\n- ❌ Response body caching\n- ❌ Remote address tracking\n- ❌ Request timing information\n\n## 🚀 Quick Start\n\n### Basic GET Request\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"log\"\n    \"github.com/enetx/surf\"\n)\n\nfunc main() {\n    resp := surf.NewClient().Get(\"https://api.github.com/users/github\").Do()\n    if resp.IsErr() {\n        log.Fatal(resp.Err())\n    }\n\n    fmt.Println(resp.Ok().Body.String().Unwrap())\n}\n```\n\n### JSON Response Handling\n\n```go\ntype User struct {\n    Name     string `json:\"name\"`\n    Company  string `json:\"company\"`\n    Location string `json:\"location\"`\n}\n\nresp := surf.NewClient().Get(\"https://api.github.com/users/github\").Do()\nif resp.IsOk() {\n    var user User\n    resp.Ok().Body.JSON(\u0026user)\n    fmt.Printf(\"User: %+v\\n\", user)\n}\n```\n\n## 🎭 Browser Impersonation\n\n### Chrome Impersonation\n\n```go\nclient := surf.NewClient().\n    Builder().\n    Impersonate().\n    Chrome().        // Latest Chrome v145\n    Build().\n    Unwrap()\n\nresp := client.Get(\"https://example.com\").Do()\n```\n\n### Firefox with Random OS\n\n```go\nclient := surf.NewClient().\n    Builder().\n    Impersonate().\n    RandomOS().      // Randomly selects Windows, macOS, Linux, Android, or iOS\n    Firefox().       // Latest Firefox v147\n    Build().\n    Unwrap()\n```\n\n### Platform-Specific Impersonation\n\n```go\n// iOS Chrome\nclient := surf.NewClient().\n    Builder().\n    Impersonate().\n    IOS().\n    Chrome().\n    Build().\n    Unwrap()\n\n// Android Chrome\nclient := surf.NewClient().\n    Builder().\n    Impersonate().\n    Android().\n    Chrome().\n    Build().\n    Unwrap()\n```\n\n## 🚀 HTTP/3 \u0026 Complete QUIC Fingerprinting\n\n### Chrome HTTP/3 with Automatic Detection\n\n```go\n// Automatic HTTP/3 with Chrome fingerprinting\nclient := surf.NewClient().\n    Builder().\n    Impersonate().Chrome().\n    HTTP3().    // Auto-detects Chrome and applies appropriate HTTP/3 settings\n    Build().\n    Unwrap()\n\nresp := client.Get(\"https://cloudflare-quic.com/\").Do()\nif resp.IsOk() {\n    fmt.Printf(\"Protocol: %s\\n\", resp.Ok().Proto) // HTTP/3.0\n}\n```\n\n### Firefox HTTP/3\n\n```go\n// Firefox with HTTP/3 fingerprinting\nclient := surf.NewClient().\n    Builder().\n    Impersonate().Firefox().\n    HTTP3().    // Auto-detects Firefox and applies Firefox HTTP/3 settings\n    Build().\n    Unwrap()\n\nresp := client.Get(\"https://cloudflare-quic.com/\").Do()\n```\n\n### Manual HTTP/3 Configuration\n\n```go\n// Custom fingerprint settings\nclient := surf.NewClient().\n    Builder().\n    HTTP3Settings().Grease().Set().\n    Build().\n    Unwrap()\n\n```\n\n### HTTP/3 Compatibility \u0026 Fallbacks\n\nHTTP/3 automatically handles compatibility issues:\n\n```go\n// With HTTP proxy - automatically falls back to HTTP/2\nclient := surf.NewClient().\n    Builder().\n    Proxy(\"http://proxy:8080\").    // HTTP proxies incompatible with HTTP/3\n    HTTP3().                       // Will use HTTP/2 instead\n    Build().\n    Unwrap()\n\n// With SOCKS5 proxy - HTTP/3 works over UDP\nclient := surf.NewClient().\n    Builder().\n    Proxy(\"socks5://127.0.0.1:1080\").    // SOCKS5 UDP proxy supports HTTP/3\n    HTTP3().                             // Will use HTTP/3 over SOCKS5\n    Build().\n    Unwrap()\n\n// With DNS settings - works seamlessly\nclient := surf.NewClient().\n    Builder().\n    DNS(\"8.8.8.8:53\").   // Custom DNS works with HTTP/3\n    HTTP3().\n    Build().\n    Unwrap()\n\n// With DNS-over-TLS - works seamlessly\nclient := surf.NewClient().\n    Builder().\n    DNSOverTLS().Google().   // DoT works with HTTP/3\n    HTTP3().Set().\n    Build().\n    Unwrap()\n```\n\n**Key HTTP/3 Features:**\n- ✅ **Complete QUIC Fingerprinting**: Full Chrome and Firefox QUIC transport parameter matching\n- ✅ **Header Ordering**: Perfect browser-like header sequence preservation\n- ✅ **SOCKS5 UDP Support**: HTTP/3 works seamlessly over SOCKS5 UDP proxies\n- ✅ **Automatic Fallback**: Smart fallback to HTTP/2 when HTTP proxies are configured\n- ✅ **DNS Integration**: Custom DNS and DNS-over-TLS support\n- ✅ **JA4QUIC Support**: Advanced QUIC fingerprinting with Initial Packet + TLS ClientHello\n- ✅ **Order Independence**: `HTTP3()` works regardless of call order\n\n## 🔧 Advanced Configuration\n\n### Custom JA3 Fingerprint\n\n```go\n// Use specific browser versions\nclient := surf.NewClient().\n    Builder().\n    JA().\n    Chrome().     // Latest Chrome\n    Build().\n    Unwrap()\n\n\n// Randomized fingerprints for evasion\nclient := surf.NewClient().\n    Builder().\n    JA().\n    Randomized().    // Random TLS fingerprint\n    Build().\n    Unwrap()\n\n// With custom HelloID\nclient := surf.NewClient().\n    Builder().\n    JA().\n    SetHelloID(utls.HelloChrome_Auto).\n    Build().\n    Unwrap()\n\n// With custom HelloSpec\nclient := surf.NewClient().\n    Builder().\n    JA().\n    SetHelloSpec(customSpec).\n    Build().\n    Unwrap()\n```\n\n### HTTP/2 Configuration\n\n```go\nclient := surf.NewClient().\n    Builder().\n    HTTP2Settings().\n    HeaderTableSize(65536).\n    EnablePush(0).\n    InitialWindowSize(6291456).\n    MaxHeaderListSize(262144).\n    ConnectionFlow(15663105).\n    Set().\n    Build().\n    Unwrap()\n```\n\n### HTTP/3 Configuration\n\n```go\nclient := surf.NewClient().\n    Builder().\n\tHTTP3Settings().\n\tQpackMaxTableCapacity(65536).\n\tMaxFieldSectionSize(262144).\n\tQpackBlockedStreams(100).\n\tH3Datagram(1).\n\tGrease().\n\tSet().\n    Build().\n    Unwrap()\n```\n\n### Proxy Configuration\n\n```go\n// Single proxy\nclient := surf.NewClient().\n    Builder().\n    Proxy(\"http://proxy.example.com:8080\").\n    Build().\n    Unwrap()\n```\n\n### SOCKS5 UDP Proxy Support\nSurf supports HTTP/3 over SOCKS5 UDP proxies, combining the benefits of modern QUIC protocol with proxy functionality:\n\n```go\n// HTTP/3 over SOCKS5 UDP proxy\nclient := surf.NewClient().\n    Builder().\n    Proxy(\"socks5://127.0.0.1:1080\").\n    Impersonate().Chrome().\n    HTTP3().  // Uses HTTP/3 over SOCKS5 UDP\n    Build().\n    Unwrap()\n\n// SOCKS5 with custom DNS resolution\nclient := surf.NewClient().\n    Builder().\n    DNS(\"8.8.8.8:53\").              // Custom DNS resolver\n    Proxy(\"socks5://proxy:1080\").   // SOCKS5 UDP proxy\n    HTTP3().                        // HTTP/3 over SOCKS5\n    Build().\n    Unwrap()\n```\n\n## 🔌 Middleware System\n\n### Request Middleware\n\n```go\nclient := surf.NewClient().\n    Builder().\n    With(func(req *surf.Request) error {\n        req.AddHeaders(\"X-Custom-Header\", \"value\")\n        fmt.Printf(\"Request to: %s\\n\", req.GetRequest().URL)\n        return nil\n    }).\n    Build().\n    Unwrap()\n```\n\n### Response Middleware\n\n```go\nclient := surf.NewClient().\n    Builder().\n    With(func(resp *surf.Response) error {\n        fmt.Printf(\"Response status: %d\\n\", resp.StatusCode)\n        fmt.Printf(\"Response time: %v\\n\", resp.Time)\n        return nil\n    }).\n    Build().\n    Unwrap()\n```\n\n### Client Middleware\n\n```go\nclient := surf.NewClient().\n    Builder().\n    With(func(client *surf.Client) error {\n        // Modify client configuration\n        client.GetClient().Timeout = 30 * time.Second\n        return nil\n    }).\n    Build().\n    Unwrap()\n```\n\n## 📤 Request Types\n\n### POST with JSON\n\n```go\nuser := map[string]string{\n    \"name\": \"John Doe\",\n    \"email\": \"john@example.com\",\n}\n\nresp := surf.NewClient().\n    Post(\"https://api.example.com/users\").\n    Body(user).\n    Do()\n```\n\n### Form Data\n\n```go\n// Standard form data (field order not guaranteed)\nformData := map[string]string{\n    \"username\": \"john\",\n    \"password\": \"secret\",\n}\n\nresp := surf.NewClient().\n    Post(\"https://example.com/login\").\n    Body(formData).\n    Do()\n\n// Ordered form data (preserves field insertion order)\norderedForm := g.NewMapOrd[string, string]()\norderedForm.Insert(\"username\", \"john\")\norderedForm.Insert(\"password\", \"secret\")\norderedForm.Insert(\"remember_me\", \"true\")\n\nresp := surf.NewClient().\n    Post(\"https://example.com/login\").\n    Body(orderedForm).\n    Do()\n```\n\n### File Upload\n\n```go\n// Single file upload\nmp := surf.NewMultipart().\n    File(\"file\", g.NewFile(\"/path/to/file.pdf\"))\n\nresp := surf.NewClient().\n    Post(\"https://api.example.com/upload\").\n    Multipart(mp).\n    Do()\n\n// With additional form fields\nmp := surf.NewMultipart().\n    Field(\"description\", \"Important document\").\n    Field(\"category\", \"reports\").\n    File(\"file\", g.NewFile(\"/path/to/file.pdf\"))\n\nresp := surf.NewClient().\n    Post(\"https://api.example.com/upload\").\n    Multipart(mp).\n    Do()\n```\n\n### Multipart Form\n\n```go\n// Simple multipart form with fields only\nmp := surf.NewMultipart().\n    Field(\"field1\", \"value1\").\n    Field(\"field2\", \"value2\")\n\nresp := surf.NewClient().\n    Post(\"https://api.example.com/form\").\n    Multipart(mp).\n    Do()\n\n// Advanced multipart with files from different sources\nmp := surf.NewMultipart().\n    Field(\"description\", \"Multiple files\").\n    File(\"document\", g.NewFile(\"/path/to/doc.pdf\")).               // Physical file\n    FileBytes(\"data\", \"data.json\", g.Bytes(`{\"key\": \"value\"}`)).   // Bytes with custom filename\n    FileString(\"text\", \"note.txt\", \"Hello, World!\").               // String content\n    FileReader(\"stream\", \"upload.bin\", someReader).                // io.Reader\n    ContentType(\"application/pdf\")                                 // Custom Content-Type for last file\n\nresp := surf.NewClient().\n    Post(\"https://api.example.com/upload\").\n    Multipart(mp).\n    Do()\n```\n\n## 🔄 Session Management\n\n### Persistent Sessions\n\n```go\nclient := surf.NewClient().\n    Builder().\n    Session().        // Enable cookie jar\n    Build().\n    Unwrap()\n\n// Login\nclient.Post(\"https://example.com/login\").Body(credentials).Do()\n\n// Subsequent requests will include session cookies\nresp := client.Get(\"https://example.com/dashboard\").Do()\n```\n\n### Manual Cookie Management\n\n```go\n// Set cookies\ncookies := []*http.Cookie{\n    {Name: \"session\", Value: \"abc123\"},\n    {Name: \"preference\", Value: \"dark_mode\"},\n}\n\nresp := surf.NewClient().\n    Get(\"https://example.com\").\n    AddCookies(cookies...).\n    Do()\n\n// Get cookies from response\nif resp.IsOk() {\n    for _, cookie := range resp.Ok().Cookies {\n        fmt.Printf(\"Cookie: %s = %s\\n\", cookie.Name, cookie.Value)\n    }\n}\n```\n\n## 📊 Response Handling\n\n### Status Code Checking\n\n```go\nresp := surf.NewClient().Get(\"https://api.example.com/data\").Do()\n\nif resp.IsOk() {\n    switch {\n    case resp.Ok().StatusCode.IsSuccess():\n        fmt.Println(\"Success!\")\n    case resp.Ok().StatusCode.IsRedirection():\n        fmt.Println(\"Redirected to:\", resp.Ok().Location())\n    case resp.Ok().StatusCode.IsClientError():\n        fmt.Println(\"Client error:\", resp.Ok().StatusCode)\n    case resp.Ok().StatusCode.IsServerError():\n        fmt.Println(\"Server error:\", resp.Ok().StatusCode)\n    }\n}\n```\n\n### Body Processing\n\n```go\nresp := surf.NewClient().Get(\"https://example.com/data\").Do()\nif resp.IsOk() {\n    body := resp.Ok().Body\n\n    // As string (returns g.Result[g.String])\n    if content := body.String(); content.IsOk() {\n        fmt.Println(content.Ok())\n    }\n\n    // As bytes (returns g.Result[g.Bytes])\n    if data := body.Bytes(); data.IsOk() {\n        fmt.Println(len(data.Ok()))\n    }\n\n    // UTF-8 conversion (returns g.Result[g.String])\n    if utf8Content := body.UTF8(); utf8Content.IsOk() {\n        fmt.Println(utf8Content.Ok())\n    }\n\n    // Check content\n    if body.Contains(\"success\") {\n        fmt.Println(\"Request succeeded!\")\n    }\n\n    // Save to file\n    err := body.Dump(\"response.html\")\n}\n```\n\n### Streaming Large Responses\n\n```go\nresp := surf.NewClient().Get(\"https://example.com/large-file\").Do()\nif resp.IsOk() {\n    stream := resp.Ok().Body.Stream()\n    defer stream.Close()\n\n    scanner := bufio.NewScanner(stream)\n    for scanner.Scan() {\n        fmt.Println(scanner.Text())\n    }\n}\n```\n\n### Server-Sent Events (SSE)\n\n```go\nresp := surf.NewClient().Get(\"https://example.com/events\").Do()\nif resp.IsOk() {\n    resp.Ok().Body.SSE(func(event *sse.Event) bool {\n        fmt.Printf(\"Event: %s, Data: %s\\n\", event.Event, event.Data)\n        return true  // Continue reading (false to stop)\n    })\n}\n```\n\n## 🔍 Debugging\n\n### Request/Response Debugging\n\n```go\nresp := surf.NewClient().\n    Get(\"https://api.example.com\").\n    Do()\n\nif resp.IsOk() {\n    resp.Ok().Debug().\n        Request().      // Show request details\n        Response(true). // Show response with body\n        Print()\n}\n```\n\n### TLS Information\n\n```go\nresp := surf.NewClient().Get(\"https://example.com\").Do()\nif resp.IsOk() {\n    if tlsInfo := resp.Ok().TLSGrabber(); tlsInfo != nil {\n        fmt.Printf(\"TLS Version: %s\\n\", tlsInfo.TLSVersion)\n        fmt.Printf(\"Server Name: %s\\n\", tlsInfo.ExtensionServerName)\n        fmt.Printf(\"Fingerprint: %s\\n\", tlsInfo.FingerprintSHA256)\n        fmt.Printf(\"Common Name: %v\\n\", tlsInfo.CommonName)\n        fmt.Printf(\"Organization: %v\\n\", tlsInfo.Organization)\n    }\n}\n```\n\n## ⚡ Performance Optimization\n\n### Connection Reuse\n\n```go\n// Create a reusable client\nclient := surf.NewClient().\n    Builder().\n    Impersonate().\n    Chrome().\n    Build().\n    Unwrap()\n\n// Reuse for multiple requests\nfor i := 0; i \u003c 100; i++ {\n    resp := client.Get(\"https://api.example.com/data\").Do()\n    // Process response\n}\n\n// Clean up when done\ndefer client.CloseIdleConnections()\n```\n\n### Response Caching\n\n```go\nclient := surf.NewClient().\n    Builder().\n    CacheBody().      // Enable body caching\n    Build().\n    Unwrap()\n\nresp := client.Get(\"https://api.example.com/data\").Do()\nif resp.IsOk() {\n    // First access reads from network\n    data1 := resp.Ok().Body.Bytes().Unwrap()\n\n    // Subsequent accesses use cache\n    data2 := resp.Ok().Body.Bytes().Unwrap()  // No network I/O\n}\n```\n\n### Retry Configuration\n\n```go\nclient := surf.NewClient().\n    Builder().\n    Retry(3, 2*time.Second).           // Max 3 retries, 2 second wait\n    Build().\n    Unwrap()\n```\n\n## 🌐 Advanced Features\n\n### H2C (HTTP/2 Cleartext)\n\n```go\n// Enable HTTP/2 without TLS\nclient := surf.NewClient().\n    Builder().\n    H2C().\n    Build().\n    Unwrap()\n\nresp := client.Get(\"http://localhost:8080/h2c-endpoint\").Do()\n```\n\n### Custom Headers Order\n\n```go\n// Control exact header order for fingerprinting evasion\nheaders := g.NewMapOrd[g.String, g.String]()\nheaders.Insert(\"User-Agent\", \"Custom/1.0\")\nheaders.Insert(\"Accept\", \"*/*\")\nheaders.Insert(\"Accept-Language\", \"en-US\")\nheaders.Insert(\"Accept-Encoding\", \"gzip, deflate\")\n\nclient := surf.NewClient().\n    Builder().\n    SetHeaders(headers).  // Headers will be sent in this exact order\n    Build().\n    Unwrap()\n```\n\n### Custom DNS Resolver\n\n```go\nclient := surf.NewClient().\n    Builder().\n    DNS(\"8.8.8.8:53\").  // Use Google DNS\n    Build().\n    Unwrap()\n```\n\n### DNS-over-TLS\n\n```go\nclient := surf.NewClient().\n    Builder().\n    DNSOverTLS().Cloudflare().  // Cloudflare DoT\n    Build().\n    Unwrap()\n```\n\n### Unix Domain Sockets\n\n```go\nclient := surf.NewClient().\n    Builder().\n    UnixSocket(\"/var/run/docker.sock\").\n    Build().\n    Unwrap()\n\nresp := client.Get(\"http://localhost/v1.41/containers/json\").Do()\n```\n\n### Network Interface Binding\n\n```go\nclient := surf.NewClient().\n    Builder().\n    InterfaceAddr(\"192.168.1.100\").  // Bind to specific IP\n    Build().\n    Unwrap()\n```\n\n### Raw HTTP Requests\n\n```go\nrawRequest := `GET /api/data HTTP/1.1\nHost: example.com\nUser-Agent: Custom/1.0\nAccept: application/json\n\n`\n\nresp := surf.NewClient().\n    Raw(g.String(rawRequest), \"https\").\n    Do()\n```\n\n## 📚 API Reference\n\n### Client Methods\n\n| Method | Description |\n|--------|-------------|\n| `NewClient()` | Creates a new HTTP client with defaults |\n| `Get(url)` | Creates a GET request |\n| `Post(url)` | Creates a POST request |\n| `Put(url)` | Creates a PUT request |\n| `Patch(url)` | Creates a PATCH request |\n| `Delete(url)` | Creates a DELETE request |\n| `Head(url)` | Creates a HEAD request |\n| `Options(url)` | Creates an OPTIONS request |\n| `Connect(url)` | Creates a CONNECT request |\n| `Trace(url)` | Creates a TRACE request |\n| `Raw(raw, scheme)` | Creates a request from raw HTTP |\n| `Builder()` | Returns a new Builder for client configuration |\n| `Std()` | Convert to standard `*net/http.Client` |\n| `CloseIdleConnections()` | Closes idle connections while keeping client usable |\n| `Close()` | Completely shuts down the client and releases all resources |\n\n### Builder Methods\n\n| Method | Description |\n|--------|-------------|\n| `Impersonate()` | Enable browser impersonation |\n| `JA()` | Configure JA3/JA4 fingerprinting |\n| `HTTP2Settings()` | Configure HTTP/2 parameters |\n| `HTTP3Settings()` | Configure HTTP/3 parameters |\n| `HTTP3()` | Enable HTTP/3 with automatic browser detection |\n| `H2C()` | Enable HTTP/2 cleartext |\n| `Proxy(proxy)` | Set proxy configuration |\n| `DNS(dns)` | Set custom DNS resolver |\n| `DNSOverTLS()` | Configure DNS-over-TLS |\n| `Session()` | Enable cookie jar for sessions |\n| `Timeout(duration)` | Set request timeout |\n| `MaxRedirects(n)` | Set maximum redirects |\n| `NotFollowRedirects()` | Disable redirect following |\n| `FollowOnlyHostRedirects()` | Only follow same-host redirects |\n| `ForwardHeadersOnRedirect()` | Forward headers on redirects |\n| `RedirectPolicy(fn)` | Custom redirect policy function |\n| `Retry(max, wait, codes...)` | Configure retry logic |\n| `CacheBody()` | Enable response body caching |\n| `With(middleware, priority...)` | Add middleware |\n| `BasicAuth(auth)` | Set basic authentication |\n| `BearerAuth(token)` | Set bearer token authentication |\n| `UserAgent(ua)` | Set custom user agent |\n| `SetHeaders(headers...)` | Set request headers |\n| `AddHeaders(headers...)` | Add request headers |\n| `AddCookies(cookies...)` | Add cookies |\n| `WithContext(ctx)` | Add context |\n| `ContentType(type)` | Set content type |\n| `GetRemoteAddress()` | Track remote address |\n| `DisableKeepAlive()` | Disable keep-alive |\n| `DisableCompression()` | Disable compression |\n| `ForceHTTP1()` | Force HTTP/1.1 |\n| `ForceHTTP2()` | Force HTTP/2 |\n| `ForceHTTP3()` | Force HTTP/3 |\n| `UnixSocket(path)` | Use Unix socket |\n| `InterfaceAddr(addr)` | Bind to network interface |\n| `Boundary(fn)` | Custom multipart boundary generator |\n\n### Request Methods\n\n| Method | Description |\n|--------|-------------|\n| `Do()` | Execute the request |\n| `WithContext(ctx)` | Add context to request |\n| `Body(data)` | Set request body (JSON, form data, bytes, string, io.Reader) |\n| `SetHeaders(headers...)` | Set request headers |\n| `AddHeaders(headers...)` | Add request headers |\n| `AddCookies(cookies...)` | Add cookies to request |\n| `Multipart(mp)` | Set multipart form data for request |\n| `GetRequest()` | Returns underlying `*http.Request` |\n\n### Multipart Methods\n\n| Method | Description |\n|--------|-------------|\n| `NewMultipart()` | Creates a new Multipart builder |\n| `Field(name, value)` | Adds a form field |\n| `File(fieldName, file)` | Adds a file from `*g.File` |\n| `FileReader(fieldName, fileName, reader)` | Adds a file from `io.Reader` |\n| `FileString(fieldName, fileName, content)` | Adds a file from string content |\n| `FileBytes(fieldName, fileName, data)` | Adds a file from byte slice |\n| `ContentType(ct)` | Sets custom Content-Type for the last added file |\n| `FileName(name)` | Overrides filename for the last added file |\n| `Retry()` | Buffers multipart body for retry support |\n\n### Response Properties\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `StatusCode` | `StatusCode` | HTTP status code |\n| `Headers` | `Headers` | Response headers |\n| `Cookies` | `Cookies` | Response cookies |\n| `Body` | `*Body` | Response body |\n| `URL` | `*url.URL` | Final URL after redirects |\n| `Time` | `time.Duration` | Request duration |\n| `ContentLength` | `int64` | Content length |\n| `Proto` | `string` | HTTP protocol version |\n| `Attempts` | `int` | Number of retry attempts |\n\n### Response Methods\n\n| Method | Description |\n|--------|-------------|\n| `Debug()` | Returns debug info for request/response inspection |\n| `Location()` | Returns the Location header (redirect URL) |\n| `TLSGrabber()` | Returns TLS connection information |\n| `Referer()` | Returns HTTP Referer header from original request |\n| `GetResponse()` | Returns underlying `*http.Response` |\n| `GetCookies(url)` | Returns cookies for a specific URL |\n| `SetCookies(url, cookies)` | Stores cookies in client's cookie jar |\n| `RemoteAddress()` | Returns remote server address |\n\n### Body Methods\n\n| Method | Description |\n|--------|-------------|\n| `String()` | Get body as string (returns `g.Result[g.String]`) |\n| `Bytes()` | Get body as bytes (returns `g.Result[g.Bytes]`) |\n| `JSON(v)` | Decode JSON into struct |\n| `XML(v)` | Decode XML into struct |\n| `UTF8()` | Convert to UTF-8 (returns `g.Result[g.String]`) |\n| `Stream()` | Get StreamReader for streaming (with Close support) |\n| `SSE(fn)` | Process Server-Sent Events |\n| `Dump(file)` | Save to file |\n| `Contains(pattern)` | Check if contains pattern |\n| `Limit(n)` | Limit body size |\n| `WithContext(ctx)` | Set context for cancellation of read operations |\n| `Close()` | Close body reader |\n\n## 🤝 Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/AmazingFeature`)\n3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)\n4. Push to the branch (`git push origin feature/AmazingFeature`)\n5. Open a Pull Request\n\n## ❤️ Support / Sponsorship\n\nIf you enjoy **Surf** and want to help keep development going, you can support the project with crypto donations:\n\n| USDT | TON | SOL | BTC | ETH |\n|--------------|-----|-----|-----|-----|\n| \u003cimg src=\"https://github.com/user-attachments/assets/72ccb81c-f958-416b-86f6-349c759cdb93\" width=\"100\" /\u003e | \u003cimg src=\"https://github.com/user-attachments/assets/49431b49-3e43-49a6-8083-2f5cb39d4f4e\" width=\"100\" /\u003e | \u003cimg src=\"https://github.com/user-attachments/assets/d92ba4e9-408b-411e-bc08-473725a880f8\" width=\"100\" /\u003e | \u003cimg src=\"https://github.com/user-attachments/assets/67a1ac0e-de90-4341-a13c-614eb213f5da\" width=\"100\" /\u003e | \u003cimg src=\"https://github.com/user-attachments/assets/2e1b6c2b-f4b8-47ca-9785-f0512198ae49\" width=\"100\" /\u003e |\n\nThank you for your support!\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## 🙏 Acknowledgments\n\n- Built with [enetx/http](https://github.com/enetx/http) for enhanced HTTP functionality\n- HTTP/3 support and complete QUIC fingerprinting powered by [uQUIC](https://github.com/enetx/uquic)\n- TLS fingerprinting powered by [uTLS](https://github.com/enetx/utls)\n- Generic utilities from [enetx/g](https://github.com/enetx/g)\n\n## 📞 Support\n\n- **Issues**: [GitHub Issues](https://github.com/enetx/surf/issues)\n- **Discussions**: [GitHub Discussions](https://github.com/enetx/surf/discussions)\n- **Documentation**: [pkg.go.dev](https://pkg.go.dev/github.com/enetx/surf)\n\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003eMade with ❤️ by the Surf contributors\u003c/b\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fenetx%2Fsurf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fenetx%2Fsurf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fenetx%2Fsurf/lists"}