fix(http): return 401 (not 500) on expired/rejected session

Authenticate/RequireCSRF write a 401 then raise ESessionRejected; when it
reached the dispatcher catch-all, the generic `on E: Exception` overwrote it
with a 500. Added `on ESessionRejected do Exit` before the generic clause in
both dispatchers (GET + Other) — one place, covers every handler whether or
not it wraps Authenticate. Root cause, not per-handler patch.

ponytail: runtime check only (expired token → 401) — no Delphi unit harness.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-07-09 21:42:08 +01:00
parent a980af1e94
commit b023eab1f4
2 changed files with 6 additions and 2 deletions
+5 -1
View File
@@ -15,7 +15,7 @@ uses
Winapi.Windows,
IdHTTPServer, IdContext, IdCustomHTTPServer, IdSocketHandle, IdTCPConnection,
PM.Router, PM.JSON, PM.Database, PM.StaticFiles, PM.EmbeddedAssets,
PM.Crypto, PM.ProcessLockdown;
PM.Crypto, PM.ProcessLockdown, PM.Session;
type
TLogProc = reference to procedure(const AMsg: string);
@@ -284,6 +284,9 @@ begin
if Assigned(StaticServer) and StaticServer.TryServe(ARequest, AResponse) then Exit;
TJSONHelper.SendError(AResponse, 404, 'Not found');
except
// Authenticate/RequireCSRF already wrote the 401 — don't overwrite it
// with a 500. Any handler that doesn't wrap Authenticate lands here.
on ESessionRejected do Exit;
on E: Exception do
begin
Log('ERROR ' + ARequest.Command + ' ' + ARequest.Document + ' : ' + E.Message);
@@ -308,6 +311,7 @@ begin
if not Router.DispatchRequest(ARequest, AResponse) then
TJSONHelper.SendError(AResponse, 404, 'Not found');
except
on ESessionRejected do Exit; // 401 already sent — keep it, don't 500
on E: Exception do
begin
Log('ERROR ' + ARequest.Command + ' ' + ARequest.Document + ' : ' + E.Message);