From ffc7717359f29e48026332f8e775fe5262f0d07e Mon Sep 17 00:00:00 2001 From: David Thrane Christiansen Date: Mon, 2 Jun 2025 07:55:55 +0200 Subject: [PATCH] chore: add web server script that avoids bogus caching --- README.md | 2 +- server.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100755 server.py diff --git a/README.md b/README.md index 07f4dc54..3c217afb 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ lake exe generate-manual --depth 2 Then run a local web server on its output: ``` -python3 -m http.server 8880 --directory _out/html-multi & +python3 ./server.py 8880 & ``` Then open in your browser. diff --git a/server.py b/server.py new file mode 100755 index 00000000..58f0d6ad --- /dev/null +++ b/server.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 + +# This wrapper turns off the Python HTTP server's overly aggressive +# cache headers, which can get in the way of Verso hovers. + +from http import server # Python 3 +from http.server import ThreadingHTTPServer, test +import os + + +class NonCachingHTTPRequestHandler(server.SimpleHTTPRequestHandler): + def end_headers(self): + self.send_my_headers() + server.SimpleHTTPRequestHandler.end_headers(self) + + def send_my_headers(self): + self.send_header("Cache-Control", "no-cache, no-store, must-revalidate") + self.send_header("Pragma", "no-cache") + self.send_header("Expires", "0") + +if __name__ == '__main__': + import argparse + import contextlib + + parser = argparse.ArgumentParser() + parser.add_argument('-b', '--bind', metavar='ADDRESS', + help='bind to this address ' + '(default: all interfaces)') + parser.add_argument('-d', '--directory', default="_out/html-multi", + help='serve this directory ' + '(default: _out/html-multi)') + parser.add_argument('-p', '--protocol', metavar='VERSION', + default='HTTP/1.0', + 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() + + # ensure dual-stack is not disabled; ref #38907 + class DualStackServer(ThreadingHTTPServer): + + def server_bind(self): + # suppress exception when protocol is IPv4 + with contextlib.suppress(Exception): + self.socket.setsockopt( + socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) + return super().server_bind() + + def finish_request(self, request, client_address): + self.RequestHandlerClass(request, client_address, self, + directory=args.directory) + + print(args) + + test( + HandlerClass=NonCachingHTTPRequestHandler, + ServerClass=DualStackServer, + port=args.port, + bind=args.bind, + protocol=args.protocol, + )