package providers import ( "context" "net" "net/http" "strings" "sync" "time" tls "github.com/refraction-networking/utls" "golang.org/x/net/http2" ) type anthropicOAuthRoundTripper struct { mu sync.Mutex connections map[string]*http2.ClientConn pending map[string]*sync.Cond dialer net.Dialer dialContext func(context.Context, string, string) (net.Conn, error) } func newAnthropicOAuthHTTPClient(timeout time.Duration, proxyURL string) (*http.Client, error) { rt, err := newAnthropicOAuthRoundTripper(proxyURL) if err != nil { return nil, err } return &http.Client{ Timeout: timeout, Transport: rt, }, nil } func newAnthropicOAuthRoundTripper(proxyURL string) (*anthropicOAuthRoundTripper, error) { dialContext, err := proxyDialContext(proxyURL) if err != nil { return nil, err } return &anthropicOAuthRoundTripper{ connections: map[string]*http2.ClientConn{}, pending: map[string]*sync.Cond{}, dialer: net.Dialer{ Timeout: 15 * time.Second, KeepAlive: 30 * time.Second, }, dialContext: dialContext, }, nil } func (t *anthropicOAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { host := req.URL.Hostname() addr := req.URL.Host if !strings.Contains(addr, ":") { addr += ":443" } conn, err := t.getOrCreateConnection(host, addr) if err != nil { return nil, err } resp, err := conn.RoundTrip(req) if err != nil { t.mu.Lock() if cached, ok := t.connections[host]; ok && cached == conn { delete(t.connections, host) } t.mu.Unlock() return nil, err } return resp, nil } func (t *anthropicOAuthRoundTripper) getOrCreateConnection(host, addr string) (*http2.ClientConn, error) { t.mu.Lock() if conn, ok := t.connections[host]; ok && conn.CanTakeNewRequest() { t.mu.Unlock() return conn, nil } if wait, ok := t.pending[host]; ok { wait.Wait() if conn, ok := t.connections[host]; ok && conn.CanTakeNewRequest() { t.mu.Unlock() return conn, nil } } wait := sync.NewCond(&t.mu) t.pending[host] = wait t.mu.Unlock() conn, err := t.createConnection(host, addr) t.mu.Lock() defer t.mu.Unlock() delete(t.pending, host) wait.Broadcast() if err != nil { return nil, err } t.connections[host] = conn return conn, nil } func (t *anthropicOAuthRoundTripper) createConnection(host, addr string) (*http2.ClientConn, error) { dialContext := t.dialContext if dialContext == nil { dialContext = t.dialer.DialContext } rawConn, err := dialContext(context.Background(), "tcp", addr) if err != nil { return nil, err } tlsConn := tls.UClient(rawConn, &tls.Config{ServerName: host}, tls.HelloChrome_Auto) if err := tlsConn.Handshake(); err != nil { _ = rawConn.Close() return nil, err } h2Conn, err := (&http2.Transport{}).NewClientConn(tlsConn) if err != nil { _ = tlsConn.Close() return nil, err } return h2Conn, nil }