From 3839690b77e29882288e4b3c66d2b5f0a9d778b8 Mon Sep 17 00:00:00 2001 From: tzssangglass Date: Tue, 4 Nov 2025 15:02:28 +0800 Subject: [PATCH] fix: wake parent request when HTTP/2 subrequest finishes with error When a client disconnects during an HTTP/2 subrequest (e.g., while ngx.sleep() is yielding), the subrequest fails to wake up its parent request, causing the parent's Lua coroutine to hang indefinitely. Root cause: HTTP/2 sets c->error=1 immediately on client disconnect, triggering the error path in ngx_http_finalize_request(). This path calls ngx_http_terminate_request(), which clears the posted_requests queue before the parent can be processed. Solution: In ngx_http_finalize_request(), when a subrequest completes with c->error set, manually update subrequest state and wake the parent request, then return immediately to avoid ngx_http_terminate_request(). This fix ensures the parent request can process the subrequest response even when the client connection is closed, which is critical for OpenResty's async subrequest mechanism with ngx.location.capture(). Signed-off-by: tzssangglass --- ...inx-1.27.1-http2_subreq_error_wakeup.patch | 20 +++++++++++++++++++ ...inx-1.29.2-http2_subreq_error_wakeup.patch | 20 +++++++++++++++++++ util/mirror-tarballs | 6 ++++++ 3 files changed, 46 insertions(+) create mode 100644 patches/nginx/1.27.1/nginx-1.27.1-http2_subreq_error_wakeup.patch create mode 100644 patches/nginx/1.29.2/nginx-1.29.2-http2_subreq_error_wakeup.patch diff --git a/patches/nginx/1.27.1/nginx-1.27.1-http2_subreq_error_wakeup.patch b/patches/nginx/1.27.1/nginx-1.27.1-http2_subreq_error_wakeup.patch new file mode 100644 index 0000000..f6ded5e --- /dev/null +++ b/patches/nginx/1.27.1/nginx-1.27.1-http2_subreq_error_wakeup.patch @@ -0,0 +1,20 @@ +diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c +index 9593b7f..dbc23ff 100644 +--- a/src/http/ngx_http_request.c ++++ b/src/http/ngx_http_request.c +@@ -2560,8 +2560,15 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) + return; + } + ++#if (NGX_HTTP_V2) ++ if (r->http_version < NGX_HTTP_VERSION_20 || r == r->main) { ++ ngx_http_terminate_request(r, rc); ++ return; ++ } ++#else + ngx_http_terminate_request(r, rc); + return; ++#endif + } + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE diff --git a/patches/nginx/1.29.2/nginx-1.29.2-http2_subreq_error_wakeup.patch b/patches/nginx/1.29.2/nginx-1.29.2-http2_subreq_error_wakeup.patch new file mode 100644 index 0000000..d20df8c --- /dev/null +++ b/patches/nginx/1.29.2/nginx-1.29.2-http2_subreq_error_wakeup.patch @@ -0,0 +1,20 @@ +diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c +index 16d79c4..760e0e5 100644 +--- a/src/http/ngx_http_request.c ++++ b/src/http/ngx_http_request.c +@@ -2559,8 +2559,15 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) + return; + } + ++#if (NGX_HTTP_V2) ++ if (r->http_version < NGX_HTTP_VERSION_20 || r == r->main) { ++ ngx_http_terminate_request(r, rc); ++ return; ++ } ++#else + ngx_http_terminate_request(r, rc); + return; ++#endif + } + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE diff --git a/util/mirror-tarballs b/util/mirror-tarballs index 4bce35b..33ca30e 100755 --- a/util/mirror-tarballs +++ b/util/mirror-tarballs @@ -576,6 +576,12 @@ if [ "$answer" = "Y" ]; then patch -p1 < $root/patches/nginx/$main_ver/nginx-$main_ver-quic_ssl_lua_yield.patch || exit 1 fi +answer=`$root/util/ver-ge "$main_ver" 1.27.1` +if [ "$answer" = "Y" ]; then + echo "$info_txt applying nginx-$main_ver-http2_subreq_error_wakeup patch for nginx" + patch -p1 < $root/patches/nginx/$main_ver/nginx-$main_ver-http2_subreq_error_wakeup.patch || exit 1 +fi + cp $root/html/index.html docs/html/ || exit 1 cp $root/html/50x.html docs/html/ || exit 1