Skip to content
CodeMonkeyKevinPublic

About

Forwarder is a production-ready, fast MITM proxy with PAC support. It's suitable for debugging, intercepting and manipulating HTTP traffic. It's used as a core component of Sauce Labs Sauce Connect Proxy.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1,896 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Upstream Proxy API - Forwarder Extension

This package adds a REST API to dynamically update the upstream proxy configuration at runtime without restarting the forwarder service.

Files Included

New Files (copy to repository root)

File Description
upstream.go Thread-safe upstream proxy manager
api_upstream.go REST API handlers for proxy management
upstream_test.go Unit tests for the manager
api_upstream_test.go Unit tests for the API handlers

Documentation

File Description
docs/api-upstream.md API documentation
patches/http_proxy.go.patch Optional changes to http_proxy.go
patches/run.go.patch Changes needed for command/run/run.go

Installation

Step 1: Copy New Files

Copy the following files to the root of the forwarder repository:

cp upstream.go api_upstream.go upstream_test.go api_upstream_test.go /path/to/forwarder/

Step 2: Integrate with Run Command

In command/run/run.go, you need to:

  1. Create the upstream proxy manager
  2. Wire it to the proxy config
  3. Add the API endpoint

Here's the integration code to add:

import (
    // ... existing imports ...
    "github.com/saucelabs/forwarder"
)

func runProxy(ctx context.Context, cfg *Config, logger log.StructuredLogger) error {
    // ... existing setup code ...

    // === NEW: Create upstream proxy manager ===
    upstreamManager := forwarder.NewUpstreamProxyManager(cfg.Proxy.UpstreamProxy)

    // === NEW: Configure proxy to use the manager ===
    proxyConfig := forwarder.DefaultHTTPProxyConfig()
    // ... other config settings ...
    
    // Replace static upstream proxy with dynamic manager
    proxyConfig.UpstreamProxyFunc = upstreamManager.ProxyFunc()
    // Note: Don't set proxyConfig.UpstreamProxy when using the manager

    // === NEW: Add API endpoint ===
    extraEndpoints := []forwarder.APIEndpoint{
        forwarder.UpstreamProxyAPIEndpoint("/api/v1/upstream", upstreamManager, logger),
    }

    // Modify APIHandler creation to include extra endpoints
    apiHandler := forwarder.NewAPIHandler(
        "forwarder",
        promRegistry,
        readyFunc,
        extraEndpoints...,
    )

    // ... rest of existing code ...
}

Step 3: Run Tests

go test -v ./... -run "Upstream"

API Usage

Get Current Upstream Proxy

curl http://localhost:10000/api/v1/upstream

Response:

{"proxy": "http://proxy.example.com:8080"}

Or when in direct mode:

{"proxy": ""}

Set Upstream Proxy

curl -X PUT http://localhost:10000/api/v1/upstream \
  -H "Content-Type: application/json" \
  -d '{"proxy": "http://newproxy.example.com:8080"}'

Response:

{
  "proxy": "http://newproxy.example.com:8080",
  "message": "upstream proxy updated successfully"
}

Supported Proxy Schemes

  • http:// - HTTP proxy
  • https:// - HTTPS proxy
  • socks5:// - SOCKS5 proxy
  • socks5h:// - SOCKS5 proxy with DNS resolution on proxy

With Credentials

curl -X PUT http://localhost:10000/api/v1/upstream \
  -H "Content-Type: application/json" \
  -d '{"proxy": "http://user:password@proxy.example.com:8080"}'

Note: Credentials are redacted in GET responses for security.

Remove Upstream Proxy (Direct Mode)

curl -X DELETE http://localhost:10000/api/v1/upstream

Or:

curl -X PUT http://localhost:10000/api/v1/upstream \
  -H "Content-Type: application/json" \
  -d '{"proxy": ""}'

Architecture

Thread Safety

The UpstreamProxyManager uses Go's atomic.Pointer for lock-free reads, ensuring:

  • No blocking during proxy lookups (critical path)
  • Immediate visibility of updates to all goroutines
  • Safe concurrent access from multiple request handlers

Integration Points

┌─────────────────┐     ┌──────────────────────┐
│   API Server    │────▶│ UpstreamProxyManager │
│  (port 10000)   │     │   (atomic.Pointer)   │
└─────────────────┘     └──────────────────────┘
                                   │
                                   ▼
                        ┌──────────────────────┐
                        │    HTTPProxy         │
                        │  (uses ProxyFunc)    │
                        └──────────────────────┘
                                   │
                                   ▼
                        ┌──────────────────────┐
                        │  Upstream Proxy      │
                        │   (or direct)        │
                        └──────────────────────┘

Advanced Usage

Combining with PAC Files

If you're using PAC files for proxy selection, use ProxyFuncWithFallback:

upstreamManager := forwarder.NewUpstreamProxyManager(nil)

// PAC resolver as fallback
pacResolver := loadPACResolver()

proxyConfig.UpstreamProxyFunc = upstreamManager.ProxyFuncWithFallback(
    func(r *http.Request) (*url.URL, error) {
        result, err := pacResolver.FindProxyForURL(r.URL, r.URL.Hostname())
        if err != nil {
            return nil, err
        }
        return parseProxyResult(result)
    },
)

This way:

  • If the manager has a proxy set → use it
  • If the manager is in direct mode (nil) → fall back to PAC

Programmatic Updates

You can also update the proxy programmatically:

manager := forwarder.NewUpstreamProxyManager(nil)

// Later, update the proxy
newProxy, _ := url.Parse("http://newproxy:8080")
manager.Set(newProxy)

// Or remove it
manager.Set(nil)

License

Same as forwarder - MPL-2.0

About

Forwarder is a production-ready, fast MITM proxy with PAC support. It's suitable for debugging, intercepting and manipulating HTTP traffic. It's used as a core component of Sauce Labs Sauce Connect Proxy.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages