From 67db4c654a54f94270c8e89dec3e53238c00410e Mon Sep 17 00:00:00 2001 From: s3lph Date: Tue, 19 Jun 2018 23:51:20 +0200 Subject: [PATCH] Added tests for HTTP POST requests. --- matemat/webserver/httpd.py | 21 ++------ matemat/webserver/test/test_post.py | 77 ++++++++++++++++++++++++++++ matemat/webserver/test/test_serve.py | 11 ++++ 3 files changed, 93 insertions(+), 16 deletions(-) create mode 100644 matemat/webserver/test/test_post.py diff --git a/matemat/webserver/httpd.py b/matemat/webserver/httpd.py index a22969e..220849c 100644 --- a/matemat/webserver/httpd.py +++ b/matemat/webserver/httpd.py @@ -227,13 +227,8 @@ class HttpHandler(BaseHTTPRequestHandler): # Make sure the file is actually inside the webroot directory and that it exists if os.path.commonpath([filepath, self.server.webroot]) == self.server.webroot and os.path.exists(filepath): # Open and read the file - try: - with open(filepath, 'rb') as f: - data = f.read() - except PermissionError: - self.send_error(403) - self.end_headers() - return + with open(filepath, 'rb') as f: + data = f.read() # File read successfully, send 'OK' header self.send_response(200) # TODO: Guess the MIME type. Unfortunately this call solely relies on the file extension, not ideal? @@ -292,22 +287,16 @@ class HttpHandler(BaseHTTPRequestHandler): path, args = self._parse_args(self.path) self._handle('GET', path, args) # Special handling for some errors - except PermissionError as e: + except PermissionError: self.send_response(403, 'Forbidden') self.end_headers() - print(e) - traceback.print_tb(e.__traceback__) - except ValueError as e: + except ValueError: self.send_response(400, 'Bad Request') self.end_headers() - print(e) - traceback.print_tb(e.__traceback__) - except BaseException as e: + except BaseException: # Generic error handling self.send_response(500, 'Internal Server Error') self.end_headers() - print(e) - traceback.print_tb(e.__traceback__) # noinspection PyPep8Naming def do_POST(self) -> None: diff --git a/matemat/webserver/test/test_post.py b/matemat/webserver/test/test_post.py new file mode 100644 index 0000000..cc92ad1 --- /dev/null +++ b/matemat/webserver/test/test_post.py @@ -0,0 +1,77 @@ + +from typing import Any, Dict, List + +import os +import os.path +from matemat.webserver.httpd import HttpHandler +from matemat.webserver.test.abstract_httpd_test import AbstractHttpdTest, test_pagelet + + +@test_pagelet('/just/testing/post') +def post_test_pagelet(method: str, + path: str, + args: Dict[str, str], + session_vars: Dict[str, Any], + headers: Dict[str, str]): + dump: str = '' + for k, v in args.items(): + dump += f'{k}: {v}\n' + return 200, dump + + +class TestPost(AbstractHttpdTest): + """ + Test cases for the content serving of the web server. + """ + + def setUp(self): + super().setUp() + # Create a static resource in the temp dir + with open(os.path.join(self.tempdir.name, 'static_resource.txt'), 'w') as f: + f.write('static resource test') + + def test_post_get_only_args(self): + 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() + lines: List[str] = packet.body.split('\n')[:-1] + kv: Dict[str, str] = dict() + for l in lines: + k, v = l.split(':', 1) + kv[k.strip()] = v.strip() + self.assertEqual('bar', kv['foo']) + self.assertEqual('1', kv['test']) + + def test_post_post_only_args(self): + 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() + lines: List[str] = packet.body.split('\n')[:-1] + kv: Dict[str, str] = dict() + for l in lines: + k, v = l.split(':', 1) + kv[k.strip()] = v.strip() + self.assertEqual('bar', kv['foo']) + self.assertEqual('1', kv['test']) + + def test_post_mixed_args(self): + 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() + lines: List[str] = packet.body.split('\n')[:-1] + kv: Dict[str, str] = dict() + for l in lines: + k, v = l.split(':', 1) + kv[k.strip()] = v.strip() + self.assertEqual('bar', kv['foo']) + self.assertEqual('1', kv['gettest']) + self.assertEqual('2', kv['posttest']) + diff --git a/matemat/webserver/test/test_serve.py b/matemat/webserver/test/test_serve.py index 5fdc6ec..f3dc6be 100644 --- a/matemat/webserver/test/test_serve.py +++ b/matemat/webserver/test/test_serve.py @@ -113,3 +113,14 @@ class TestServe(AbstractHttpdTest): self.assertIsNone(packet.pagelet) # Make sure a 404 header is served self.assertEqual(404, packet.statuscode) + + def test_static_post_not_allowed(self): + # Request a resource outside the webroot + self.client_sock.set_request(b'POST /iwanttouploadthis HTTP/1.1\r\n\r\nq=this%20should%20not%20be%20uploaded') + HttpHandler(self.client_sock, ('::1', 45678), self.server) + packet = self.client_sock.get_response() + + # Make sure that no pagelet was called + self.assertIsNone(packet.pagelet) + # Make sure a 405 Method Not Allowed header is served + self.assertEqual(405, packet.statuscode)