Refactor: fix socket leak, deduplicate stat/path logic, simplify config

- get_local_ip: use context manager to prevent socket leak
- _route_files: single stat() per file instead of two
- _safe_path helper: DRY path resolution for download/delete
- load_config: loop over vars(args) instead of 6 repetitive blocks
- Remove stale comment from index.html

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 20:38:53 +04:00
co-authored by Claude Opus 4.6
parent 266308a2eb
commit ebe5c6ec90
2 changed files with 17 additions and 27 deletions
+16 -24
View File
@@ -39,11 +39,9 @@ def cleanup_loop(upload_dir: Path, max_age: int):
def get_local_ip():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("8.8.8.8", 80))
ip = s.getsockname()[0]
s.close()
return ip
return s.getsockname()[0]
except Exception:
return "127.0.0.1"
@@ -158,15 +156,19 @@ class Handler(http.server.BaseHTTPRequestHandler):
self._respond(self.server.html, "text/html; charset=utf-8")
def _route_files(self):
files = []
for p in sorted(self.server.upload_dir.iterdir(), key=lambda p: p.stat().st_mtime, reverse=True):
entries = []
for p in self.server.upload_dir.iterdir():
if p.is_file():
files.append({"name": p.name, "size": p.stat().st_size, "type": _file_type(p)})
self._json(files)
entries.append((p, p.stat()))
entries.sort(key=lambda e: e[1].st_mtime, reverse=True)
self._json([{"name": p.name, "size": st.st_size, "type": _file_type(p)} for p, st in entries])
def _safe_path(self, prefix_len: int) -> Path:
name = urllib.parse.unquote(self.path[prefix_len:])
return self.server.upload_dir / Path(name).name
def _route_download(self):
name = urllib.parse.unquote(self.path[4:])
safe = self.server.upload_dir / Path(name).name
safe = self._safe_path(4)
if not safe.is_file():
self.send_error(404)
return
@@ -191,8 +193,7 @@ class Handler(http.server.BaseHTTPRequestHandler):
self._json({"ok": True, "count": count})
def _route_delete(self):
name = urllib.parse.unquote(self.path[5:])
safe = self.server.upload_dir / Path(name).name
safe = self._safe_path(5)
if safe.is_file():
safe.unlink()
self._json({"ok": True})
@@ -260,18 +261,9 @@ def load_config() -> dict:
p.add_argument("--refresh", type=int)
args = p.parse_args()
if args.port is not None:
conf["port"] = str(args.port)
if args.dir is not None:
conf["dir"] = args.dir
if args.ttl is not None:
conf["ttl"] = str(args.ttl)
if args.san is not None:
conf["san"] = " ".join(args.san)
if args.lang is not None:
conf["lang"] = args.lang
if args.refresh is not None:
conf["refresh"] = str(args.refresh)
for key, val in vars(args).items():
if val is not None:
conf[key] = " ".join(val) if isinstance(val, list) else str(val)
return conf
-2
View File
@@ -259,8 +259,6 @@ $('lang-sw').addEventListener('click', e => {
if (e.target.dataset.l) setLang(e.target.dataset.l);
});
/* File type is determined server-side via /files API ("text" | "image" | "other") */
/* ── Helpers ── */
let toastTimer;