Skip to content

Instantly share code, notes, and snippets.

@ometa
Created February 25, 2020 16:05
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save ometa/71d23ed48c03c003f6e4910648612859 to your computer and use it in GitHub Desktop.
Save ometa/71d23ed48c03c003f6e4910648612859 to your computer and use it in GitHub Desktop.
Golang HTTP Client using SOCKS5 proxy and DialContext
// Golang example that creates an http client that leverages a SOCKS5 proxy and a DialContext
func NewClientFromEnv() (*http.Client, error) {
proxyHost := os.Getenv("PROXY_HOST")
baseDialer := &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}
var dialContext DialContext
if proxyHost != "" {
dialSocksProxy, err := proxy.SOCKS5("tcp", proxyHost, nil, baseDialer)
if err != nil {
return nil, errors.Wrap(err, "Error creating SOCKS5 proxy")
}
if contextDialer, ok := dialSocksProxy.(proxy.ContextDialer); ok {
dialContext = contextDialer.DialContext
} else {
return nil, errors.New("Failed type assertion to DialContext")
}
logger.Debug("Using SOCKS5 proxy for http client",
zap.String("host", proxyHost),
)
} else {
dialContext = (baseDialer).DialContext
}
httpClient = newClient(dialContext)
return httpClient, nil
}
func newClient(dialContext DialContext) *http.Client {
return &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: dialContext,
MaxIdleConns: 10,
IdleConnTimeout: 60 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1,
},
}
}
@karelbilek
Copy link

Hm. Why do I need all this DialContext: dialContext when it already uses http.ProxyFromEnvironment?

@mikebaldry
Copy link

Hm. Why do I need all this DialContext: dialContext when it already uses http.ProxyFromEnvironment?

this code could use any proxy at all, not just one from the environment, which is quite limiting, if say, for instance, you wanted to use 10 different proxies at the same time, or round robin between them, etc...

I agree in this example, to make it clearer, I'd not use os.Getenv("PROXY_HOST") and not http.ProxyFromEnvironment!

@karelbilek
Copy link

Ah makes sense, thanks

@suntong
Copy link

suntong commented Jul 7, 2021

in this example, to make it clearer, I'd not use os.Getenv("PROXY_HOST") and not http.ProxyFromEnvironment!

How to use it then? I can't see how I can pass my SOCKS5 proxy setting to the code.

Would you give another complete demo code to use it please?

resp, err := http.Get("http://example.com/") 
if err != nil { // handle error } 

defer resp.Body.Close() 
body, err := ioutil.ReadAll(resp.Body)

@zendesk-thittesdorf
Copy link

in this example, to make it clearer, I'd not use os.Getenv("PROXY_HOST") and not http.ProxyFromEnvironment!

How to use it then? I can't see how I can pass my SOCKS5 proxy setting to the code.

Would you give another complete demo code to use it please?

resp, err := http.Get("http://example.com/") 
if err != nil { // handle error } 

defer resp.Body.Close() 
body, err := ioutil.ReadAll(resp.Body)
client := NewClientFromEnv()
resp, err := client.Get("http://example.com")

@suntong
Copy link

suntong commented Aug 13, 2021

client := NewClientFromEnv()
resp, err := client.Get("http://example.com")

Thanks, and where can I find the definition of such NewClientFromEnv() please?

@volvinbur1
Copy link

volvinbur1 commented Nov 29, 2021

Thanks, and where can I find the definition of such NewClientFromEnv() please?

@suntong, Here it is. It is a part of snippet

@makew0rld
Copy link

Another way to get the dial context:

    dialer, err := proxy.SOCKS5("tcp", proxyUrl, nil, proxy.Direct)
    dialContext := func(ctx context.Context, network, address string) (net.Conn, error) {
        return dialer.Dial(network, address)
    }

Source: https://stackoverflow.com/a/63661992

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment