|
@@ -0,0 +1,127 @@
|
|
|
+#!/usr/local/bin/python3.8
|
|
|
+"""
|
|
|
+A Simple Python HTTP server that echos the request in the response.
|
|
|
+"""
|
|
|
+
|
|
|
+import socket
|
|
|
+import argparse
|
|
|
+from six.moves.urllib import parse
|
|
|
+import email.message
|
|
|
+
|
|
|
+try:
|
|
|
+ from email.generator import BytesGenerator
|
|
|
+except ImportError:
|
|
|
+ # BBB Python 2 compatibility
|
|
|
+ from email.generator import Generator as BytesGenerator
|
|
|
+
|
|
|
+from six.moves import BaseHTTPServer
|
|
|
+
|
|
|
+parser = argparse.ArgumentParser(
|
|
|
+ description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
|
|
+)
|
|
|
+parser.add_argument(
|
|
|
+ "--address",
|
|
|
+ "-a",
|
|
|
+ default="0.0.0.0",
|
|
|
+ help="Hostname or IP address to accept requests on.",
|
|
|
+)
|
|
|
+parser.add_argument(
|
|
|
+ "--port",
|
|
|
+ "-p",
|
|
|
+ help="Port to accept requests on. "
|
|
|
+ "If not specified, use the first available port after 8000.",
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
+class EchoHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|
|
+ """
|
|
|
+ A Simple Python HTTP server that echos the request in the response.
|
|
|
+ """
|
|
|
+
|
|
|
+ def do_GET(self):
|
|
|
+ """
|
|
|
+ Echo a request without a body.
|
|
|
+ """
|
|
|
+ message = self.get_message()
|
|
|
+ self.send_head()
|
|
|
+ BytesGenerator(self.wfile).flatten(message, unixfrom=False)
|
|
|
+
|
|
|
+ do_HEAD = do_GET
|
|
|
+ do_OPTIONS = do_GET
|
|
|
+ do_DELETE = do_GET
|
|
|
+
|
|
|
+ def do_POST(self):
|
|
|
+ """
|
|
|
+ Echo a request with a body.
|
|
|
+ """
|
|
|
+ message = self.get_message()
|
|
|
+ message.set_payload(self.rfile.read(int(self.headers["Content-Length"])))
|
|
|
+ self.send_head()
|
|
|
+ BytesGenerator(self.wfile).flatten(message, unixfrom=False)
|
|
|
+
|
|
|
+ do_PUT = do_POST
|
|
|
+ do_PATCH = do_POST
|
|
|
+
|
|
|
+ def send_head(self):
|
|
|
+ """
|
|
|
+ Send all the basic, required headers.
|
|
|
+ """
|
|
|
+ self.send_response(200)
|
|
|
+ self.send_header("Content-Type", "text/rfc822-headers; charset=UTF-8")
|
|
|
+ self.send_header("Last-Modified", self.date_time_string())
|
|
|
+ self.end_headers()
|
|
|
+
|
|
|
+ def get_message(self):
|
|
|
+ """
|
|
|
+ Assemble the basic message including query parameters.
|
|
|
+ """
|
|
|
+ message = email.message.Message()
|
|
|
+ message["Method"] = self.command
|
|
|
+ message["Path"] = self.path
|
|
|
+
|
|
|
+ server_url = parse.SplitResult(
|
|
|
+ "http",
|
|
|
+ "{0}:{1}".format(self.server.server_name, self.server.server_port),
|
|
|
+ "",
|
|
|
+ "",
|
|
|
+ "",
|
|
|
+ )
|
|
|
+ request_url = parse.urlsplit(server_url.geturl() + self.path)
|
|
|
+ for header, value in parse.parse_qs(request_url.query).items():
|
|
|
+ message.add_header(header, value[0])
|
|
|
+
|
|
|
+ return message
|
|
|
+
|
|
|
+
|
|
|
+def main(args=None, default_port=8000):
|
|
|
+ """
|
|
|
+ Run the echo HTTP server.
|
|
|
+ """
|
|
|
+ args = parser.parse_args(args)
|
|
|
+
|
|
|
+ port = args.port
|
|
|
+ if port is None:
|
|
|
+ port = default_port
|
|
|
+ bound = False
|
|
|
+ while not bound:
|
|
|
+ try:
|
|
|
+ httpd = BaseHTTPServer.HTTPServer(
|
|
|
+ (args.address, port), EchoHTTPRequestHandler
|
|
|
+ )
|
|
|
+ except socket.error:
|
|
|
+ port += 1
|
|
|
+ if port > 65535:
|
|
|
+ raise ValueError("No available port found")
|
|
|
+ else:
|
|
|
+ bound = True
|
|
|
+ else:
|
|
|
+ httpd = BaseHTTPServer.HTTPServer(
|
|
|
+ (args.address, int(port)), EchoHTTPRequestHandler
|
|
|
+ )
|
|
|
+
|
|
|
+ print("Echoing HTTP at http://{0}:{1} ...".format(args.address, port))
|
|
|
+ httpd.serve_forever()
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ main()
|