httputil.ReverseProxy pools backend connections via sharedTransport but
has no built-in retry when it picks a pooled connection the backend has
just closed - an inherent HTTP/1.1 keep-alive race. Reproduced this
100% of the time against the LMS backend (lms.noroutes.net) right after
its OIDC login callback: the client got a 502 on the very next request,
with zero trace of that request in LMS's own logs. LMS's side showed
"wthttp/async: handleReadBody(): while waiting for disconnect, received
unexpected data, closing" at the same moment - Wt's lightweight built-in
httpd closing idle connections more eagerly than Go's pool expects.
Retry once, only for idempotent bodyless requests (GET/HEAD/OPTIONS),
directly against sharedTransport from within ErrorHandler - standard
practice for reverse proxies (nginx's proxy_next_upstream, Traefik's
retry middleware). Safe because ReverseProxy hasn't written any response
bytes yet when ErrorHandler runs.