commit 8a55092: [Test] Rewrite dummy http server
Vsevolod Stakhov
vsevolod at rspamd.com
Sat Dec 31 14:21:03 UTC 2022
Author: Vsevolod Stakhov
Date: 2022-12-31 13:28:49 +0000
URL: https://github.com/rspamd/rspamd/commit/8a5509271689250f6a57587d01a2b288163fd16f
[Test] Rewrite dummy http server
---
test/functional/util/dummy_http.py | 268 +++++++++++++++++-------------------
test/functional/util/dummy_https.py | 141 -------------------
2 files changed, 123 insertions(+), 286 deletions(-)
diff --git a/test/functional/util/dummy_http.py b/test/functional/util/dummy_http.py
index 1fb721413..8e2cc2656 100755
--- a/test/functional/util/dummy_http.py
+++ b/test/functional/util/dummy_http.py
@@ -1,154 +1,132 @@
#!/usr/bin/env python3
-import http.server
+import tornado.ioloop
+import tornado.web
+import tornado.httpserver
+import ssl
+import argparse
import os
-import socket
-import socketserver
-import sys
-import time
-from urllib.parse import urlparse, parse_qs
-import dummy_killer
-
-PORT = 18080
-HOST_NAME = '0.0.0.0'
-
-PID = "/tmp/dummy_http.pid"
-
-
-class MyHandler(http.server.BaseHTTPRequestHandler):
- protocol_version = 'HTTP/1.1'
-
- def do_HEAD(self):
- if self.path == "/redirect1":
- self.send_response(301)
- self.send_header("Location", "http://127.0.0.1:"+str(PORT)+"/hello")
- elif self.path == "/redirect2":
- self.send_response(301)
- self.send_header("Location", "http://127.0.0.1:"+str(PORT)+"/redirect1")
- elif self.path == "/redirect3":
- self.send_response(301)
- self.send_header("Location", "http://127.0.0.1:"+str(PORT)+"/redirect4")
- elif self.path == "/redirect4":
- self.send_response(301)
- self.send_header("Location", "http://127.0.0.1:"+str(PORT)+"/redirect3")
+class MainHandler(tornado.web.RequestHandler):
+ @tornado.gen.coroutine
+ def get(self, path):
+ if path == '/empty':
+ # Return an empty reply
+ self.set_header("Content-Type", "text/plain")
+ self.write("")
+ elif path == '/error_403':
+ # Return a 403 HTTP error
+ raise tornado.web.HTTPError(403)
+ elif path == '/timeout':
+ # Wait for 4 seconds before returning an empty reply
+ yield tornado.gen.sleep(4)
+ self.set_header("Content-Type", "text/plain")
+ self.write("")
+ elif path == '/map-simple':
+ # Return a string 'hello map'
+ self.set_header("Content-Type", "text/plain")
+ self.write("hello map")
+ elif path == '/map-query':
+ # Parse the 'key' argument from the HTTP request
+ key = self.get_query_argument("key", default=None)
+ if key == 'au':
+ # Return a string 'hit' if 'key' is equal to 'au'
+ self.set_header("Content-Type", "text/plain")
+ self.write("hit")
+ else:
+ # Return a 404 HTTP error if 'key' is not equal to 'au'
+ raise tornado.web.HTTPError(404)
+ elif path == '/settings':
+ self.set_header("Content-Type", "application/json")
+ self.write("{\"actions\": { \"reject\": 1.0}, \"symbols\": { \"EXTERNAL_SETTINGS\": 1.0 }}")
else:
- self.send_response(200)
- self.send_header("Content-type", "text/html")
- self.end_headers()
- self.log_message("to be closed: " + repr(self.close_connection))
-
- def do_GET(self):
- """Respond to a GET request."""
- response = b"hello world"
- url = urlparse(self.path)
- self.path = url.path
-
- if self.path == "/empty":
- self.finish()
- return
-
- if self.path == "/timeout":
- time.sleep(2)
- elif self.path == "/error_403":
- self.send_response(403)
- elif self.path == "/map-query":
- query = parse_qs(url.query)
- self.log_message('query=%s', query)
- if query['key'][0] == 'au':
- response = b"1.0"
- self.send_response(200)
+ raise tornado.web.HTTPError(404)
+
+ @tornado.gen.coroutine
+ def post(self, path):
+ if path == '/empty':
+ # Return an empty reply
+ self.set_header("Content-Type", "text/plain")
+ self.write("")
+ elif path == '/error_403':
+ # Return a 403 HTTP error
+ raise tornado.web.HTTPError(403)
+ elif path == '/timeout':
+ # Wait for 4 seconds before returning an empty reply
+ yield tornado.gen.sleep(4)
+ self.set_header("Content-Type", "text/plain")
+ self.write("")
+ elif path == '/map-simple':
+ # Return a string 'hello map'
+ self.set_header("Content-Type", "text/plain")
+ self.write("hello map")
+ elif path == '/map-query':
+ # Parse the 'key' argument from the HTTP request
+ key = self.get_query_argument("key", default="")
+ if key == 'au':
+ # Return a string 'hit' if 'key' is equal to 'au'
+ self.set_header("Content-Type", "text/plain")
+ self.write("hit")
else:
- response = b""
- self.send_response(404)
+ # Return a 404 HTTP error if 'key' is not equal to 'au'
+ raise tornado.web.HTTPError(404)
+ elif path == '/settings':
+ self.set_header("Content-Type", "application/json")
+ self.write("{\"actions\": { \"reject\": 1.0}, \"symbols\": { \"EXTERNAL_SETTINGS\": 1.0 }}")
else:
- self.send_response(200)
-
- self.send_header("Content-Length", str(len(response)))
- self.send_header("Content-type", "text/plain")
- self.end_headers()
- self.wfile.write(response)
- self.log_message("to be closed: %d, headers: %s, conn:'%s'" % (self.close_connection, str(self.headers), self.headers.get('Connection', "").lower()))
-
- conntype = self.headers.get('Connection', "").lower()
- if conntype != 'keep-alive':
- self.close_connection = True
-
- self.log_message("ka:'%s', pv:%s[%s]" % (str(conntype == 'keep-alive'), str(self.protocol_version >= "HTTP/1.1"), self.protocol_version))
-
-
- def do_POST(self):
- """Respond to a POST request."""
- response = b"hello post"
- content_length = int(self.headers.get('Content-Length', "0")) or 0
- content_type = "text/plain"
- url = urlparse(self.path)
- self.path = url.path
- if content_length > 0:
- _ = self.rfile.read(content_length)
- if self.path == "/empty":
- self.finish()
- return
-
- if self.path == "/timeout":
- time.sleep(2)
-
- if self.path == "/error_403":
- self.send_response(403)
+ raise tornado.web.HTTPError(404)
+
+ def head(self, path):
+ self.set_header("Content-Type", "text/plain")
+ if path == "/redirect1":
+ # Send an HTTP redirect to the bind address of the server
+ self.redirect(f"http://{self.request.host}:{self.request.port}/hello")
+ elif path == "/redirect2":
+ # Send an HTTP redirect to the bind address of the server
+ self.redirect(f"http://{self.request.host}:{self.request.port}/redirect1")
+ elif self.path == "/redirect3":
+ # Send an HTTP redirect to the bind address of the server
+ self.redirect(f"http://{self.request.host}:{self.request.port}/redirect4")
+ elif self.path == "/redirect4":
+ # Send an HTTP redirect to the bind address of the server
+ self.redirect(f"http://{self.request.host}:{self.request.port}/redirect3")
else:
self.send_response(200)
- if self.path == "/map-simple":
- response = b"hello map"
- if self.path == "/map-query":
- query = parse_qs(url.query)
- if query['key'] == 'au':
- response = b"hit"
- else:
- self.send_response(404)
- if self.path == "/settings":
- response = b"{\"actions\": { \"reject\": 1.0}, \"symbols\": { \"EXTERNAL_SETTINGS\": 1.0 }}"
- content_type = "application/json"
-
- self.send_header("Content-Length", str(len(response)))
- conntype = self.headers.get('Connection', "").lower()
- if conntype != 'keep-alive':
- self.close_connection = True
- else:
- self.send_header("Connection", "keep-alive")
-
- self.send_header("Content-type", content_type)
- self.end_headers()
- self.wfile.write(response)
- self.log_message("to be closed: %d, headers: %s, conn:'%s'" % (self.close_connection, str(self.headers), self.headers.get('Connection', "").lower()))
- self.log_message("ka:'%s', pv:%s[%s]" % (str(conntype == 'keep-alive'), str(self.protocol_version >= "HTTP/1.1"), self.protocol_version))
-
-
-class ThreadingSimpleServer(socketserver.ThreadingMixIn,
- http.server.HTTPServer):
- def __init__(self):
- self.allow_reuse_address = True
- self.timeout = 1
- http.server.HTTPServer.__init__(self, (HOST_NAME, PORT), MyHandler)
-
- def run(self):
- dummy_killer.write_pid(PID)
- try:
- while 1:
- sys.stdout.flush()
- server.handle_request()
- except KeyboardInterrupt:
- print("Interrupt")
- except socket.error:
- print("Socket closed")
-
- def stop(self):
- self.keep_running = False
- self.server_close()
-
-
-if __name__ == '__main__':
- server = ThreadingSimpleServer()
-
- dummy_killer.setup_killer(server, server.stop)
-
- server.run()
+ self.set_header("Content-Type", "text/plain")
+
+def make_app():
+ return tornado.web.Application([
+ (r"(/[^/]+)", MainHandler),
+ ])
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--bind", "-b", default="localhost", help="bind address")
+ parser.add_argument("--port", "-p", type=int, default=18080, help="bind port")
+ parser.add_argument("--keyfile", "-k", help="server private key file")
+ parser.add_argument("--certfile", "-c", help="server certificate file")
+ parser.add_argument("--pidfile", "-pf", help="path to the PID file")
+ args = parser.parse_args()
+
+ # Create the Tornado application
+ app = make_app()
+
+ # If keyfile and certfile are provided, create an HTTPS server.
+ # Otherwise, create an HTTP server.
+ if args.keyfile and args.certfile:
+ ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
+ ssl_ctx.load_cert_chain(args.certfile, args.keyfile)
+ server = tornado.httpserver.HTTPServer(app, ssl_options=ssl_ctx)
+ else:
+ server = tornado.httpserver.HTTPServer(app)
+
+ # Start the server
+ server.bind(args.port, args.bind)
+ server.start(1)
+
+ # Write the PID to the specified PID file, if provided
+ if args.pidfile:
+ with open(args.pidfile, "w") as f:
+ f.write(str(os.getpid()))
+
+ tornado.ioloop.IOLoop.current().start()
diff --git a/test/functional/util/dummy_https.py b/test/functional/util/dummy_https.py
deleted file mode 100755
index 1dc058bdb..000000000
--- a/test/functional/util/dummy_https.py
+++ /dev/null
@@ -1,141 +0,0 @@
-#!/usr/bin/env python3
-
-import http.server
-import http.server
-import os
-import socket
-import socketserver
-import ssl
-import sys
-import time
-
-import dummy_killer
-from urllib.parse import urlparse, parse_qs
-
-PORT = 18081
-HOST_NAME = '127.0.0.1'
-
-PID = "/tmp/dummy_https.pid"
-
-
-class MyHandler(http.server.BaseHTTPRequestHandler):
-
- def setup(self):
- http.server.BaseHTTPRequestHandler.setup(self)
- self.protocol_version = "HTTP/1.1" # allow connection: keep-alive
-
- def do_HEAD(self):
- self.send_response(200)
- self.send_header("Content-type", "text/html")
- self.end_headers()
- self.log_message("to be closed: " + self.close_connection)
-
- def do_GET(self):
- response = b"hello world"
-
- """Respond to a GET request."""
- if self.path == "/empty":
- self.finish()
- return
-
- if self.path == "/timeout":
- time.sleep(2)
-
- if self.path == "/error_403":
- self.send_response(403)
- else:
- self.send_response(200)
-
- if self.path == "/content-length":
- self.send_header("Content-Length", str(len(response)))
-
- self.send_header("Content-type", "text/plain")
- self.end_headers()
- self.wfile.write(response)
- self.log_message("to be closed: %d, headers: %s, conn:'%s'" % (self.close_connection, str(self.headers), self.headers.get('Connection', "").lower()))
-
- conntype = self.headers.get('Connection', "").lower()
- if conntype != 'keep-alive':
- self.close_connection = True
-
- self.log_message("ka:'%s', pv:%s[%s]" % (str(conntype == 'keep-alive'), str(self.protocol_version >= "HTTP/1.1"), self.protocol_version))
-
-
- def do_POST(self):
- """Respond to a POST request."""
- response = b"hello post"
- content_length = int(self.headers.get('Content-Length', "0")) or 0
- content_type = "text/plain"
- url = urlparse(self.path)
- self.path = url.path
- if content_length > 0:
- _ = self.rfile.read(content_length)
- if self.path == "/empty":
- self.finish()
- return
-
- if self.path == "/timeout":
- time.sleep(2)
-
- if self.path == "/error_403":
- self.send_response(403)
- else:
- self.send_response(200)
- if self.path == "/map-simple":
- response = b"hello map"
- if self.path == "/map-query":
- query = parse_qs(url.query)
- if query['key'] == 'au':
- response = b"hit"
- else:
- self.send_response(404)
- if self.path == "/settings":
- response = b"{\"actions\": { \"reject\": 1.0}, \"symbols\": { \"EXTERNAL_SETTINGS\": 1.0 }}"
- content_type = "application/json"
-
- self.send_header("Content-Length", str(len(response)))
- conntype = self.headers.get('Connection', "").lower()
- if conntype != 'keep-alive':
- self.close_connection = True
- else:
- self.send_header("Connection", "keep-alive")
-
- self.send_header("Content-type", content_type)
- self.end_headers()
- self.wfile.write(response)
- self.log_message("to be closed: %d, headers: %s, conn:'%s'" % (self.close_connection, str(self.headers), self.headers.get('Connection', "").lower()))
- self.log_message("ka:'%s', pv:%s[%s]" % (str(conntype == 'keep-alive'), str(self.protocol_version >= "HTTP/1.1"), self.protocol_version))
-
-class ThreadingSimpleServer(socketserver.ThreadingMixIn,
- http.server.HTTPServer):
- def __init__(self, certfile,
- keyfile,):
- self.allow_reuse_address = True
- self.timeout = 10
- http.server.HTTPServer.__init__(self, (HOST_NAME, PORT), MyHandler)
- self.socket = ssl.wrap_socket (self.socket,
- keyfile=keyfile,
- certfile=certfile, server_side=True)
-
- def run(self):
- dummy_killer.write_pid(PID)
- try:
- while 1:
- sys.stdout.flush()
- server.handle_request()
- except KeyboardInterrupt:
- print("Interrupt")
- except socket.error:
- print("Socket closed")
-
- def stop(self):
- self.keep_running = False
- self.server_close()
-
-
-if __name__ == '__main__':
- server = ThreadingSimpleServer(sys.argv[1], sys.argv[1])
-
- dummy_killer.setup_killer(server, server.stop)
-
- server.run()
More information about the Commits
mailing list