From: Dmitry Volyntsev Date: Fri, 30 Oct 2026 03:16:10 +0000 (-0700) Subject: Fetch: free QuickJS response body chain after reading X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=f7d70ccdaafcdb35c3ff6cfa3e2587955b54d12e;p=njs.git Fetch: free QuickJS response body chain after reading Previously, Response.text(), json() and arrayBuffer() joined the body chain into a new block of the engine pool and left both the chain nodes and the joined copy in the pool. The memory was released only with the engine, so with js_context_reuse every response body read accumulated in the pool, unaccounted by the context reuse memory check. Now, the chain is destroyed after the body is read. For text() the string is created with qjs_string_create_chb(), and for json() the joined copy is freed after parsing. The issue was introduced in b7f76b71 (0.9.1). --- diff --git a/nginx/ngx_qjs_fetch.c b/nginx/ngx_qjs_fetch.c index d4b2d536..be3f299b 100644 --- a/nginx/ngx_qjs_fetch.c +++ b/nginx/ngx_qjs_fetch.c @@ -2316,21 +2316,21 @@ ngx_qjs_ext_fetch_response_body(JSContext *cx, JSValueConst this_val, response->body_used = 1; switch (magic) { - case NGX_JS_BODY_ARRAY_BUFFER: case NGX_JS_BODY_TEXT: + result = qjs_string_create_chb(cx, &response->chain); + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + break; + + case NGX_JS_BODY_ARRAY_BUFFER: ret = njs_chb_join(&response->chain, &string); if (ret != NJS_OK) { return JS_ThrowOutOfMemory(cx); } - if (magic == NGX_JS_BODY_TEXT) { - result = qjs_string_create(cx, string.start, string.length); - if (JS_IsException(result)) { - return JS_ThrowOutOfMemory(cx); - } - - break; - } + njs_chb_destroy(&response->chain); /* * string.start is allocated from e->pool @@ -2355,9 +2355,9 @@ ngx_qjs_ext_fetch_response_body(JSContext *cx, JSValueConst this_val, result = JS_ParseJSON(cx, (char *) string.start, string.length - 1, ""); - if (JS_IsException(result)) { - break; - } + + njs_chb_destroy(&response->chain); + response->chain.free(response->chain.pool, string.start); } return qjs_promise_result(cx, result);