fix: name the proxy schemes that work, and stop panicking on the rest
"Which proxy does this support?" has a narrower answer than the docs
gave. `golang.org/x/net/proxy.FromURL` resolves `socks5` and `socks5h`
and nothing else, yet the README and `Proxy`'s doc comment both offered
"socks5, socks4 and socks4a". A `socks4://` URI fails every dial with
`proxy: unknown scheme: socks4`, which is what taking the docs at their
word looks like from the caller's side.
Corrected both, and pointed at `proxy.RegisterDialerType` -- the way
x/net/proxy expects a caller to add a scheme it does not carry.
That escape hatch had a second problem waiting. `establishProxyConnection`
asserted the dialer to `proxy.ContextDialer` unconditionally, but a
registered dialer need only implement `Dial`, and the assertion panicked
on those:
interface conversion: T is not proxy.ContextDialer: missing method
DialContext
It now falls back to dialing on a goroutine and abandoning the attempt
when the context expires, which is what x/net/proxy itself does for the
same case.
Closes: #95
This commit is contained in:
1 parent
74c6cde98a
commit
87744aa7c1
4 files changed
+80
-3
No files matched your search
@@ -326,5 +326,37 @@ func establishProxyConnection(addr, proxyURI string, timeout time.Duration) (net
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
return dialer.(proxy.ContextDialer).DialContext(ctx, "tcp", addr)
|
||||
if contextDialer, ok := dialer.(proxy.ContextDialer); ok {
|
||||
return contextDialer.DialContext(ctx, "tcp", addr)
|
||||
}
|
||||
|
||||
// A dialer added with proxy.RegisterDialerType need not be a ContextDialer.
|
||||
return dialWithTimeout(ctx, dialer, addr)
|
||||
}
|
||||
|
||||
// dialWithTimeout dials through a Dialer that cannot take a context, abandoning
|
||||
// the attempt -- though not the goroutine -- when ctx is done, as x/net/proxy does.
|
||||
func dialWithTimeout(ctx context.Context, dialer proxy.Dialer, addr string) (net.Conn, error) {
|
||||
type result struct {
|
||||
conn net.Conn
|
||||
err error
|
||||
}
|
||||
done := make(chan result, 1)
|
||||
|
||||
go func() {
|
||||
conn, err := dialer.Dial("tcp", addr)
|
||||
done <- result{conn, err}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
go func() {
|
||||
if r := <-done; r.conn != nil {
|
||||
r.conn.Close()
|
||||
}
|
||||
}()
|
||||
return nil, ctx.Err()
|
||||
case r := <-done:
|
||||
return r.conn, r.err
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user