summaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--test/test_proxy_chunked.py249
1 files changed, 249 insertions, 0 deletions
diff --git a/test/test_proxy_chunked.py b/test/test_proxy_chunked.py
new file mode 100644
index 00000000..2d4f7b94
--- /dev/null
+++ b/test/test_proxy_chunked.py
@@ -0,0 +1,249 @@
+import os
+import re
+import socket
+import select
+import time
+
+from unit.applications.lang.python import TestApplicationPython
+
+
+class TestProxyChunked(TestApplicationPython):
+ prerequisites = {'modules': {'python': 'any'}}
+
+ SERVER_PORT = 7999
+
+ @staticmethod
+ def run_server(server_port, testdir):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+
+ server_address = ('127.0.0.1', server_port)
+ sock.bind(server_address)
+ sock.listen(10)
+
+ def recvall(sock):
+ buff_size = 4096 * 4096
+ data = b''
+ while True:
+ rlist = select.select([sock], [], [], 0.1)
+
+ if not rlist[0]:
+ break
+
+ part = sock.recv(buff_size)
+ data += part
+
+ if not len(part):
+ break
+
+ return data
+
+ while True:
+ connection, client_address = sock.accept()
+
+ req = """HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked"""
+
+ data = recvall(connection).decode()
+
+ m = re.search('\x0d\x0a\x0d\x0a(.*)', data, re.M | re.S)
+ if m is not None:
+ body = m.group(1)
+
+ for line in re.split('\r\n', body):
+ add = ''
+ m1 = re.search('(.*)\sX\s(\d+)', line)
+
+ if m1 is not None:
+ add = m1.group(1) * int(m1.group(2))
+ else:
+ add = line
+
+ req = req + add + '\r\n'
+
+ for chunk in re.split(r'([@#])', req):
+ if chunk == '@' or chunk == '#':
+ if chunk == '#':
+ time.sleep(0.1)
+ continue
+
+ connection.sendall(chunk.encode())
+
+ connection.close()
+
+ def chunks(self, chunks):
+ body = '\r\n\r\n'
+
+ for l, c in chunks:
+ body = body + l + '\r\n' + c + '\r\n'
+
+ return body + '0\r\n\r\n'
+
+ def get_http10(self, *args, **kwargs):
+ return self.get(*args, http_10=True, **kwargs)
+
+ def setUp(self):
+ super().setUp()
+
+ self.run_process(self.run_server, self.SERVER_PORT, self.testdir)
+ self.waitforsocket(self.SERVER_PORT)
+
+ self.assertIn(
+ 'success',
+ self.conf(
+ {
+ "listeners": {"*:7080": {"pass": "routes"},},
+ "routes": [
+ {
+ "action": {
+ "proxy": "http://127.0.0.1:" + str(self.SERVER_PORT)
+ }
+ }
+ ],
+ }
+ ),
+ 'proxy initial configuration',
+ )
+
+ def test_proxy_chunked(self):
+ for _ in range(10):
+ self.assertEqual(
+ self.get_http10(body='\r\n\r\n0\r\n\r\n')['status'], 200
+ )
+
+ def test_proxy_chunked_body(self):
+ part = '0123456789abcdef'
+
+ self.assertEqual(
+ self.get_http10(body=self.chunks([('1000', part + ' X 256')]))[
+ 'body'
+ ],
+ part * 256,
+ )
+ self.assertEqual(
+ self.get_http10(body=self.chunks([('100000', part + ' X 65536')]))[
+ 'body'
+ ],
+ part * 65536,
+ )
+ self.assertEqual(
+ self.get_http10(
+ body=self.chunks([('1000000', part + ' X 1048576')]),
+ read_buffer_size=4096 * 4096,
+ )['body'],
+ part * 1048576,
+ )
+
+ self.assertEqual(
+ self.get_http10(
+ body=self.chunks(
+ [('1000', part + ' X 256'), ('1000', part + ' X 256')]
+ )
+ )['body'],
+ part * 256 * 2,
+ )
+ self.assertEqual(
+ self.get_http10(
+ body=self.chunks(
+ [
+ ('100000', part + ' X 65536'),
+ ('100000', part + ' X 65536'),
+ ]
+ )
+ )['body'],
+ part * 65536 * 2,
+ )
+ self.assertEqual(
+ self.get_http10(
+ body=self.chunks(
+ [
+ ('1000000', part + ' X 1048576'),
+ ('1000000', part + ' X 1048576'),
+ ]
+ ),
+ read_buffer_size=4096 * 4096,
+ )['body'],
+ part * 1048576 * 2,
+ )
+
+ def test_proxy_chunked_fragmented(self):
+ part = '0123456789abcdef'
+
+ self.assertEqual(
+ self.get_http10(
+ body=self.chunks(
+ [('1', hex(i % 16)[2:]) for i in range(4096)]
+ ),
+ )['body'],
+ part * 256,
+ )
+
+ def test_proxy_chunked_send(self):
+ self.assertEqual(
+ self.get_http10(body='\r\n\r\n@0@\r\n\r\n')['status'], 200
+ )
+ self.assertEqual(
+ self.get_http10(
+ body='\r@\n\r\n2\r@\na@b\r\n2\r\ncd@\r\n0\r@\n\r\n'
+ )['body'],
+ 'abcd',
+ )
+ self.assertEqual(
+ self.get_http10(
+ body='\r\n\r\n2\r#\na#b\r\n##2\r\n#cd\r\n0\r\n#\r#\n'
+ )['body'],
+ 'abcd',
+ )
+
+ def test_proxy_chunked_invalid(self):
+ def check_invalid(body):
+ self.assertNotEqual(self.get_http10(body=body)['status'], 200)
+
+ check_invalid('\r\n\r0')
+ check_invalid('\r\n\r\n\r0')
+ check_invalid('\r\n\r\n\r\n0')
+ check_invalid('\r\nContent-Length: 5\r\n\r\n0\r\n\r\n')
+ check_invalid('\r\n\r\n1\r\nXX\r\n0\r\n\r\n')
+ check_invalid('\r\n\r\n2\r\nX\r\n0\r\n\r\n')
+ check_invalid('\r\n\r\nH\r\nXX\r\n0\r\n\r\n')
+ check_invalid('\r\n\r\n0\r\nX')
+
+ resp = self.get_http10(body='\r\n\r\n65#\r\nA X 100')
+ self.assertEqual(resp['status'], 200, 'incomplete chunk status')
+ self.assertNotEqual(resp['body'][-5:], '0\r\n\r\n', 'incomplete chunk')
+
+ resp = self.get_http10(body='\r\n\r\n64#\r\nA X 100')
+ self.assertEqual(resp['status'], 200, 'no zero chunk status')
+ self.assertNotEqual(resp['body'][-5:], '0\r\n\r\n', 'no zero chunk')
+
+ self.assertEqual(
+ self.get_http10(body='\r\n\r\n80000000\r\nA X 100')['status'], 200,
+ )
+ self.assertEqual(
+ self.get_http10(body='\r\n\r\n10000000000000000\r\nA X 100')[
+ 'status'
+ ],
+ 502,
+ )
+ self.assertGreaterEqual(
+ len(
+ self.get_http10(
+ body='\r\n\r\n1000000\r\nA X 1048576\r\n1000000\r\nA X 100',
+ read_buffer_size=4096 * 4096,
+ )['body']
+ ),
+ 1048576,
+ )
+ self.assertGreaterEqual(
+ len(
+ self.get_http10(
+ body='\r\n\r\n1000000\r\nA X 1048576\r\nXXX\r\nA X 100',
+ read_buffer_size=4096 * 4096,
+ )['body']
+ ),
+ 1048576,
+ )
+
+
+if __name__ == '__main__':
+ TestProxyChunked.main()