Skip to content

Commit

Permalink
Merge serverFromString-py-7982: Port twisted.internet.endpoints.serve…
Browse files Browse the repository at this point in the history
…rFromString to Python 3

Author: hawkowl
Reviewer: adiroiban
Fixes: twisted#7982

git-svn-id: svn://svn.twistedmatrix.com/svn/Twisted/trunk@45467 bbbe8e31-12d6-0310-92fd-ac37d47ddeeb
  • Loading branch information
hawkowl committed Aug 12, 2015
1 parent 59daefa commit 9d676cc
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 64 deletions.
39 changes: 12 additions & 27 deletions twisted/internet/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from twisted.internet.task import LoopingCall
from twisted.plugin import IPlugin, getPlugins
from twisted.python import log
from twisted.python.compat import _PY3
from twisted.python.compat import nativeString
from twisted.python.components import proxyForInterface
from twisted.python.constants import NamedConstant, Names
from twisted.python.failure import Failure
Expand All @@ -52,13 +52,6 @@
"ProcessEndpoint", "HostnameEndpoint",
"StandardErrorBehavior", "connectProtocol"]

__all3__ = ["clientFromString",
"TCP4ServerEndpoint", "TCP6ServerEndpoint",
"TCP4ClientEndpoint", "TCP6ClientEndpoint",
"SSL4ServerEndpoint", "SSL4ClientEndpoint",
"UNIXServerEndpoint", "UNIXClientEndpoint",
"connectProtocol", "HostnameEndpoint",
"ProcessEndpoint", "StandardErrorBehavior"]


class _WrappingProtocol(Protocol):
Expand Down Expand Up @@ -1092,12 +1085,12 @@ def _parseSSL(factory, port, privateKey="server.pem", certKey=None,
@param extraCertChain: The path of a file containing one or more
certificates in PEM format that establish the chain from a root CA to
the CA that signed your C{certKey}.
@type extraCertChain: L{bytes}
@type extraCertChain: L{str}
@param dhParameters: The file name of a file containing parameters that are
required for Diffie-Hellman key exchange. If this is not specified,
the forward secret C{DHE} ciphers aren't available for servers.
@type dhParameters: L{bytes}
@type dhParameters: L{str}
@return: a 2-tuple of (args, kwargs), describing the parameters to
L{IReactorSSL.listenSSL} (or, modulo argument 2, the factory, arguments
Expand All @@ -1113,9 +1106,10 @@ def _parseSSL(factory, port, privateKey="server.pem", certKey=None,
keyPEM = FilePath(privateKey).getContent()
privateCertificate = ssl.PrivateCertificate.loadPEM(certPEM + keyPEM)
if extraCertChain is not None:
extraCertChain = FilePath(extraCertChain).getContent()
matches = re.findall(
r'(-----BEGIN CERTIFICATE-----\n.+?\n-----END CERTIFICATE-----)',
FilePath(extraCertChain).getContent(),
nativeString(extraCertChain),
flags=re.DOTALL
)
chainCertificates = [ssl.Certificate.loadPEM(chainCertPEM).original
Expand Down Expand Up @@ -1423,20 +1417,20 @@ def serverFromString(reactor, description):
For example, you can call it like this to create an endpoint that will
listen on TCP port 80::
serverFromString(reactor, b"tcp:80")
serverFromString(reactor, "tcp:80")
Additional arguments may be specified as keywords, separated with colons.
For example, you can specify the interface for a TCP server endpoint to
bind to like this::
serverFromString(reactor, b"tcp:80:interface=127.0.0.1")
serverFromString(reactor, "tcp:80:interface=127.0.0.1")
SSL server endpoints may be specified with the 'ssl' prefix, and the
private key and certificate files may be specified by the C{privateKey} and
C{certKey} arguments::
serverFromString(
reactor, b"ssl:443:privateKey=key.pem:certKey=crt.pem")
reactor, "ssl:443:privateKey=key.pem:certKey=crt.pem")
If a private key file name (C{privateKey}) isn't provided, a "server.pem"
file is assumed to exist which contains the private key. If the certificate
Expand All @@ -1447,14 +1441,14 @@ def serverFromString(reactor, description):
use if you want to specify a full pathname argument on Windows::
serverFromString(reactor,
b"ssl:443:privateKey=C\\:/key.pem:certKey=C\\:/cert.pem")
"ssl:443:privateKey=C\\:/key.pem:certKey=C\\:/cert.pem")
finally, the 'unix' prefix may be used to specify a filesystem UNIX socket,
optionally with a 'mode' argument to specify the mode of the socket file
created by C{listen}::
serverFromString(reactor, b"unix:/var/run/finger")
serverFromString(reactor, b"unix:/var/run/finger:mode=660")
serverFromString(reactor, "unix:/var/run/finger")
serverFromString(reactor, "unix:/var/run/finger:mode=660")
This function is also extensible; new endpoint types may be registered as
L{IStreamServerEndpointStringParser} plugins. See that interface for more
Expand All @@ -1463,7 +1457,7 @@ def serverFromString(reactor, description):
@param reactor: The server endpoint will be constructed with this reactor.
@param description: The strports description to parse.
@type description: L{bytes}
@type description: L{str}
@return: A new endpoint which can be used to listen with the parameters
given by C{description}.
Expand Down Expand Up @@ -1776,12 +1770,3 @@ class OneShotFactory(Factory):
def buildProtocol(self, addr):
return protocol
return endpoint.connect(OneShotFactory())



if _PY3:
for name in __all__[:]:
if name not in __all3__:
__all__.remove(name)
del globals()[name]
del name, __all3__
64 changes: 27 additions & 37 deletions twisted/internet/test/test_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
from twisted.internet.task import Clock
from twisted.plugin import getPlugins
from twisted.python import log
from twisted.python.compat import _PY3
from twisted.python.failure import Failure
from twisted.python.filepath import FilePath
from twisted.python.modules import getModule
Expand Down Expand Up @@ -2458,12 +2457,12 @@ def test_tcp(self):
"""
reactor = object()
server = endpoints.serverFromString(
reactor, b"tcp:1234:backlog=12:interface=10.0.0.1")
reactor, "tcp:1234:backlog=12:interface=10.0.0.1")
self.assertIsInstance(server, endpoints.TCP4ServerEndpoint)
self.assertIs(server._reactor, reactor)
self.assertEqual(server._port, 1234)
self.assertEqual(server._backlog, 12)
self.assertEqual(server._interface, b"10.0.0.1")
self.assertEqual(server._interface, "10.0.0.1")


def test_ssl(self):
Expand All @@ -2475,14 +2474,14 @@ def test_ssl(self):
reactor = object()
server = endpoints.serverFromString(
reactor,
b"ssl:1234:backlog=12:privateKey=%s:"
b"certKey=%s:sslmethod=TLSv1_METHOD:interface=10.0.0.1"
"ssl:1234:backlog=12:privateKey=%s:"
"certKey=%s:sslmethod=TLSv1_METHOD:interface=10.0.0.1"
% (escapedPEMPathName, escapedPEMPathName))
self.assertIsInstance(server, endpoints.SSL4ServerEndpoint)
self.assertIs(server._reactor, reactor)
self.assertEqual(server._port, 1234)
self.assertEqual(server._backlog, 12)
self.assertEqual(server._interface, b"10.0.0.1")
self.assertEqual(server._interface, "10.0.0.1")
self.assertEqual(server._sslContextFactory.method, TLSv1_METHOD)
ctx = server._sslContextFactory.getContext()
self.assertIsInstance(ctx, ContextType)
Expand All @@ -2495,7 +2494,7 @@ def test_sslWithDefaults(self):
"""
reactor = object()
server = endpoints.serverFromString(
reactor, b"ssl:4321:privateKey=%s" % (escapedPEMPathName,))
reactor, "ssl:4321:privateKey=%s" % (escapedPEMPathName,))
self.assertIsInstance(server, endpoints.SSL4ServerEndpoint)
self.assertIs(server._reactor, reactor)
self.assertEqual(server._port, 4321)
Expand All @@ -2511,7 +2510,7 @@ def test_sslWithDefaults(self):

# Use a class variable to ensure we use the exactly same endpoint string
# except for the chain file itself.
SSL_CHAIN_TEMPLATE = b"ssl:1234:privateKey=%s:extraCertChain=%s"
SSL_CHAIN_TEMPLATE = "ssl:1234:privateKey=%s:extraCertChain=%s"


def test_sslChainLoads(self):
Expand Down Expand Up @@ -2565,7 +2564,7 @@ def test_sslDHparameters(self):
If C{dhParameters} are specified, they are passed as
L{DiffieHellmanParameters} into L{CertificateOptions}.
"""
fileName = b'someFile'
fileName = 'someFile'
reactor = object()
server = endpoints.serverFromString(
reactor,
Expand Down Expand Up @@ -2593,10 +2592,10 @@ def test_unix(self):
reactor = object()
endpoint = endpoints.serverFromString(
reactor,
b"unix:/var/foo/bar:backlog=7:mode=0123:lockfile=1")
"unix:/var/foo/bar:backlog=7:mode=0123:lockfile=1")
self.assertIsInstance(endpoint, endpoints.UNIXServerEndpoint)
self.assertIs(endpoint._reactor, reactor)
self.assertEqual(endpoint._address, b"/var/foo/bar")
self.assertEqual(endpoint._address, "/var/foo/bar")
self.assertEqual(endpoint._backlog, 7)
self.assertEqual(endpoint._mode, 0o123)
self.assertEqual(endpoint._wantPID, True)
Expand All @@ -2612,7 +2611,7 @@ def test_implicitDefaultNotAllowed(self):
to the new API, you'll get a C{ValueError}.
"""
value = self.assertRaises(
ValueError, endpoints.serverFromString, None, b"4321")
ValueError, endpoints.serverFromString, None, "4321")
self.assertEqual(
str(value),
"Unqualified strport description passed to 'service'."
Expand All @@ -2627,7 +2626,7 @@ def test_unknownType(self):
value = self.assertRaises(
# faster-than-light communication not supported
ValueError, endpoints.serverFromString, None,
b"ftl:andromeda/carcosa/hali/2387")
"ftl:andromeda/carcosa/hali/2387")
self.assertEqual(
str(value),
"Unknown endpoint type: 'ftl'")
Expand All @@ -2644,7 +2643,7 @@ def test_typeFromPlugin(self):
# Plugin is set up: now actually test.
notAReactor = object()
fakeEndpoint = endpoints.serverFromString(
notAReactor, b"fake:hello:world:yes=no:up=down")
notAReactor, "fake:hello:world:yes=no:up=down")
from twisted.plugins.fakeendpoint import fake
self.assertIs(fakeEndpoint.parser, fake)
self.assertEqual(fakeEndpoint.args, (notAReactor, 'hello', 'world'))
Expand Down Expand Up @@ -2892,15 +2891,15 @@ def test_ssl(self):
reactor = object()
client = endpoints.clientFromString(
reactor,
b"ssl:host=example.net:port=4321:privateKey=%s:"
b"certKey=%s:bindAddress=10.0.0.3:timeout=3:caCertsDir=%s" %
"ssl:host=example.net:port=4321:privateKey=%s:"
"certKey=%s:bindAddress=10.0.0.3:timeout=3:caCertsDir=%s" %
(escapedPEMPathName, escapedPEMPathName, escapedCAsPathName))
self.assertIsInstance(client, endpoints.SSL4ClientEndpoint)
self.assertIs(client._reactor, reactor)
self.assertEqual(client._host, b"example.net")
self.assertEqual(client._host, "example.net")
self.assertEqual(client._port, 4321)
self.assertEqual(client._timeout, 3)
self.assertEqual(client._bindAddress, (b"10.0.0.3", 0))
self.assertEqual(client._bindAddress, ("10.0.0.3", 0))
certOptions = client._sslContextFactory
self.assertIsInstance(certOptions, CertificateOptions)
self.assertEqual(certOptions.method, SSLv23_METHOD)
Expand Down Expand Up @@ -2931,15 +2930,15 @@ def test_sslPositionalArgs(self):
reactor = object()
client = endpoints.clientFromString(
reactor,
b"ssl:example.net:4321:privateKey=%s:"
b"certKey=%s:bindAddress=10.0.0.3:timeout=3:caCertsDir=%s" %
"ssl:example.net:4321:privateKey=%s:"
"certKey=%s:bindAddress=10.0.0.3:timeout=3:caCertsDir=%s" %
(escapedPEMPathName, escapedPEMPathName, escapedCAsPathName))
self.assertIsInstance(client, endpoints.SSL4ClientEndpoint)
self.assertIs(client._reactor, reactor)
self.assertEqual(client._host, b"example.net")
self.assertEqual(client._host, "example.net")
self.assertEqual(client._port, 4321)
self.assertEqual(client._timeout, 3)
self.assertEqual(client._bindAddress, (b"10.0.0.3", 0))
self.assertEqual(client._bindAddress, ("10.0.0.3", 0))


def test_sslWithDefaults(self):
Expand All @@ -2949,10 +2948,10 @@ def test_sslWithDefaults(self):
whose context factory is initialized with default values.
"""
reactor = object()
client = endpoints.clientFromString(reactor, b"ssl:example.net:4321")
client = endpoints.clientFromString(reactor, "ssl:example.net:4321")
self.assertIsInstance(client, endpoints.SSL4ClientEndpoint)
self.assertIs(client._reactor, reactor)
self.assertEqual(client._host, b"example.net")
self.assertEqual(client._host, "example.net")
self.assertEqual(client._port, 4321)
certOptions = client._sslContextFactory
self.assertEqual(certOptions.method, SSLv23_METHOD)
Expand Down Expand Up @@ -2989,7 +2988,7 @@ def test_sslSimple(self):
"""
reactor = object()
client = endpoints.clientFromString(
reactor, b"ssl:host=simple.example.org:port=4321")
reactor, "ssl:host=simple.example.org:port=4321")
certOptions = client._sslContextFactory
self.assertIsInstance(certOptions, CertificateOptions)
self.assertEqual(certOptions.verify, False)
Expand Down Expand Up @@ -3248,12 +3247,12 @@ def test_stringDescription(self):
'tcp6' endpoint string description.
"""
ep = endpoints.serverFromString(
MemoryReactor(), b"tcp6:8080:backlog=12:interface=\:\:1")
MemoryReactor(), "tcp6:8080:backlog=12:interface=\:\:1")
self.assertIsInstance(ep, endpoints.TCP6ServerEndpoint)
self.assertIsInstance(ep._reactor, MemoryReactor)
self.assertEqual(ep._port, 8080)
self.assertEqual(ep._backlog, 12)
self.assertEqual(ep._interface, b'::1')
self.assertEqual(ep._interface, '::1')



Expand Down Expand Up @@ -3293,7 +3292,7 @@ def test_stringDescription(self):
L{serverFromString} returns a L{StandardIOEndpoint} instance with a
'stdio' endpoint string description.
"""
ep = endpoints.serverFromString(MemoryReactor(), b"stdio:")
ep = endpoints.serverFromString(MemoryReactor(), "stdio:")
self.assertIsInstance(ep, endpoints.StandardIOEndpoint)
self.assertIsInstance(ep._reactor, MemoryReactor)

Expand Down Expand Up @@ -3337,12 +3336,3 @@ def connect(self, factory):

endpoint = Endpoint()
self.assertIs(result, endpoints.connectProtocol(endpoint, object()))



if _PY3:
del (StandardIOEndpointsTests, ParserTests,
ServerStringTests, SSLClientStringTests,
AdoptedStreamServerEndpointTests, SystemdEndpointPluginTests,
TCP6ServerEndpointPluginTests, StandardIOEndpointPluginTests
)
1 change: 1 addition & 0 deletions twisted/topfiles/7982.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
twisted.internet.endpoints.serverFromString is now ported to Python 3.

0 comments on commit 9d676cc

Please sign in to comment.