Skip to content

Commit

Permalink
Remember proxy_ep properly if it was Deferred
Browse files Browse the repository at this point in the history
  • Loading branch information
meejah committed Feb 12, 2018
1 parent ce0e471 commit 25422e6
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 3 deletions.
23 changes: 23 additions & 0 deletions test/test_socks.py
Expand Up @@ -5,9 +5,12 @@
from twisted.internet import defer
from twisted.internet.address import IPv4Address
from twisted.internet.protocol import Protocol
from twisted.internet.interfaces import IStreamClientEndpoint
from twisted.test import proto_helpers
from twisted.test.iosim import connect, FakeTransport

from zope.interface import directlyProvides

from txtorcon import socks


Expand Down Expand Up @@ -511,6 +514,7 @@ def connect(factory):
@defer.inlineCallbacks
def test_connect_deferred_proxy(self):
socks_ep = Mock()
directlyProvides(socks_ep, IStreamClientEndpoint)
transport = proto_helpers.StringTransport()

def connect(factory):
Expand All @@ -533,6 +537,25 @@ def connect(factory):
proto = yield ep.connect(factory)
self.assertEqual(proto, protocol)

@defer.inlineCallbacks
def test_connect_deferred_proxy_wrong_return(self):

class NotAnEndpoint(object):
"definitely doesn't implement IStreamClientEndpoint"
not_an_endpoint = NotAnEndpoint()
factory = Mock()
ep = socks.TorSocksEndpoint(
socks_endpoint=defer.succeed(not_an_endpoint),
host=u'meejah.ca',
port=443,
)
with self.assertRaises(ValueError) as ctx:
yield ep.connect(factory)
self.assertIn(
"must resolve to an IStreamClientEndpoint provider",
str(ctx.exception),
)

@defer.inlineCallbacks
def test_connect_tls(self):
socks_ep = Mock()
Expand Down
1 change: 1 addition & 0 deletions txtorcon/endpoints.py
Expand Up @@ -679,6 +679,7 @@ def _create_socks_endpoint(reactor, control_protocol, socks_config=None):
yield control_protocol.set_conf(*args)
socks_endpoint = _endpoint_from_socksport_line(reactor, socks_config)

assert socks_endpoint is not None
defer.returnValue(socks_endpoint)


Expand Down
6 changes: 6 additions & 0 deletions txtorcon/socks.py
Expand Up @@ -689,6 +689,7 @@ class TorSocksEndpoint(object):
# IAddress-implementer?
def __init__(self, socks_endpoint, host, port, tls=False):
self._proxy_ep = socks_endpoint # can be Deferred
assert self._proxy_ep is not None
if six.PY2 and isinstance(host, str):
host = unicode(host) # noqa
if six.PY3 and isinstance(host, bytes):
Expand Down Expand Up @@ -735,6 +736,11 @@ def connect(self, factory):
# XXX isn't this just maybeDeferred()
if isinstance(self._proxy_ep, Deferred):
proxy_ep = yield self._proxy_ep
if not IStreamClientEndpoint.providedBy(proxy_ep):
raise ValueError(
"The Deferred provided as 'socks_endpoint' must "
"resolve to an IStreamClientEndpoint provider"
)
else:
proxy_ep = self._proxy_ep

Expand Down
12 changes: 9 additions & 3 deletions txtorcon/web.py
Expand Up @@ -6,7 +6,7 @@

from twisted.web.iweb import IAgentEndpointFactory
from twisted.web.client import Agent
from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.internet.defer import inlineCallbacks, returnValue, Deferred
from twisted.internet.endpoints import TCP4ClientEndpoint, UNIXClientEndpoint

from zope.interface import implementer
Expand All @@ -20,8 +20,14 @@ class _AgentEndpointFactoryUsingTor(object):
def __init__(self, reactor, tor_socks_endpoint):
self._reactor = reactor
self._proxy_ep = tor_socks_endpoint
# XXX could accept optional "tls=" to do something besides
# optionsForClientTLS(hostname)?
# if _proxy_ep is Deferred, but we get called twice, we must
# remember the resolved object here
if isinstance(tor_socks_endpoint, Deferred):
self._proxy_ep.addCallback(self._set_proxy)

def _set_proxy(self, p):
self._proxy_ep = p
return p

def endpointForURI(self, uri):
return TorSocksEndpoint(
Expand Down

0 comments on commit 25422e6

Please sign in to comment.