FlowAct-R2 / serve.py
ProAudience's picture
Deploy FlowAct-R2 static site
16ed0c5 verified
Raw
History Blame Contribute Delete
3.22 kB
#!/usr/bin/env python3
import argparse
import os
import re
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
class RangeRequestHandler(SimpleHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def send_head(self):
path = self.translate_path(self.path)
if os.path.isdir(path) or "Range" not in self.headers:
response = super().send_head()
if response and not os.path.isdir(path):
self._range = None
return response
try:
file_handle = open(path, "rb")
except OSError:
self.send_error(404, "File not found")
return None
file_size = os.fstat(file_handle.fileno()).st_size
match = re.fullmatch(r"bytes=(\d*)-(\d*)", self.headers["Range"].strip())
if not match:
file_handle.close()
self.send_error(400, "Invalid Range header")
return None
start_text, end_text = match.groups()
if not start_text:
suffix_length = int(end_text)
start = max(file_size - suffix_length, 0)
end = file_size - 1
else:
start = int(start_text)
end = int(end_text) if end_text else file_size - 1
if start >= file_size or start > end:
file_handle.close()
self.send_response(416)
self.send_header("Content-Range", f"bytes */{file_size}")
self.send_header("Content-Length", "0")
self.end_headers()
return None
end = min(end, file_size - 1)
content_length = end - start + 1
self._range = (start, end)
self.send_response(206)
self.send_header("Content-Type", self.guess_type(path))
self.send_header("Accept-Ranges", "bytes")
self.send_header("Content-Range", f"bytes {start}-{end}/{file_size}")
self.send_header("Content-Length", str(content_length))
self.send_header("Last-Modified", self.date_time_string(os.path.getmtime(path)))
self.end_headers()
file_handle.seek(start)
return file_handle
def copyfile(self, source, outputfile):
if not getattr(self, "_range", None):
return super().copyfile(source, outputfile)
remaining = self._range[1] - self._range[0] + 1
while remaining:
chunk = source.read(min(64 * 1024, remaining))
if not chunk:
break
outputfile.write(chunk)
remaining -= len(chunk)
def main():
parser = argparse.ArgumentParser(description="Serve static files with HTTP Range support.")
parser.add_argument("--bind", default="0.0.0.0")
parser.add_argument("--port", type=int, default=8123)
parser.add_argument("--directory", default=".")
args = parser.parse_args()
handler = lambda *handler_args, **handler_kwargs: RangeRequestHandler(
*handler_args, directory=args.directory, **handler_kwargs
)
server = ThreadingHTTPServer((args.bind, args.port), handler)
print(f"Serving {os.path.abspath(args.directory)} on http://{args.bind}:{args.port}")
server.serve_forever()
if __name__ == "__main__":
main()