Skip to content

Commit 4948947

Browse files
committed
Implement SSL support for create_server and create_unix_server
1 parent 08246bd commit 4948947

15 files changed

+466
-174
lines changed

tests/certs/ssl_cert.pem

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
3+
BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
4+
IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
5+
MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
6+
Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
7+
YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
8+
gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
9+
6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
10+
pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
11+
FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
12+
BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
13+
lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
14+
CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
15+
-----END CERTIFICATE-----

tests/certs/ssl_key.pem

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm
3+
LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0
4+
ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP
5+
USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt
6+
CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq
7+
SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK
8+
UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y
9+
BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ
10+
ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5
11+
oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik
12+
eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F
13+
0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS
14+
x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/
15+
SPIXQuT8RMPDVNQ=
16+
-----END PRIVATE KEY-----

tests/test_tcp.py

Lines changed: 163 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,31 @@
11
import asyncio
2+
import logging
23
import socket
34
import uvloop
5+
import ssl
6+
import warnings
47

58
from uvloop import _testbase as tb
69

710

811
class _TestTCP:
912
def test_create_server_1(self):
1013
CNT = 0 # number of clients that were successful
11-
TOTAL_CNT = 100 # total number of clients that test will create
14+
TOTAL_CNT = 25 # total number of clients that test will create
1215
TIMEOUT = 5.0 # timeout for this test
1316

17+
A_DATA = b'A' * 1024 * 1024
18+
B_DATA = b'B' * 1024 * 1024
19+
1420
async def handle_client(reader, writer):
1521
nonlocal CNT
1622

17-
data = await reader.readexactly(4)
18-
self.assertEqual(data, b'AAAA')
23+
data = await reader.readexactly(len(A_DATA))
24+
self.assertEqual(data, A_DATA)
1925
writer.write(b'OK')
2026

21-
data = await reader.readexactly(4)
22-
self.assertEqual(data, b'BBBB')
27+
data = await reader.readexactly(len(B_DATA))
28+
self.assertEqual(data, B_DATA)
2329
writer.writelines([b'SP', bytearray(b'A'), memoryview(b'M')])
2430

2531
await writer.drain()
@@ -33,54 +39,43 @@ async def test_client(addr):
3339
sock.setblocking(False)
3440
await self.loop.sock_connect(sock, addr)
3541

36-
await self.loop.sock_sendall(sock, b'AAAA')
42+
await self.loop.sock_sendall(sock, A_DATA)
3743
data = await self.loop.sock_recv(sock, 2)
3844
self.assertEqual(data, b'OK')
3945

40-
await self.loop.sock_sendall(sock, b'BBBB')
46+
await self.loop.sock_sendall(sock, B_DATA)
4147
data = await self.loop.sock_recv(sock, 4)
4248
self.assertEqual(data, b'SPAM')
4349

4450
async def start_server():
4551
nonlocal CNT
4652
CNT = 0
4753

48-
try:
49-
srv = await asyncio.start_server(
50-
handle_client,
51-
('127.0.0.1', 'localhost'), 0,
52-
family=socket.AF_INET,
53-
loop=self.loop)
54-
55-
try:
56-
srv_socks = srv.sockets
57-
self.assertTrue(srv_socks)
54+
srv = await asyncio.start_server(
55+
handle_client,
56+
('127.0.0.1', 'localhost'), 0,
57+
family=socket.AF_INET,
58+
loop=self.loop)
5859

59-
addr = srv_socks[0].getsockname()
60+
srv_socks = srv.sockets
61+
self.assertTrue(srv_socks)
6062

61-
tasks = []
62-
for _ in range(TOTAL_CNT):
63-
tasks.append(test_client(addr))
63+
addr = srv_socks[0].getsockname()
6464

65-
try:
66-
await asyncio.wait_for(
67-
asyncio.gather(*tasks, loop=self.loop),
68-
TIMEOUT, loop=self.loop)
69-
finally:
70-
self.loop.stop()
65+
tasks = []
66+
for _ in range(TOTAL_CNT):
67+
tasks.append(test_client(addr))
7168

72-
finally:
73-
self.loop.call_soon(srv.close)
74-
await srv.wait_closed()
69+
await asyncio.wait_for(
70+
asyncio.gather(*tasks, loop=self.loop),
71+
TIMEOUT, loop=self.loop)
7572

76-
# Check that the server cleaned-up proxy-sockets
77-
for srv_sock in srv_socks:
78-
self.assertEqual(srv_sock.fileno(), -1)
73+
self.loop.call_soon(srv.close)
74+
await srv.wait_closed()
7975

80-
except:
81-
self.loop.stop() # We don't want this test to stuck when
82-
# it fails.
83-
raise
76+
# Check that the server cleaned-up proxy-sockets
77+
for srv_sock in srv_socks:
78+
self.assertEqual(srv_sock.fileno(), -1)
8479

8580
async def start_server_sock():
8681
nonlocal CNT
@@ -89,47 +84,35 @@ async def start_server_sock():
8984
sock = socket.socket()
9085
sock.bind(('127.0.0.1', 0))
9186
addr = sock.getsockname()
92-
try:
93-
srv = await asyncio.start_server(
94-
handle_client,
95-
None, None,
96-
family=socket.AF_INET,
97-
loop=self.loop,
98-
sock=sock)
9987

100-
try:
101-
srv_socks = srv.sockets
102-
self.assertTrue(srv_socks)
103-
104-
tasks = []
105-
for _ in range(TOTAL_CNT):
106-
tasks.append(test_client(addr))
107-
108-
try:
109-
await asyncio.wait_for(
110-
asyncio.gather(*tasks, loop=self.loop),
111-
TIMEOUT, loop=self.loop)
112-
finally:
113-
self.loop.stop()
114-
115-
finally:
116-
srv.close()
117-
118-
# Check that the server cleaned-up proxy-sockets
119-
for srv_sock in srv_socks:
120-
self.assertEqual(srv_sock.fileno(), -1)
121-
122-
except:
123-
self.loop.stop() # We don't want this test to stuck when
124-
# it fails.
125-
raise
126-
127-
self.loop.create_task(start_server())
128-
self.loop.run_forever()
88+
srv = await asyncio.start_server(
89+
handle_client,
90+
None, None,
91+
family=socket.AF_INET,
92+
loop=self.loop,
93+
sock=sock)
94+
95+
srv_socks = srv.sockets
96+
self.assertTrue(srv_socks)
97+
98+
tasks = []
99+
for _ in range(TOTAL_CNT):
100+
tasks.append(test_client(addr))
101+
102+
await asyncio.wait_for(
103+
asyncio.gather(*tasks, loop=self.loop),
104+
TIMEOUT, loop=self.loop)
105+
106+
srv.close()
107+
108+
# Check that the server cleaned-up proxy-sockets
109+
for srv_sock in srv_socks:
110+
self.assertEqual(srv_sock.fileno(), -1)
111+
112+
self.loop.run_until_complete(start_server())
129113
self.assertEqual(CNT, TOTAL_CNT)
130114

131-
self.loop.create_task(start_server_sock())
132-
self.loop.run_forever()
115+
self.loop.run_until_complete(start_server_sock())
133116
self.assertEqual(CNT, TOTAL_CNT)
134117

135118
def test_create_connection_1(self):
@@ -185,8 +168,7 @@ def run(coro):
185168

186169
srv = tb.tcp_server(server,
187170
max_clients=TOTAL_CNT,
188-
backlog=TOTAL_CNT,
189-
timeout=5)
171+
backlog=TOTAL_CNT)
190172
srv.start()
191173

192174
tasks = []
@@ -248,8 +230,7 @@ def run(coro):
248230

249231
srv = tb.tcp_server(server,
250232
max_clients=TOTAL_CNT,
251-
backlog=TOTAL_CNT,
252-
timeout=5)
233+
backlog=TOTAL_CNT)
253234
srv.start()
254235

255236
tasks = []
@@ -403,3 +384,106 @@ class Test_UV_TCP(_TestTCP, tb.UVTestCase):
403384

404385
class Test_AIO_TCP(_TestTCP, tb.AIOTestCase):
405386
pass
387+
388+
389+
class _TestSSL(tb.SSLTestCase):
390+
391+
def test_create_server_ssl_1(self):
392+
CNT = 0 # number of clients that were successful
393+
TOTAL_CNT = 25 # total number of clients that test will create
394+
TIMEOUT = 5.0 # timeout for this test
395+
396+
A_DATA = b'A' * 1024 * 1024
397+
B_DATA = b'B' * 1024 * 1024
398+
399+
sslctx = self._create_server_ssl_context(self.ONLYCERT, self.ONLYKEY)
400+
client_sslctx = self._create_client_ssl_context()
401+
402+
clients = []
403+
404+
async def handle_client(reader, writer):
405+
nonlocal CNT
406+
407+
data = await reader.readexactly(len(A_DATA))
408+
self.assertEqual(data, A_DATA)
409+
writer.write(b'OK')
410+
411+
data = await reader.readexactly(len(B_DATA))
412+
self.assertEqual(data, B_DATA)
413+
writer.writelines([b'SP', bytearray(b'A'), memoryview(b'M')])
414+
415+
await writer.drain()
416+
writer.close()
417+
418+
CNT += 1
419+
420+
async def test_client(addr):
421+
fut = asyncio.Future(loop=self.loop)
422+
423+
def prog():
424+
try:
425+
yield tb.starttls(client_sslctx)
426+
yield tb.connect(addr)
427+
yield tb.write(A_DATA)
428+
429+
data = yield tb.read(2)
430+
self.assertEqual(data, b'OK')
431+
432+
yield tb.write(B_DATA)
433+
data = yield tb.read(4)
434+
self.assertEqual(data, b'SPAM')
435+
436+
yield tb.close()
437+
438+
except Exception as ex:
439+
self.loop.call_soon_threadsafe(fut.set_exception, ex)
440+
else:
441+
self.loop.call_soon_threadsafe(fut.set_result, None)
442+
443+
client = tb.tcp_client(prog)
444+
client.start()
445+
clients.append(client)
446+
447+
await fut
448+
449+
async def start_server():
450+
srv = await asyncio.start_server(
451+
handle_client,
452+
'127.0.0.1', 0,
453+
family=socket.AF_INET,
454+
ssl=sslctx,
455+
loop=self.loop)
456+
457+
try:
458+
srv_socks = srv.sockets
459+
self.assertTrue(srv_socks)
460+
461+
addr = srv_socks[0].getsockname()
462+
463+
tasks = []
464+
for _ in range(TOTAL_CNT):
465+
tasks.append(test_client(addr))
466+
467+
await asyncio.wait_for(
468+
asyncio.gather(*tasks, loop=self.loop),
469+
TIMEOUT, loop=self.loop)
470+
471+
finally:
472+
self.loop.call_soon(srv.close)
473+
await srv.wait_closed()
474+
475+
with self._silence_eof_received_warning():
476+
self.loop.run_until_complete(start_server())
477+
478+
self.assertEqual(CNT, TOTAL_CNT)
479+
480+
for client in clients:
481+
client.stop()
482+
483+
484+
class Test_UV_TCPSSL(_TestSSL, tb.UVTestCase):
485+
pass
486+
487+
488+
class Test_AIO_TCPSSL(_TestSSL, tb.AIOTestCase):
489+
pass

0 commit comments

Comments
 (0)