224 lines
9.2 KiB
Python
224 lines
9.2 KiB
Python
|
|
from typing import Any, Dict, List
|
|
|
|
from matemat.webserver import HttpHandler, RequestArguments
|
|
from matemat.webserver.test.abstract_httpd_test import AbstractHttpdTest, test_pagelet
|
|
|
|
import codecs
|
|
|
|
|
|
@test_pagelet('/just/testing/post')
|
|
def post_test_pagelet(method: str,
|
|
path: str,
|
|
args: RequestArguments,
|
|
session_vars: Dict[str, Any],
|
|
headers: Dict[str, str]):
|
|
"""
|
|
Test pagelet that simply prints the parsed arguments as response body.
|
|
"""
|
|
headers['Content-Type'] = 'text/plain'
|
|
dump: str = ''
|
|
for ra in args:
|
|
for a in ra:
|
|
if a.get_content_type().startswith('text/'):
|
|
dump += f'{a.name}: {a.get_str()}\n'
|
|
else:
|
|
dump += f'{a.name}: {codecs.encode(a.get_bytes(), "hex").decode("utf-8")}\n'
|
|
return 200, dump
|
|
|
|
|
|
class TestPost(AbstractHttpdTest):
|
|
"""
|
|
Test cases for the content serving of the web server.
|
|
"""
|
|
|
|
def test_post_urlenc_get_only_args(self):
|
|
"""
|
|
Test a POST request that only contains GET arguments.
|
|
"""
|
|
# Send POST request
|
|
self.client_sock.set_request(b'POST /just/testing/post?foo=bar&test=1 HTTP/1.1\r\n'
|
|
b'Content-Length: 0\r\n'
|
|
b'Content-Type: application/x-www-form-urlencoded\r\n\r\n')
|
|
HttpHandler(self.client_sock, ('::1', 45678), self.server)
|
|
packet = self.client_sock.get_response()
|
|
|
|
# Parse response body
|
|
lines: List[bytes] = packet.body.split(b'\n')[:-1]
|
|
kv: Dict[str, str] = dict()
|
|
for l in lines:
|
|
k, v = l.decode('utf-8').split(':', 1)
|
|
kv[k.strip()] = v.strip() if ',' not in v else v.strip().split(',')
|
|
|
|
# Make sure the arguments were properly parsed
|
|
self.assertEqual('bar', kv['foo'])
|
|
self.assertEqual('1', kv['test'])
|
|
|
|
def test_post_urlenc_post_only_args(self):
|
|
"""
|
|
Test a POST request that only contains POST arguments (urlencoded).
|
|
"""
|
|
# Send POST request
|
|
self.client_sock.set_request(b'POST /just/testing/post HTTP/1.1\r\n'
|
|
b'Content-Type: application/x-www-form-urlencoded\r\n'
|
|
b'Content-Length: 14\r\n\r\n'
|
|
b'foo=bar&test=1\r\n')
|
|
HttpHandler(self.client_sock, ('::1', 45678), self.server)
|
|
packet = self.client_sock.get_response()
|
|
|
|
# Parse response body
|
|
lines: List[bytes] = packet.body.split(b'\n')[:-1]
|
|
kv: Dict[str, str] = dict()
|
|
for l in lines:
|
|
k, v = l.decode('utf-8').split(':', 1)
|
|
kv[k.strip()] = v.strip() if ',' not in v else v.strip().split(',')
|
|
|
|
# Make sure the arguments were properly parsed
|
|
self.assertEqual('bar', kv['foo'])
|
|
self.assertEqual('1', kv['test'])
|
|
|
|
def test_post_urlenc_mixed_args(self):
|
|
"""
|
|
Test that mixed POST and GET args are properly parsed, and that POST takes precedence over GET.
|
|
"""
|
|
# Send POST request
|
|
self.client_sock.set_request(b'POST /just/testing/post?gettest=1&foo=baz HTTP/1.1\r\n'
|
|
b'Content-Type: application/x-www-form-urlencoded\r\n'
|
|
b'Content-Length: 18\r\n\r\n'
|
|
b'foo=bar&posttest=2\r\n')
|
|
HttpHandler(self.client_sock, ('::1', 45678), self.server)
|
|
packet = self.client_sock.get_response()
|
|
|
|
# Parse response body
|
|
lines: List[bytes] = packet.body.split(b'\n')[:-1]
|
|
kv: Dict[str, str] = dict()
|
|
for l in lines:
|
|
k, v = l.decode('utf-8').split(':', 1)
|
|
kv[k.strip()] = v.strip() if ',' not in v else v.strip().split(',')
|
|
|
|
# Make sure the arguments were properly parsed
|
|
self.assertEqual('bar', kv['foo'])
|
|
self.assertEqual('1', kv['gettest'])
|
|
self.assertEqual('2', kv['posttest'])
|
|
|
|
def test_post_urlenc_get_array(self):
|
|
"""
|
|
Test a POST request that contains GET array arguments.
|
|
"""
|
|
# Send POST request
|
|
self.client_sock.set_request(b'POST /just/testing/post?foo=bar&test=1&foo=baz HTTP/1.1\r\n'
|
|
b'Content-Length: 0\r\n'
|
|
b'Content-Type: application/x-www-form-urlencoded\r\n\r\n')
|
|
HttpHandler(self.client_sock, ('::1', 45678), self.server)
|
|
packet = self.client_sock.get_response()
|
|
|
|
# Parse response body
|
|
lines: List[bytes] = packet.body.split(b'\n')[:-1]
|
|
kv: Dict[str, str] = dict()
|
|
for l in lines:
|
|
k, v = l.decode('utf-8').split(':', 1)
|
|
k = k.strip()
|
|
v = v.strip()
|
|
if k in kv:
|
|
kv[k] += f',{v}'
|
|
else:
|
|
kv[k] = v
|
|
# Make sure the arguments were properly parsed
|
|
self.assertEqual('bar,baz', kv['foo'])
|
|
self.assertEqual('1', kv['test'])
|
|
|
|
def test_post_urlenc_post_array(self):
|
|
"""
|
|
Test a POST request that contains POST array arguments.
|
|
"""
|
|
# Send POST request
|
|
self.client_sock.set_request(b'POST /just/testing/post HTTP/1.1\r\n'
|
|
b'Content-Length: 22\r\n'
|
|
b'Content-Type: application/x-www-form-urlencoded\r\n\r\n'
|
|
b'foo=bar&test=1&foo=baz\r\n')
|
|
HttpHandler(self.client_sock, ('::1', 45678), self.server)
|
|
packet = self.client_sock.get_response()
|
|
|
|
# Parse response body
|
|
lines: List[bytes] = packet.body.split(b'\n')[:-1]
|
|
kv: Dict[str, str] = dict()
|
|
for l in lines:
|
|
k, v = l.decode('utf-8').split(':', 1)
|
|
k = k.strip()
|
|
v = v.strip()
|
|
if k in kv:
|
|
kv[k] += f',{v}'
|
|
else:
|
|
kv[k] = v
|
|
# Make sure the arguments were properly parsed
|
|
self.assertEqual('bar,baz', kv['foo'])
|
|
self.assertEqual('1', kv['test'])
|
|
|
|
def test_post_urlenc_mixed_array(self):
|
|
"""
|
|
Test a POST request that contains both GET and POST array arguments.
|
|
"""
|
|
# Send POST request
|
|
self.client_sock.set_request(b'POST /just/testing/post?foo=getbar&gettest=1&gettest=42&foo=getbaz HTTP/1.1\r\n'
|
|
b'Content-Length: 45\r\n'
|
|
b'Content-Type: application/x-www-form-urlencoded\r\n\r\n'
|
|
b'foo=postbar&posttest=1&posttest=2&foo=postbaz\r\n')
|
|
HttpHandler(self.client_sock, ('::1', 45678), self.server)
|
|
packet = self.client_sock.get_response()
|
|
|
|
# Parse response body
|
|
lines: List[bytes] = packet.body.split(b'\n')[:-1]
|
|
kv: Dict[str, str] = dict()
|
|
for l in lines:
|
|
k, v = l.decode('utf-8').split(':', 1)
|
|
k = k.strip()
|
|
v = v.strip()
|
|
if k in kv:
|
|
kv[k] += f',{v}'
|
|
else:
|
|
kv[k] = v
|
|
# Make sure the arguments were properly parsed
|
|
self.assertEqual('postbar,postbaz', kv['foo'])
|
|
self.assertEqual('1,42', kv['gettest'])
|
|
self.assertEqual('1,2', kv['posttest'])
|
|
|
|
def test_post_no_body(self):
|
|
"""
|
|
Test a POST request that contains no headers or body.
|
|
"""
|
|
# Send POST request
|
|
self.client_sock.set_request(b'POST /just/testing/post?foo=bar HTTP/1.1\r\n\r\n')
|
|
HttpHandler(self.client_sock, ('::1', 45678), self.server)
|
|
packet = self.client_sock.get_response()
|
|
# Make sure a 400 Bad Request is returned
|
|
self.assertEqual(400, packet.statuscode)
|
|
|
|
def test_post_multipart_post_only(self):
|
|
"""
|
|
Test a POST request with a miutipart/form-data body.
|
|
"""
|
|
# Send POST request
|
|
formdata = (b'------testboundary\r\n'
|
|
b'Content-Disposition: form-data; name="foo"\r\n'
|
|
b'Content-Type: text/plain\r\n\r\n'
|
|
b'Hello, World!\r\n'
|
|
b'------testboundary\r\n'
|
|
b'Content-Disposition: form-data; name="bar"; filename="foo.bar"\r\n'
|
|
b'Content-Type: application/octet-stream\r\n\r\n'
|
|
b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x80\x0b\x0c\x73\x0e\x0f\r\n'
|
|
b'------testboundary--\r\n')
|
|
|
|
self.client_sock.set_request(f'POST /just/testing/post HTTP/1.1\r\n'
|
|
f'Content-Type: multipart/form-data; boundary=----testboundary\r\n'
|
|
f'Content-Length: {len(formdata)}\r\n\r\n'.encode('utf-8') + formdata)
|
|
HttpHandler(self.client_sock, ('::1', 45678), self.server)
|
|
packet = self.client_sock.get_response()
|
|
lines: List[bytes] = packet.body.split(b'\n')[:-1]
|
|
kv: Dict[str, Any] = dict()
|
|
for l in lines:
|
|
k, v = l.split(b':', 1)
|
|
kv[k.decode('utf-8').strip()] = v.strip()
|
|
self.assertIn('foo', kv)
|
|
self.assertIn('bar', kv)
|
|
self.assertEqual(kv['foo'], b'Hello, World!')
|
|
self.assertEqual(kv['bar'], b'00010203040506070809800b0c730e0f')
|