package proxy import ( "fmt" "net/http" "net/url" "golang.org/x/net/proxy" ) func GetTransport(proxy string) (http.RoundTripper, error) { if proxy == "" { return http.DefaultTransport, nil } proxyUrl, err := url.Parse(proxy) if err != nil { return nil, fmt.Errorf("failed to parse proxyUrl, url:%s, err: %w", proxy, err) } if proxyUrl.Host == "unix" && proxyUrl.Scheme == "socks5" && len(proxyUrl.Path) > 1 /* Path cannot be empty or just / */ { return unixSocks5Proxy(proxyUrl.Path) } return proxyHttp(proxyUrl) } func unixSocks5Proxy(path string) (http.RoundTripper, error) { // TODO: Auth? dialer, err := proxy.SOCKS5("unix", path, nil /*auth*/, nil) if err != nil { return nil, fmt.Errorf("failed to make socks proxy, path: %s, err: %w", path, err) } ctxDialer, ok := dialer.(proxy.ContextDialer) if !ok { panic("proxy.SOCKS5 did not return a ContextDialer") } trans := defaultTransport() trans.DialContext = ctxDialer.DialContext trans.Proxy = nil return trans, nil } func proxyHttp(proxyUrl *url.URL) (http.RoundTripper, error) { trans := defaultTransport() trans.Proxy = http.ProxyURL(proxyUrl) return trans, nil } func defaultTransport() *http.Transport { transPtr, ok := http.DefaultTransport.(*http.Transport) if !ok { panic("http.DefaultTransport is not a *http.Transport") } trans := transPtr.Clone() return trans }