From aa0f3e501bffe8736fe1ada80d68a48b57432d00 Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Fri, 9 Jan 2026 18:08:56 -0800 Subject: [PATCH] QuickJS: fixed js_body_filter with multiple chunks. Previously, last_key atoms was freed too early. Also, js_body_filter.t is modified to ensure js_body_filter sees multiple data chains to catch the issue. --- nginx/ngx_http_js_module.c | 6 ++++- nginx/t/js_body_filter.t | 47 +++++++++++++++----------------------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/nginx/ngx_http_js_module.c b/nginx/ngx_http_js_module.c index 6bc2bca3..d7bcd78f 100644 --- a/nginx/ngx_http_js_module.c +++ b/nginx/ngx_http_js_module.c @@ -7525,11 +7525,11 @@ ngx_http_qjs_body_filter(ngx_http_request_t *r, ngx_http_js_loc_conf_t *jlcf, rc = ctx->engine->call((ngx_js_ctx_t *) ctx, &jlcf->body_filter, (njs_opaque_value_t *) &arguments[0], 3); - JS_FreeAtom(cx, last_key); JS_FreeValue(cx, arguments[1]); JS_FreeValue(cx, arguments[2]); if (rc == NGX_ERROR) { + JS_FreeAtom(cx, last_key); return NGX_ERROR; } @@ -7537,6 +7537,7 @@ ngx_http_qjs_body_filter(ngx_http_request_t *r, ngx_http_js_loc_conf_t *jlcf, ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "async operation inside \"%V\" body filter", &jlcf->body_filter); + JS_FreeAtom(cx, last_key); return NGX_ERROR; } @@ -7545,6 +7546,7 @@ ngx_http_qjs_body_filter(ngx_http_request_t *r, ngx_http_js_loc_conf_t *jlcf, } else { cl = ngx_alloc_chain_link(c->pool); if (cl == NULL) { + JS_FreeAtom(cx, last_key); return NGX_ERROR; } @@ -7557,6 +7559,8 @@ ngx_http_qjs_body_filter(ngx_http_request_t *r, ngx_http_js_loc_conf_t *jlcf, in = in->next; } + JS_FreeAtom(cx, last_key); + return NGX_OK; } diff --git a/nginx/t/js_body_filter.t b/nginx/t/js_body_filter.t index 6bd6bddb..afe77bc3 100644 --- a/nginx/t/js_body_filter.t +++ b/nginx/t/js_body_filter.t @@ -156,9 +156,24 @@ like(http_get('/prepend'), qr/XXXAAABBCDDDD$/, 'prepend'); ############################################################################### +sub send_chunked { + my ($client, @chunks) = @_; + + print $client + "HTTP/1.1 200 OK" . CRLF . + "Transfer-Encoding: chunked" . CRLF . + "Connection: close" . CRLF . + CRLF; + + for my $chunk (@chunks) { + printf $client "%x\r\n%s\r\n", length($chunk), $chunk; + } + + print $client "0\r\n\r\n"; +} + sub http_daemon { my $port = shift; - my $delay = shift || 0.05; my $server = IO::Socket::INET->new( Proto => 'tcp', @@ -189,34 +204,10 @@ sub http_daemon { log2c("(new connection $client $uri)"); if ($uri eq '/source') { - print $client - "HTTP/1.1 200 OK" . CRLF . - "Content-Length: 10" . CRLF . - "Connection: close" . CRLF . - CRLF; - - print $client "AAA"; - select undef, undef, undef, $delay; - print $client "BB"; - select undef, undef, undef, $delay; - print $client "C"; - select undef, undef, undef, $delay; - print $client "DDDD"; - - } elsif ($uri eq '/nonutf8_source') { - print $client - "HTTP/1.1 200 OK" . CRLF . - "Content-Length: 6" . CRLF . - "Connection: close" . CRLF . - CRLF; + send_chunked($client, "AAA", "BB", "C", "DDDD"); - print $client "\xaa\xaa"; - select undef, undef, undef, $delay; - print $client "\xbb"; - select undef, undef, undef, $delay; - print $client "\xcc"; - select undef, undef, undef, $delay; - print $client "\xdd\xdd"; + } elsif ($uri eq '/nonutf8_source') { + send_chunked($client, "\xaa\xaa", "\xbb", "\xcc", "\xdd\xdd"); } else { print $client -- 2.47.3