v1.1.0: fix /crawl/* GET routes (move handlers to do_GET start)

Bug: /crawl/status and /crawl/download handlers were placed after
return statement in do_GET, making them dead code. Static file
check would 404 + fall through to index.html (HTML 200), masking
the real issue.

Fix: move /crawl/* API handlers to top of do_GET, before static
file check. Now /crawl/status returns JSON, /crawl/download
returns file with proper Content-Disposition.

Also: cleanup duplicate def do_GET introduced by earlier patch.

Reported by: Hermes (@Ir_workbot)
This commit is contained in:
IT狗
2026-07-24 20:23:39 +08:00
parent e6116ecc7d
commit 2e823c9d16
+47 -58
View File
@@ -313,9 +313,52 @@ class Handler(BaseHTTPRequestHandler):
self.wfile.write(json.dumps(data).encode()) self.wfile.write(json.dumps(data).encode())
def do_GET(self): def do_GET(self):
# Static file serving: <file> or /url2pdf-tools/<file> → /opt/url2pdf/<file> # 1. /crawl/status?job=ID - poll job status
# (nginx strips /url2pdf prefix; we accept both with and without it) if self.path.startswith("/crawl/status"):
# Static file serving: <file> or /url2pdf-tools/<file> -> /opt/url2pdf/<file> qs = urllib.parse.urlparse(self.path).query
params = urllib.parse.parse_qs(qs)
job = params.get("job", [None])[0]
if not job:
self._json(400, {"error": "Missing job"})
return
sp = os.path.join(JOBS_DIR, job, "status.json")
if os.path.exists(sp):
with open(sp) as f:
self._json(200, json.load(f))
else:
self._json(200, {"status": "pending"})
return
# 2. /crawl/download?job=ID&format=md|pdf - download output
if self.path.startswith("/crawl/download"):
qs = urllib.parse.urlparse(self.path).query
params = urllib.parse.parse_qs(qs)
job = params.get("job", [None])[0]
fmt = params.get("format", ["pdf"])[0]
if not job:
self.send_error(400)
return
jdir = os.path.join(JOBS_DIR, job)
if fmt == "md":
fp = os.path.join(jdir, "output.md")
ct = "text/markdown"
else:
fp = os.path.join(jdir, "output.pdf")
ct = "application/pdf"
if not os.path.exists(fp):
self.send_error(404, "Not found")
return
with open(fp, "rb") as f:
data = f.read()
self.send_response(200)
self.send_header("Content-Type", ct)
self.send_header("Content-Disposition", f'attachment; filename="{job}.{fmt}"')
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
return
# 3. Static file serving: <file> or /url2pdf-tools/<file> -> /opt/url2pdf/<file>
# (nginx strips /url2pdf prefix; we accept both with and without it) # (nginx strips /url2pdf prefix; we accept both with and without it)
if self.path.startswith("/url2pdf-tools/"): if self.path.startswith("/url2pdf-tools/"):
rel = self.path[len("/url2pdf-tools/"):] rel = self.path[len("/url2pdf-tools/"):]
@@ -332,7 +375,6 @@ class Handler(BaseHTTPRequestHandler):
self.send_error(400, "Bad path") self.send_error(400, "Bad path")
return return
fp = os.path.join("/opt/url2pdf", safe) fp = os.path.join("/opt/url2pdf", safe)
fp = os.path.join("/opt/url2pdf", safe)
if os.path.isfile(fp): if os.path.isfile(fp):
import mimetypes import mimetypes
ct, _ = mimetypes.guess_type(fp) ct, _ = mimetypes.guess_type(fp)
@@ -346,63 +388,10 @@ class Handler(BaseHTTPRequestHandler):
self.end_headers() self.end_headers()
self.wfile.write(data) self.wfile.write(data)
return return
# file not found under /opt/url2pdf - fall through to API or HTML fallback # file not found under /opt/url2pdf
self.send_error(404, "Not found: " + fp) self.send_error(404, "Not found: " + fp)
return return
if self.path.startswith("/crawl/status"):
qs = urllib.parse.urlparse(self.path).query
params = urllib.parse.parse_qs(qs)
job = params.get("job", [None])[0]
if not job:
self._json(400, {"error": "Missing job"})
return
sp = os.path.join(JOBS_DIR, job, "status.json")
if os.path.exists(sp):
with open(sp) as f:
self._json(200, json.load(f))
else:
self._json(200, {"status": "pending"})
return
if self.path.startswith("/crawl/download"):
qs = urllib.parse.urlparse(self.path).query
params = urllib.parse.parse_qs(qs)
job = params.get("job", [None])[0]
fmt = params.get("format", ["pdf"])[0]
if not job:
self.send_error(400)
return
jdir = os.path.join(JOBS_DIR, job)
if fmt == "md":
fp = os.path.join(jdir, "output.md")
ct = "text/markdown"
else:
fp = os.path.join(jdir, "output.pdf")
ct = "application/pdf"
if not os.path.exists(fp):
self.send_error(404, "Not found")
return
with open(fp, "rb") as f:
data = f.read()
self.send_response(200)
self.send_header("Content-Type", ct)
self.send_header("Content-Disposition", f'attachment; filename="{job}.{fmt}"')
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
return
# Serve HTML
self.send_response(200)
self.send_header("Content-Type", "text/html")
self.end_headers()
self.wfile.write(HTML.encode())
def do_POST(self): def do_POST(self):
length = int(self.headers.get("Content-Length", 0)) length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(length) body = self.rfile.read(length)