Skip to content

Instantly share code, notes, and snippets.

@leetschau
Created April 20, 2025 07:09
Show Gist options
  • Save leetschau/25c37cd63df6dba7c52194e62a08dcad to your computer and use it in GitHub Desktop.
Save leetschau/25c37cd63df6dba7c52194e62a08dcad to your computer and use it in GitHub Desktop.
A standalone (and naive) texts and files sharing web server
#!/usr/bin/env python3
## This script starts a Web server providing texts and files sharing function.
## See the usage with `-h` option.
import os
import sys
import argparse
import urllib.parse
from http.server import HTTPServer, BaseHTTPRequestHandler
from html import escape
text_log = []
class SimpleHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.respond(200, "text/html; charset=utf-8", self.render_main_page())
elif self.path.startswith("/files/"):
filename = os.path.basename(urllib.parse.unquote(self.path[len("/files/"):]))
file_path = os.path.join(self.server.directory, filename)
if os.path.isfile(file_path):
with open(file_path, "rb") as f:
data = f.read()
self.send_response(200)
self.send_header("Content-Disposition", f"attachment; filename*=UTF-8''{urllib.parse.quote(filename)}")
self.send_header("Content-Type", "application/octet-stream")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
else:
self.send_error(404, "File not found")
else:
self.send_error(404)
def do_POST(self):
content_type = self.headers.get("Content-Type", "")
content_length = int(self.headers.get("Content-Length", "0"))
body = self.rfile.read(content_length)
if self.path == "/upload" and "multipart/form-data" in content_type:
boundary = content_type.split("boundary=")[-1].encode()
parts = body.split(b"--" + boundary)
for part in parts:
if b"filename=" in part:
header_data, file_data = part.split(b"\r\n\r\n", 1)
file_data = file_data.rstrip(b"\r\n--")
disposition = [line for line in header_data.split(b"\r\n") if b"Content-Disposition" in line][0]
disposition_str = disposition.decode("utf-8", errors="replace")
filename_enc = disposition_str.split("filename=")[-1].strip().strip('"')
filename = os.path.basename(filename_enc)
if filename:
with open(os.path.join(self.server.directory, filename), "wb") as f:
f.write(file_data)
self.redirect("/")
elif self.path == "/text":
fields = urllib.parse.parse_qs(body.decode('utf-8', errors='replace'))
text = fields.get("text", [""])[0]
text_log.append(text)
print("Received text:", text)
self.redirect("/")
else:
self.send_error(400)
def render_main_page(self):
file_list_html = "".join(
f"<li><a href='/files/{urllib.parse.quote(f)}'>{escape(f)}</a></li>"
for f in os.listdir(self.server.directory)
if os.path.isfile(os.path.join(self.server.directory, f))
)
log_html = escape("\n".join(text_log))
directory_display = escape(self.server.directory)
return f"""
<html><head><meta charset="utf-8"></head><body>
<h1>File & Text Server</h1>
<h2>Upload File</h2>
<form method="POST" action="/upload" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
<h2>Files at {directory_display}</h2>
<ul>{file_list_html}</ul>
<h2>Send Text</h2>
<form method="POST" action="/text">
<textarea name="text" rows="4" cols="50"></textarea><br>
<input type="submit" value="Send">
</form>
<h2>Text Log</h2>
<pre>{log_html}</pre>
</body></html>
"""
def respond(self, status, content_type, content):
content_bytes = content.encode("utf-8")
self.send_response(status)
self.send_header("Content-Type", content_type)
self.send_header("Content-Length", str(len(content_bytes)))
self.end_headers()
self.wfile.write(content_bytes)
def redirect(self, location):
self.send_response(303)
self.send_header("Location", location)
self.end_headers()
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--dir", default=".", help="Directory to serve files from (default: current directory)")
parser.add_argument("--port", type=int, default=7123, help="Port to listen on (default: 7123)")
args = parser.parse_args()
directory = os.path.abspath(args.dir)
if not os.path.isdir(directory):
print("Directory does not exist:", directory)
sys.exit(1)
server = HTTPServer(('', args.port), SimpleHandler)
server.directory = directory
print(f"Serving at http://localhost:{args.port}")
print(f"Sharing directory: {directory}")
server.serve_forever()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment