commit f55b84aca876a9c72ce4d364695457f8a0fd124d Author: Matt Traudt sirmatt@ksu.edu Date: Sun Jun 17 21:16:43 2018 -0400
Add simple HTTP server script --- scripts/tools/sbws-http-server.py | 77 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+)
diff --git a/scripts/tools/sbws-http-server.py b/scripts/tools/sbws-http-server.py new file mode 100755 index 0000000..d8575d0 --- /dev/null +++ b/scripts/tools/sbws-http-server.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# File: sbws-http-server.py +# Author: Matt Traudt +# License: CC0 +# +# This script implements just enough of the HTTP protocol to work with Simple +# Bandwidth Scanner. +# +# All requested URLs exist. All return 1 GiB of garbage data. We always speak +# HTTP/1.1 because that's necessary for Keep-Alive request headers +# (used by sbws scanners) to work. +# +# HEAD and GET requests are supported to the minimum extent necessary. +# This essentially means that if the client sends Range request headers just +# like sbws does, then we'll only send back the number of bytes they requested. +# Indeed, this was the motivating reason for the complexity of this script; +# normally I would have used SimpleHTTPRequestHandler unmodified. +# +# Don't breathe too hard or this script might break. +from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter +import http.server +from http import HTTPStatus +# import time + +FILE_SIZE = 1*1024*1024*1024 # 1 GiB + + +def _get_resp_size_from_range(range_str): + assert range_str.startswith('bytes=') + range_str = range_str[len('bytes='):] + start_byte, end_byte = range_str.split('-') + return int(end_byte) - int(start_byte) + 1 + + +class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): + protocol_version = 'HTTP/1.1' + + def __init__(self, *a, **kw): + super().__init__(*a, **kw) + + def send_head(self, length): + self.send_response(HTTPStatus.OK) + self.send_header('Content-Type', 'application/octet-stream') + self.send_header('Content-Length', length) + # self.send_header('Last-Modified', self.date_time_string(time.time())) + self.end_headers() + + def do_GET(self): + range_hdr = self.headers['Range'] + if not range_hdr: + num_bytes = FILE_SIZE + else: + assert range_hdr.startswith('bytes=') + num_bytes = _get_resp_size_from_range(range_hdr) + self.send_head(num_bytes) + self.wfile.write(b'A' * num_bytes) + + def do_HEAD(self): + self.send_head(FILE_SIZE) + + +def main(args): + addr = ('', args.port) + print('Listening on', addr) + httpd = http.server.HTTPServer(addr, MyHTTPRequestHandler) + httpd.serve_forever() + + +if __name__ == '__main__': + parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) + parser.add_argument( + '-p', '--port', default=8000, type=int, help='Port on which to listen') + args = parser.parse_args() + try: + exit(main(args)) + except KeyboardInterrupt: + pass