| package cliproxy |
|
|
| import ( |
| "context" |
| "net" |
| "net/http" |
| "net/url" |
| "strings" |
| "sync" |
|
|
| coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth" |
| log "github.com/sirupsen/logrus" |
| "golang.org/x/net/proxy" |
| ) |
|
|
| |
| |
| type defaultRoundTripperProvider struct { |
| mu sync.RWMutex |
| cache map[string]http.RoundTripper |
| } |
|
|
| func newDefaultRoundTripperProvider() *defaultRoundTripperProvider { |
| return &defaultRoundTripperProvider{cache: make(map[string]http.RoundTripper)} |
| } |
|
|
| |
| func (p *defaultRoundTripperProvider) RoundTripperFor(auth *coreauth.Auth) http.RoundTripper { |
| if auth == nil { |
| return nil |
| } |
| proxyStr := strings.TrimSpace(auth.ProxyURL) |
| if proxyStr == "" { |
| return nil |
| } |
| p.mu.RLock() |
| rt := p.cache[proxyStr] |
| p.mu.RUnlock() |
| if rt != nil { |
| return rt |
| } |
| |
| proxyURL, errParse := url.Parse(proxyStr) |
| if errParse != nil { |
| log.Errorf("parse proxy URL failed: %v", errParse) |
| return nil |
| } |
| var transport *http.Transport |
| |
| if proxyURL.Scheme == "socks5" { |
| |
| username := proxyURL.User.Username() |
| password, _ := proxyURL.User.Password() |
| proxyAuth := &proxy.Auth{User: username, Password: password} |
| dialer, errSOCKS5 := proxy.SOCKS5("tcp", proxyURL.Host, proxyAuth, proxy.Direct) |
| if errSOCKS5 != nil { |
| log.Errorf("create SOCKS5 dialer failed: %v", errSOCKS5) |
| return nil |
| } |
| |
| transport = &http.Transport{ |
| DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { |
| return dialer.Dial(network, addr) |
| }, |
| } |
| } else if proxyURL.Scheme == "http" || proxyURL.Scheme == "https" { |
| |
| transport = &http.Transport{Proxy: http.ProxyURL(proxyURL)} |
| } else { |
| log.Errorf("unsupported proxy scheme: %s", proxyURL.Scheme) |
| return nil |
| } |
| p.mu.Lock() |
| p.cache[proxyStr] = transport |
| p.mu.Unlock() |
| return transport |
| } |
|
|