0

I've created my own script based on Python http.server module. The main target of script is handling custom path "/files" to get list of files in JSON format. Parameter --protocol was added in Python 3.11 for http.server module. I use Python 3.11.4. I'm trying to support this parameter in my script in the following way:

import json
import os
import sys
from functools import partial
from http.server import SimpleHTTPRequestHandler, test
from pathlib import Path


class HTTPRequestHandler(SimpleHTTPRequestHandler):
    def do_GET(self) -> None:
        if self.path == '/files':
            response = bytes(self._get_response(), 'utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.send_header('Content-Length', str(len(response)))
            self.end_headers()
            self.wfile.write(response)

            return

        return super().do_GET()

    def _get_response(self) -> str:
        results = []

        for item in Path(self.directory).rglob('*'):
            if item.is_file():
                if __file__ in str(item):
                    continue

                file_size = str(os.stat(item).st_size)
                relative_file_path = os.path.relpath(item, self.directory)

                if sys.platform == 'win32':
                    relative_file_path = relative_file_path.replace('\\', '/')

                results.append(dict(file=relative_file_path, size=file_size))

        return json.dumps(results)


if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('-b', '--bind', metavar='ADDRESS',
                        help='bind to this address '
                        '(default: all interfaces)')
    parser.add_argument('-d', '--directory', default=os.getcwd(),
                        help='serve this directory '
                        '(default: current directory)')
    parser.add_argument('-p', '--protocol', metavar='VERSION',
                        default='HTTP/1.1',
                        help='conform to this HTTP version '
                             '(default: %(default)s)')
    parser.add_argument('port', default=8000, type=int, nargs='?',
                        help='bind to this port '
                        '(default: %(default)s)')
    args = parser.parse_args()

    handler_class = partial(HTTPRequestHandler, directory=args.directory)

    test(HandlerClass=handler_class, port=args.port, bind=args.bind, protocol=args.protocol)
python server.py --bind <ip> <port> -p HTTP/1.1

But by some reason response header still contains "HTTP/1.0" version. Could you please advice what I'm doing wrong?

Pavel
  • 141
  • 1
  • 3
  • 10

2 Answers2

1

Create TCPServer instance and set protocol_version on the HTTPRequestHandler class to "HTTP/1.1" then it uses HTTP/1.1 when running.

from socketserver import TCPServer
...

handler_class = partial(HTTPRequestHandler, directory=args.directory)
HTTPRequestHandler.protocol_version = args.protocol
PORT = args.port
with TCPServer(("", PORT), handler_class) as httpd:
    print("Serving HTTP on port", PORT)
    httpd.serve_forever()

If call http.server.test() function then it sets protocol_version on the provided HandlerClass argument, but won't work if using a partial to wrap the class so must explicitly set HTTPRequestHandler.protocol_version.

CodeMonkey
  • 22,825
  • 4
  • 35
  • 75
  • Thanks for the tip! I’ll check. Anyway, for me it’s not clear why `address` and `port` are applied correct, but `protocol` not. – Pavel Jul 27 '23 at 20:05
0

Problem was solved by setting value for protocol_version on the custom handler:

...

if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('-b', '--bind', metavar='ADDRESS',
                        help='bind to this address '
                        '(default: all interfaces)')
    parser.add_argument('-d', '--directory', default=os.getcwd(),
                        help='serve this directory '
                        '(default: current directory)')
    # --protocol argument was introduced in Python 3.11+
    parser.add_argument('-p', '--protocol', metavar='VERSION',
                        default='HTTP/1.1',
                        help='conform to this HTTP version '
                        '(default: %(default)s)')
    parser.add_argument('port', default=8000, type=int, nargs='?',
                        help='bind to this port '
                        '(default: %(default)s)')
    args = parser.parse_args()

    HTTPRequestHandler.protocol_version = args.protocol
    handler_class = partial(HTTPRequestHandler, directory=args.directory)

    test(HandlerClass=handler_class, port=args.port, bind=args.bind)
Pavel
  • 141
  • 1
  • 3
  • 10