Headers set before an uncommitted panic survive onto the recovered 500, including Set-Cookie #193
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found by the independent review of #189 and measured there. NOT milestoned 1.0.0, and filed as a question rather than an assertion of a defect — see below.
When a handler sets response headers and then panics before committing the response, the recover middleware writes a 500 via
http.Error, which clears onlyContent-LengthandContent-Type. Everything else the handler already put in the header map survives onto the 500. That includesSet-CookieandLocation.The concrete shape worth thinking about: a handler that establishes a session — writes
Set-Cookie— and then panics before finishing. The client receives a 500 and a valid session cookie. The server-side effects of that half-finished request are whatever they were; the client is left holding credentials issued by a request that visibly failed.Locationhas a milder version of the same problem: a 500 carrying a redirect target.Why this is a question and not a filed defect
This is exactly what chi v5's
Recovererdoes, and it is ordinary Go practice —http.Errorhas never cleared the header map, and almost nobody clears it manually. Changing it means deviating from the idiom, and there is a real argument for the current behaviour: a handler that setsSet-Cookieearly and panics late may have committed the session server-side already, in which case dropping the cookie strands it.So the options are genuinely open:
Set-Cookie, on the argument that credentials specifically should never ride out on a failed response, and leave everything else alone.Recommendation: option 3, if anything is done at all. It addresses the case with security consequences and leaves the idiomatic behaviour otherwise intact. But this is a judgement call about a deviation from standard Go practice, so it should be decided rather than assumed.
Note this is pre-existing in spirit: before #189, a panicking request had its connection dropped outright, so the question could not arise. That PR makes panics answerable, which is what surfaces it. It is not a regression that PR introduced — a dropped connection was strictly worse.
Definition of done
Depends entirely on which option is chosen. If 2 or 3:
Set-CookieandLocationand then panics uncommitted, asserting exactly which survive.WriteHeader.http.Error's default and the next reader will otherwise assume it is a bug.If option 1: close this issue with the reason, and say so in the middleware doc comment so it is not rediscovered.
Implementation requirements
next, PR based onnext, single commit, title ending(closes #N).TODO.md(see #112).make bootstrapin a fresh clone before gating. Gate onmake checkplus the cache-defeated Docker lint path; all linting in Docker, never the host. Clean up every container and image; never prune.