#!/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()