HTTP: fix use-after-free in r.subrequest() on premature client close
Previously, since njs subrequests are background subrequests that nginx
does not wake on completion, the handlers ngx_http_js_subrequest_done()
and ngx_http_qjs_subrequest_done() woke the parent request themselves,
synchronously, via ngx_http_run_posted_requests(), from within
ngx_http_finalize_request() of the subrequest. When the downstream client
had already aborted, that re-entered request processing and freed the
request pool shared by all subrequests before finalization unwound; the
freed subrequest was then dereferenced in ngx_http_post_action()
(heap-use-after-free).
This handler is unlike the other event completions. Timers and
ngx.fetch() run their callbacks from their own event handlers, where
draining posted requests is safe; the subrequest completion handler runs
while the subrequest is still being finalized, where it is not. The wake
helper is shared, but this caller must be treated differently.
Before 0.8.1 the parent was woken by posting the request only;
0ee01840
(0.8.1) added a synchronous ngx_http_run_posted_requests(), which let an
inner run free the request while an outer one was still unwinding.
d34fcb0 (0.8.5) dropped the synchronous run and posted the connection
write event instead, fixing a nested-run use-after-free when a subrequest
callback threw; but that lost the wake when the handler runs as a
subrequest of another module (lua), whose connection write handler is not
ours.
75d6b61 (0.9.5) reverted to posting the request plus the
synchronous run to fix the lost wake, reintroducing the use-after-free,
now seen on a premature client close.
The fix is to post the parent request without running posted requests in
place, as it was done before 0.8.1.
This closes #1077 issue on Github.