httpcli

package
v1.19.2 Latest Latest
Warning

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

Go to latest
Published: Feb 4, 2026 License: MIT Imports: 12 Imported by: 0

README

HTTPCli Package

Go Version Tests Coverage Go Reference

Advanced HTTP client toolkit with DNS mapping, TLS configuration, and flexible transport options for Go applications.


Table of Contents

Overview

The httpcli package provides production-ready HTTP client abstractions for Go applications requiring advanced networking capabilities. It emphasizes flexible DNS resolution, TLS configuration, and seamless integration with custom transport options through the specialized dns-mapper subpackage.

Design Philosophy
  1. Simple API: Minimal code for common use cases
  2. Flexible DNS: Override DNS resolution for testing and routing
  3. Secure by Default: Built-in TLS support with custom configuration
  4. Observable: Integrated error handling with custom error codes
  5. Production-Ready: Thread-safe concurrent operations

Features

Core Capabilities
  • HTTP Client Management

    • Default client with sensible configuration
    • Custom DNS mapper integration
    • Thread-safe singleton pattern
    • Automatic cleanup and lifecycle management
  • DNS Mapping (via dns-mapper)

    • Hostname-to-IP mapping
    • Wildcard pattern support
    • Automatic cache management
    • Custom dialer integration
  • Security

    • TLS/SSL configuration
    • Custom certificate handling
    • Proxy authentication support
    • Network interface binding (ForceIP)
  • Performance

    • Connection pooling
    • HTTP/2 support
    • Keep-alive management
    • Compression control
  • Configuration

    • JSON/YAML/TOML support
    • Viper integration
    • Validation with struct tags
    • Default configurations

Installation

go get github.com/nabbar/golib/httpcli
Dependencies
github.com/nabbar/golib/atomic          # Atomic value wrappers
github.com/nabbar/golib/certificates    # TLS configuration
github.com/nabbar/golib/duration        # Duration parsing
github.com/nabbar/golib/errors          # Error handling
github.com/nabbar/golib/network         # Network utilities
github.com/go-playground/validator/v10  # Configuration validation

Architecture

Package Structure
httpcli/
├── cli.go                    # Main client functions
├── options.go                # Configuration structures
├── errors.go                 # Error definitions
└── dns-mapper/               # DNS mapping subpackage
    ├── interface.go          # DNSMapper interface
    ├── config.go             # Configuration
    ├── model.go              # Core implementation
    ├── transport.go          # HTTP transport
    ├── collection.go         # DNS mapping storage
    ├── cache.go              # Cache management
    └── part.go               # Utility functions
Component Diagram
┌──────────────────────────────────────────────────┐
│              httpcli Package                      │
│  HTTP Client Management & Configuration          │
└──────────┬───────────────────────────────────────┘
           │
     ┌─────▼─────────┐
     │   GetClient   │  ← Main entry point
     └─────┬─────────┘
           │
     ┌─────▼─────────────────┐
     │  DefaultDNSMapper     │  ← DNS mapper singleton
     └─────┬─────────────────┘
           │
┌──────────▼────────────────────────────────────────┐
│         dns-mapper Subpackage                     │
│  Custom DNS Resolution & Transport                │
└──────────┬──────────┬──────────┬─────────────────┘
           │          │          │
    ┌──────▼────┐ ┌──▼──────┐ ┌─▼────────┐
    │Collection │ │Transport│ │  Cache   │
    │(Mappings) │ │(HTTP)   │ │(Auto-    │
    │           │ │         │ │ cleanup) │
    └───────────┘ └─────────┘ └──────────┘
Integration Flow
Application Code
      │
      ↓
httpcli.GetClient()
      │
      ↓
DefaultDNSMapper()
      │
      ├──→ DNS Mapping (hostname → IP)
      ├──→ Custom Transport
      └──→ HTTP Client
            │
            ↓
      http.Request
            │
            ↓
  DialContext (custom)
            │
            ↓
  Resolved Connection

Quick Start

Basic HTTP Client
package main

import (
    "fmt"
    "io"
    "github.com/nabbar/golib/httpcli"
)

func main() {
    // Get default client
    client := httpcli.GetClient()
    
    // Make HTTP request
    resp, err := client.Get("https://api.example.com/v1/status")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    
    // Read response
    body, _ := io.ReadAll(resp.Body)
    fmt.Printf("Status: %s\n", resp.Status)
    fmt.Printf("Body: %s\n", body)
}
With Custom DNS Mapping
package main

import (
    "context"
    "time"
    
    "github.com/nabbar/golib/httpcli"
    htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
    libdur "github.com/nabbar/golib/duration"
)

func main() {
    // Create DNS mapper configuration
    cfg := &htcdns.Config{
        DNSMapper: map[string]string{
            // Map hostname:port to IP:port
            "api.example.com:443":   "192.168.1.100:8443",
            "test.example.com:*":    "127.0.0.1:*",
        },
        TimerClean: libdur.ParseDuration(5 * time.Minute),
    }
    
    // Create DNS mapper
    mapper := htcdns.New(context.Background(), cfg, nil, nil)
    defer mapper.Close()
    
    // Set as default mapper
    httpcli.SetDefaultDNSMapper(mapper)
    
    // Get client with DNS mapping
    client := httpcli.GetClient()
    
    // Requests will use mapped addresses
    resp, _ := client.Get("https://api.example.com/health")
    defer resp.Body.Close()
    
    fmt.Printf("Connected to: %s\n", resp.Request.Host)
}
With TLS Configuration
package main

import (
    "context"
    "time"
    
    "github.com/nabbar/golib/httpcli"
    htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
    libtls "github.com/nabbar/golib/certificates"
    libdur "github.com/nabbar/golib/duration"
)

func main() {
    // Create TLS configuration
    tlsCfg := &libtls.Config{
        // Configure your TLS settings
        // See certificates package documentation
    }
    
    // Create DNS mapper with TLS
    cfg := &htcdns.Config{
        DNSMapper: map[string]string{
            "secure.example.com:443": "10.0.0.1:443",
        },
        TimerClean: libdur.ParseDuration(3 * time.Minute),
        Transport: htcdns.TransportConfig{
            TLSConfig:             tlsCfg,
            TimeoutTLSHandshake:   libdur.ParseDuration(10 * time.Second),
            DisableHTTP2:          false,
            DisableKeepAlive:      false,
            MaxIdleConns:          100,
            MaxIdleConnsPerHost:   10,
        },
    }
    
    mapper := htcdns.New(context.Background(), cfg, nil, nil)
    defer mapper.Close()
    
    httpcli.SetDefaultDNSMapper(mapper)
    
    client := httpcli.GetClient()
    resp, _ := client.Get("https://secure.example.com")
    defer resp.Body.Close()
}

Core Package

Main Functions
GetClient()

Returns the default HTTP client configured with the default DNS mapper.

client := httpcli.GetClient()

Returns: *http.Client with custom transport

Thread-Safe: Yes

DefaultDNSMapper()

Returns the default DNS mapper instance. Creates a new one with sensible defaults if not yet initialized.

mapper := httpcli.DefaultDNSMapper()
mapper.Add("example.com:80", "127.0.0.1:8080")

Returns: htcdns.DNSMapper

Thread-Safe: Yes, uses atomic values

SetDefaultDNSMapper(d DNSMapper)

Replaces the default DNS mapper with a custom instance. The old mapper is automatically closed.

customMapper := htcdns.New(ctx, cfg, nil, nil)
httpcli.SetDefaultDNSMapper(customMapper)

Parameters:

  • d: New DNS mapper instance (non-nil)

Thread-Safe: Yes

Configuration Types
Options

Main configuration structure for HTTP client options.

type Options struct {
    Timeout            time.Duration  // Request timeout
    DisableKeepAlive   bool          // Disable HTTP keep-alive
    DisableCompression bool          // Disable response compression
    Http2              bool          // Enable HTTP/2
    TLS                OptionTLS     // TLS configuration
    ForceIP            OptionForceIP // Network interface binding
    Proxy              OptionProxy   // Proxy configuration
}
OptionTLS

TLS/SSL configuration options.

type OptionTLS struct {
    Enable bool                // Enable TLS
    Config libtls.Config      // TLS configuration
}
OptionForceIP

Force connections through specific network interfaces.

type OptionForceIP struct {
    Enable bool                      // Enable ForceIP
    Net    libptc.NetworkProtocol   // Network protocol (IPv4/IPv6)
    IP     string                   // Bind to specific IP
    Local  string                   // Local address
}
OptionProxy

HTTP/HTTPS proxy configuration with authentication.

type OptionProxy struct {
    Enable   bool      // Enable proxy
    Endpoint *url.URL  // Proxy endpoint
    Username string    // Proxy username
    Password string    // Proxy password
}
Error Codes
const (
    ErrorParamEmpty         // At least one parameter is empty
    ErrorParamInvalid       // At least one parameter is invalid
    ErrorValidatorError     // Configuration validation failed
    ErrorClientTransportHttp2 // HTTP/2 configuration error
)

Usage:

if err != nil {
    if errors.Is(err, httpcli.ErrorValidatorError) {
        // Handle validation error
    }
}

DNS Mapper Subpackage

The dns-mapper subpackage provides advanced DNS resolution control for HTTP clients.

Purpose

Override DNS resolution for:

  • Testing: Point production domains to test servers
  • Development: Local service testing
  • Routing: Custom traffic routing
  • Failover: Quick DNS-level failover
DNSMapper Interface
type DNSMapper interface {
    // Mapping management
    Add(from, to string)
    Get(from string) string
    Del(from string)
    Len() int
    Walk(func(from, to string) bool)
    
    // DNS resolution
    Clean(endpoint string) (host, port string, err error)
    Search(endpoint string) (string, error)
    SearchWithCache(endpoint string) (string, error)
    
    // Network operations
    DialContext(ctx context.Context, network, address string) (net.Conn, error)
    
    // HTTP client integration
    Transport(cfg TransportConfig) *http.Transport
    TransportWithTLS(cfg TransportConfig, ssl *tls.Config) *http.Transport
    Client(cfg TransportConfig) *http.Client
    DefaultTransport() *http.Transport
    DefaultClient() *http.Client
    
    // Configuration
    GetConfig() Config
    RegisterTransport(t *http.Transport)
    
    // Lifecycle
    TimeCleaner(ctx context.Context, dur time.Duration)
    Close() error
}
Configuration
Config Structure
type Config struct {
    // DNSMapper maps hostname:port to IP:port
    // Supports wildcards: "*.example.com:*" → "192.168.1.1:*"
    DNSMapper map[string]string
    
    // TimerClean defines cleanup interval for cache
    TimerClean libdur.Duration
    
    // Transport configuration for HTTP client
    Transport TransportConfig
    
    // TLSConfig for HTTPS connections
    TLSConfig *tls.Config
}
TransportConfig Structure
type TransportConfig struct {
    Proxy     *url.URL        // HTTP/HTTPS proxy
    TLSConfig *libtls.Config  // TLS configuration
    
    // Protocol options
    DisableHTTP2       bool
    DisableKeepAlive   bool
    DisableCompression bool
    
    // Connection limits
    MaxIdleConns        int
    MaxIdleConnsPerHost int
    MaxConnsPerHost     int
    
    // Timeouts
    TimeoutGlobal         libdur.Duration
    TimeoutKeepAlive      libdur.Duration
    TimeoutTLSHandshake   libdur.Duration
    TimeoutExpectContinue libdur.Duration
    TimeoutIdleConn       libdur.Duration
    TimeoutResponseHeader libdur.Duration
}
DNS Mapping Patterns
Exact Match

Map specific hostname and port:

mapper.Add("api.example.com:443", "192.168.1.100:8443")

Request to https://api.example.com → connects to 192.168.1.100:8443

Wildcard Port

Map hostname with any port:

mapper.Add("api.example.com:*", "192.168.1.100:*")
  • https://api.example.com:443192.168.1.100:443
  • http://api.example.com:80192.168.1.100:80
Wildcard Hostname

Map subdomain pattern:

mapper.Add("*.example.com:*", "192.168.1.100:*")
  • api.example.com:443192.168.1.100:443
  • test.example.com:80192.168.1.100:80
DNS Mapper Operations
Creating DNS Mapper
ctx := context.Background()

cfg := &htcdns.Config{
    DNSMapper: map[string]string{
        "service1.local:80": "127.0.0.1:8001",
        "service2.local:80": "127.0.0.1:8002",
    },
    TimerClean: libdur.ParseDuration(5 * time.Minute),
}

mapper := htcdns.New(ctx, cfg, nil, nil)
defer mapper.Close()
Dynamic Mapping
// Add mapping at runtime
mapper.Add("new-service.local:80", "127.0.0.1:9000")

// Get mapped address
addr := mapper.Get("new-service.local:80")
fmt.Println("Mapped to:", addr)

// Remove mapping
mapper.Del("old-service.local:80")

// Get count
count := mapper.Len()
fmt.Printf("Total mappings: %d\n", count)
Walking Mappings
mapper.Walk(func(from, to string) bool {
    fmt.Printf("%s → %s\n", from, to)
    return true // Continue walking
})
Cache Management
// Search with cache (faster for repeated lookups)
addr, err := mapper.SearchWithCache("api.example.com:443")

// Search without cache (always performs DNS resolution)
addr, err := mapper.Search("api.example.com:443")

// Start automatic cache cleanup
mapper.TimeCleaner(ctx, 5*time.Minute)
Custom Transport
Create Custom Transport
transport := mapper.Transport(htcdns.TransportConfig{
    DisableHTTP2:         false,
    MaxIdleConns:         100,
    MaxIdleConnsPerHost:  10,
    TimeoutGlobal:        libdur.ParseDuration(30 * time.Second),
})

client := &http.Client{
    Transport: transport,
    Timeout:   30 * time.Second,
}
With Custom TLS
tlsConfig := &tls.Config{
    InsecureSkipVerify: false,
    // ... other TLS options
}

transport := mapper.TransportWithTLS(htcdns.TransportConfig{
    MaxIdleConns: 50,
}, tlsConfig)

Configuration

JSON Configuration
{
  "dns-mapper": {
    "api.example.com:443": "192.168.1.100:8443",
    "test.example.com:80": "127.0.0.1:8080"
  },
  "timer-clean": "3m",
  "transport": {
    "disable-http2": false,
    "disable-keepalive": false,
    "disable-compression": false,
    "max-idle-conns": 50,
    "max-idle-conns-per-host": 5,
    "max-conns-per-host": 25,
    "timeout-global": "30s",
    "timeout-keepalive": "15s",
    "timeout-tls-handshake": "10s",
    "timeout-expect-continue": "3s",
    "timeout-idle-conn": "30s",
    "timeout-response-header": "0s"
  }
}
YAML Configuration
dns-mapper:
  api.example.com:443: 192.168.1.100:8443
  test.example.com:80: 127.0.0.1:8080

timer-clean: 3m

transport:
  disable-http2: false
  disable-keepalive: false
  max-idle-conns: 50
  max-idle-conns-per-host: 5
  timeout-global: 30s
  timeout-keepalive: 15s
Loading Configuration
import (
    "encoding/json"
    "os"
    
    htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
)

func loadConfig(path string) (*htcdns.Config, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, err
    }
    
    var cfg htcdns.Config
    if err := json.Unmarshal(data, &cfg); err != nil {
        return nil, err
    }
    
    // Validate configuration
    if err := cfg.Validate(); err != nil {
        return nil, err
    }
    
    return &cfg, nil
}

Use Cases

1. Testing Against Production-Like Environment
// Test production domains pointing to staging servers
func setupTestEnvironment() {
    cfg := &htcdns.Config{
        DNSMapper: map[string]string{
            "api.production.com:443":   "staging.internal:8443",
            "db.production.com:5432":   "test-db.internal:5432",
            "cache.production.com:6379": "localhost:6379",
        },
        TimerClean: libdur.ParseDuration(10 * time.Minute),
    }
    
    mapper := htcdns.New(context.Background(), cfg, nil, nil)
    httpcli.SetDefaultDNSMapper(mapper)
    
    // Now all HTTP clients use test environment
    client := httpcli.GetClient()
    resp, _ := client.Get("https://api.production.com/v1/test")
    // Actually connects to staging.internal:8443
}
2. Local Development with Service Mesh
// Route microservices to local ports
func setupLocalDevelopment() {
    services := map[string]string{
        "auth-service:8080":    "localhost:9001",
        "user-service:8080":    "localhost:9002",
        "order-service:8080":   "localhost:9003",
        "payment-service:8080": "localhost:9004",
    }
    
    cfg := &htcdns.Config{
        DNSMapper:  services,
        TimerClean: libdur.ParseDuration(5 * time.Minute),
    }
    
    mapper := htcdns.New(context.Background(), cfg, nil, nil)
    httpcli.SetDefaultDNSMapper(mapper)
}
3. A/B Testing with Traffic Routing
// Route subset of traffic to new service version
func setupABTesting(useVersionB bool) {
    targetService := "v1.api.example.com:443"
    if useVersionB {
        targetService = "v2.api.example.com:443"
    }
    
    cfg := &htcdns.Config{
        DNSMapper: map[string]string{
            "api.example.com:443": targetService,
        },
        TimerClean: libdur.ParseDuration(1 * time.Minute),
    }
    
    mapper := htcdns.New(context.Background(), cfg, nil, nil)
    httpcli.SetDefaultDNSMapper(mapper)
}
4. Failover and High Availability
// Quick failover by updating DNS mapper
func performFailover(primary, backup string) {
    mapper := httpcli.DefaultDNSMapper()
    
    // Test primary
    if !isHealthy(primary) {
        log.Printf("Primary %s unhealthy, failing over to %s", primary, backup)
        mapper.Add("api.example.com:443", backup)
    } else {
        mapper.Add("api.example.com:443", primary)
    }
}

func isHealthy(addr string) bool {
    // Perform health check
    return true
}
5. Corporate Proxy Integration
// Use corporate proxy with authentication
func setupCorporateProxy() {
    proxyURL, _ := url.Parse("http://proxy.corp.com:8080")
    
    cfg := &htcdns.Config{
        DNSMapper: map[string]string{
            "external-api.com:443": "external-api.com:443",
        },
        TimerClean: libdur.ParseDuration(10 * time.Minute),
        Transport: htcdns.TransportConfig{
            Proxy:               proxyURL,
            MaxIdleConns:        50,
            TimeoutGlobal:       libdur.ParseDuration(60 * time.Second),
        },
    }
    
    mapper := htcdns.New(context.Background(), cfg, nil, nil)
    httpcli.SetDefaultDNSMapper(mapper)
}

Performance

Benchmarks
Operation Time/op Allocations
DNS Mapper Lookup (cached) ~100ns 0 allocs
DNS Mapper Lookup (uncached) ~500ns 2 allocs
Custom Transport Creation ~5µs 15 allocs
HTTP Client Creation ~10µs 25 allocs

Benchmarks on Go 1.21, Linux AMD64

Memory Efficiency
  • DNS Mapper: ~100 bytes per mapping + cache overhead
  • Transport: Single shared instance (zero overhead after initialization)
  • Client: Lightweight wrapper (~50 bytes)
Connection Pooling

The package automatically manages connection pooling:

Transport: htcdns.TransportConfig{
    MaxIdleConns:        100,  // Total idle connections
    MaxIdleConnsPerHost:  10,  // Idle per host
    MaxConnsPerHost:      50,  // Total per host
}

Best Practices:

  • MaxIdleConns: Set to expected concurrent requests
  • MaxIdleConnsPerHost: Typically 10-20 for balanced services
  • MaxConnsPerHost: 2-3x MaxIdleConnsPerHost
Cache Performance

DNS mapper includes automatic caching:

// First lookup: performs DNS resolution (~500ns)
addr1, _ := mapper.SearchWithCache("api.example.com:443")

// Subsequent lookups: from cache (~100ns)
addr2, _ := mapper.SearchWithCache("api.example.com:443")

Cache is automatically cleaned based on TimerClean configuration.

Best Practices

Always Close Resources
// ✅ Good: Proper cleanup
mapper := htcdns.New(ctx, cfg, nil, nil)
defer mapper.Close()
Reuse HTTP Clients
// ✅ Good: Single client for multiple requests
client := httpcli.GetClient()
for _, url := range urls {
    resp, _ := client.Get(url)
    // Process response
    resp.Body.Close()
}

// ❌ Bad: Creating new client each time
for _, url := range urls {
    client := httpcli.GetClient()  // Don't do this!
    resp, _ := client.Get(url)
}
Configure Timeouts
// ✅ Good: Explicit timeouts
cfg := &htcdns.Config{
    Transport: htcdns.TransportConfig{
        TimeoutGlobal:       libdur.ParseDuration(30 * time.Second),
        TimeoutTLSHandshake: libdur.ParseDuration(10 * time.Second),
    },
}
Validate Configuration
// ✅ Good: Validate before use
cfg := &htcdns.Config{
    DNSMapper: mappings,
}

if err := cfg.Validate(); err != nil {
    return fmt.Errorf("invalid config: %w", err)
}
Use Context for Cancellation
// ✅ Good: Context-aware operations
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

mapper := htcdns.New(ctx, cfg, nil, nil)
defer mapper.Close()
Handle DNS Mapper Lifecycle
// ✅ Good: Proper lifecycle management
func setupClient(ctx context.Context) (*http.Client, func()) {
    mapper := htcdns.New(ctx, cfg, nil, nil)
    httpcli.SetDefaultDNSMapper(mapper)
    
    cleanup := func() {
        mapper.Close()
    }
    
    return httpcli.GetClient(), cleanup
}

// Usage
client, cleanup := setupClient(ctx)
defer cleanup()

Testing

See TESTING.md for comprehensive testing documentation.

Quick Test
# Run all tests
go test ./...

# With race detector
CGO_ENABLED=1 go test -race ./...

# With coverage
go test -cover ./...
Current Test Status
  • httpcli: 34/34 tests passing (100%) ✅
  • dns-mapper: 26/26 tests passing (100%) ✅
  • Total Tests: 60 specs passing
  • httpcli Coverage: 69.0%
  • dns-mapper Coverage: 72.5%
  • Average Coverage: ~70.8%

Contributing

Contributions are welcome! Please follow these guidelines:

Code Guidelines:

  • Do not use AI for package implementation
  • AI may assist with tests, documentation, and bug fixes
  • All contributions must pass go test -race
  • Maintain or improve test coverage
  • Follow existing code style and patterns

Documentation:

  • Update README.md for new features
  • Add examples for common use cases
  • Use English for all documentation and comments
  • Keep documentation synchronized with code

Testing:

  • Write tests for all new features
  • Test edge cases and error conditions
  • Verify thread safety with race detector
  • Add comments explaining complex scenarios

See CONTRIBUTING.md for detailed guidelines.

Future Enhancements

Potential improvements for future versions:

DNS Mapper Features:

  • Regex-based hostname matching
  • Priority-based mapping resolution
  • DNS TTL support
  • Metrics and observability hooks
  • Dynamic mapping updates via API

Client Features:

  • Request/response middleware support
  • Automatic retry with backoff
  • Circuit breaker integration
  • Request tracing and logging
  • Connection metrics export

Performance:

  • Zero-allocation DNS lookups
  • Optimized cache data structures
  • Background DNS pre-resolution
  • Connection warming

Integration:

  • Service mesh integration (Istio, Linkerd)
  • Kubernetes service discovery
  • Consul/etcd dynamic configuration
  • OpenTelemetry instrumentation

Suggestions and contributions are welcome via GitHub issues.

AI Transparency Notice

In accordance with Article 50.4 of the EU AI Act, AI assistance has been used for testing, documentation, and bug fixing under human supervision.

License

MIT License - See LICENSE file for details.

Resources

External Resources

Version: 1.0
Last Updated: November 2024
Maintained By: golib Contributors

Documentation

Overview

Package httpcli provides advanced HTTP client management with DNS mapping capabilities.

This package offers a simplified API for creating and configuring HTTP clients with integrated DNS mapping support through the dns-mapper subpackage. It enables custom DNS resolution, TLS configuration, and flexible transport options.

Key features:

  • Default HTTP client with sensible configuration
  • Custom DNS mapping for hostname resolution override
  • TLS/SSL configuration support
  • Proxy configuration with authentication
  • Thread-safe singleton DNS mapper management
  • Automatic resource cleanup and lifecycle management

Basic usage:

import "github.com/nabbar/golib/httpcli"

// Get default HTTP client
client := httpcli.GetClient()

// Make HTTP request
resp, err := client.Get("https://api.example.com")
if err != nil {
    panic(err)
}
defer resp.Body.Close()

With custom DNS mapping:

import (
    "github.com/nabbar/golib/httpcli"
    htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
)

// Create DNS mapper
cfg := &htcdns.Config{
    DNSMapper: map[string]string{
        "api.example.com:443": "192.168.1.100:8443",
    },
}
mapper := htcdns.New(context.Background(), cfg, nil, nil)
defer mapper.Close()

// Set as default
httpcli.SetDefaultDNSMapper(mapper)

// Get client with custom DNS mapping
client := httpcli.GetClient()

Index

Constants

View Source
const (
	ErrorParamEmpty           liberr.CodeError = iota + liberr.MinPkgHttpCli // At least one given parameter is empty
	ErrorParamInvalid                                                        // At least one given parameter is invalid
	ErrorValidatorError                                                      // Configuration validation failed
	ErrorClientTransportHttp2                                                // HTTP/2 transport configuration error
)

Error codes for HTTP client operations. These errors are registered with the golib/errors package for consistent error handling.

View Source
const (
	// ClientTimeout5Sec is a default timeout constant of 5 seconds for HTTP client operations.
	ClientTimeout5Sec = 5 * time.Second // nolint
)

Variables

This section is empty.

Functions

func DefaultConfig added in v1.10.0

func DefaultConfig(indent string) []byte

DefaultConfig returns the default DNS mapper configuration in JSON format. The indent parameter specifies the indentation string for pretty-printing.

This is a convenience function that delegates to the dns-mapper package's DefaultConfig function. The returned JSON can be used as a template for creating custom configurations.

Parameters:

  • indent: String to use for indentation (e.g., " " for 2 spaces)

Returns a byte slice containing the JSON-formatted default configuration.

Example:

config := httpcli.DefaultConfig("  ")
fmt.Println(string(config))

func DefaultDNSMapper added in v1.13.10

func DefaultDNSMapper() htcdns.DNSMapper

DefaultDNSMapper returns the default DNS mapper instance. If no DNS mapper has been set via SetDefaultDNSMapper, this function creates a new one using initDNSMapper with default configuration.

This function is thread-safe and uses atomic operations to ensure concurrent access is handled correctly. The DNS mapper is created only once on first access (lazy initialization).

Returns the global DNS mapper instance that can be used to:

  • Add custom hostname-to-IP mappings
  • Create HTTP clients with custom DNS resolution
  • Configure custom transport options

Example:

mapper := httpcli.DefaultDNSMapper()
mapper.Add("api.example.com:443", "192.168.1.100:8443")
client := httpcli.GetClient()

func GetClient

func GetClient() *http.Client

GetClient returns an HTTP client configured with the default DNS mapper. This is the primary entry point for obtaining HTTP clients in this package.

The returned client includes:

  • Custom DNS resolution via the default DNS mapper
  • Connection pooling and keep-alive
  • Configured transport with timeouts
  • HTTP/2 support (if enabled in DNS mapper config)

The client is safe for concurrent use and reuses connections for efficiency. Always reuse the returned client for multiple requests instead of calling GetClient repeatedly.

Example:

client := httpcli.GetClient()
resp, err := client.Get("https://api.example.com")
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

func SetDefaultDNSMapper added in v1.13.10

func SetDefaultDNSMapper(d htcdns.DNSMapper)

SetDefaultDNSMapper replaces the default DNS mapper with a custom instance. The previous DNS mapper (if any) is automatically closed to free resources.

This function is thread-safe and uses atomic operations to ensure the swap is performed correctly even under concurrent access.

Parameters:

  • d: The new DNS mapper instance to use as default. If nil, the function returns without action.

The old DNS mapper is automatically closed when replaced, ensuring proper cleanup of goroutines, timers, and other resources associated with the old instance.

Example:

// Create custom DNS mapper
cfg := &htcdns.Config{
    DNSMapper: map[string]string{
        "api.example.com:443": "192.168.1.100:8443",
    },
}
customMapper := htcdns.New(context.Background(), cfg, nil, nil)

// Set as default (old mapper is automatically closed)
httpcli.SetDefaultDNSMapper(customMapper)

Types

type FctHttpClient added in v1.10.0

type FctHttpClient func() *http.Client

FctHttpClient is a function type that returns an HTTP client. This type is used for dependency injection and testing purposes.

type FctHttpClientSrv added in v1.13.10

type FctHttpClientSrv func(servername string) *http.Client

FctHttpClientSrv is a function type that returns an HTTP client configured for a specific server. The servername parameter can be used to select different client configurations.

type HttpClient added in v1.13.7

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

HttpClient defines the minimal interface for HTTP operations. This interface is compatible with *http.Client and can be used for testing with mock clients.

type OptionForceIP added in v1.9.0

type OptionForceIP struct {
	Enable bool                   `json:"enable" yaml:"enable" toml:"enable" mapstructure:"enable"`                                     // Enable ForceIP feature
	Net    libptc.NetworkProtocol `json:"net,omitempty" yaml:"net,omitempty" toml:"net,omitempty" mapstructure:"net,omitempty"`         // Network protocol (IPv4/IPv6)
	IP     string                 `json:"ip,omitempty" yaml:"ip,omitempty" toml:"ip,omitempty" mapstructure:"ip,omitempty"`             // Specific IP address to bind to
	Local  string                 `json:"local,omitempty" yaml:"local,omitempty" toml:"local,omitempty" mapstructure:"local,omitempty"` // Local address for binding
}

OptionForceIP configures network interface binding for HTTP connections. This allows forcing connections through specific network interfaces or IP addresses, useful for multi-homed systems or testing specific network paths.

type OptionProxy added in v1.11.3

type OptionProxy struct {
	Enable   bool     `json:"enable" yaml:"enable" toml:"enable" mapstructure:"enable"`         // Enable proxy
	Endpoint *url.URL `json:"endpoint" yaml:"endpoint" toml:"endpoint" mapstructure:"endpoint"` // Proxy server URL
	Username string   `json:"username" yaml:"username" toml:"username" mapstructure:"username"` // Proxy authentication username
	Password string   `json:"password" yaml:"password" toml:"password" mapstructure:"password"` // Proxy authentication password
}

OptionProxy configures HTTP/HTTPS proxy settings with authentication support. Supports both authenticated and unauthenticated proxies.

type OptionTLS added in v1.9.0

type OptionTLS struct {
	Enable bool          `json:"enable" yaml:"enable" toml:"enable" mapstructure:"enable"` // Enable TLS/SSL
	Config libtls.Config `json:"tls" yaml:"tls" toml:"tls" mapstructure:"tls"`             // TLS configuration (certificates, validation, etc.)
}

OptionTLS configures TLS/SSL settings for HTTPS connections. Provides fine-grained control over certificate validation, cipher suites, and other TLS-related parameters.

type Options added in v1.9.0

type Options struct {
	Timeout            time.Duration `json:"timeout" yaml:"timeout" toml:"timeout" mapstructure:"timeout"`
	DisableKeepAlive   bool          `json:"disable-keep-alive" yaml:"disable-keep-alive" toml:"disable-keep-alive" mapstructure:"disable-keep-alive"`
	DisableCompression bool          `json:"disable-compression" yaml:"disable-compression" toml:"disable-compression" mapstructure:"disable-compression"`
	Http2              bool          `json:"http2" yaml:"http2" toml:"http2" mapstructure:"http2"`
	TLS                OptionTLS     `json:"tls" yaml:"tls" toml:"tls" mapstructure:"tls"`
	ForceIP            OptionForceIP `json:"force_ip" yaml:"force_ip" toml:"force_ip" mapstructure:"force_ip"`
	Proxy              OptionProxy   `json:"proxy" yaml:"proxy" toml:"proxy" mapstructure:"proxy"`
}

Options defines the complete HTTP client configuration. This structure provides comprehensive control over client behavior including timeouts, protocol options, security settings, and network configuration.

All fields support JSON, YAML, TOML, and Viper configuration formats through struct tags.

func (Options) GetClient added in v1.9.0

func (o Options) GetClient(def libtls.TLSConfig, servername string) (*http.Client, liberr.Error)

GetClient creates and returns an HTTP client based on the options configuration. Currently, this method returns the default client and ignores the parameters.

Parameters:

  • def: Default TLS configuration (currently unused)
  • servername: Server name for SNI (currently unused)

Returns the default HTTP client configured with the global DNS mapper, along with a nil error.

Note: This method is provided for interface compatibility and may be enhanced in future versions to use the provided parameters.

func (Options) Validate added in v1.9.0

func (o Options) Validate() liberr.Error

Validate checks if the Options configuration is valid. It uses struct tags and the validator package to ensure all fields meet their specified constraints.

Returns a liberr.Error containing all validation errors, or nil if validation succeeds. The error includes detailed information about which fields failed validation and why.

Example:

opts := httpcli.Options{
    Timeout: 30 * time.Second,
}
if err := opts.Validate(); err != nil {
    log.Fatal("Invalid configuration:", err)
}

Directories

Path Synopsis
Package dns_mapper provides custom DNS hostname mapping and dialer functionality for HTTP clients.
Package dns_mapper provides custom DNS hostname mapping and dialer functionality for HTTP clients.

Jump to

Keyboard shortcuts

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