]> git.kaiwu.me - njs.git/commitdiff
QuickJS: add runtime-owned byte storage helpers
authorDmitry Volyntsev <xeioex@nginx.com>
Tue, 10 Nov 2026 01:42:56 +0000 (17:42 -0800)
committerDmitry Volyntsev <xeioexception@gmail.com>
Wed, 11 Nov 2026 21:33:45 +0000 (13:33 -0800)
Fetch ownership needs native copies and chain allocations that do not
depend on request pools or a surviving JSContext.  Provide common
helpers for these operations while preserving nginx value conversion
semantics.

nginx/ngx_js.c
nginx/ngx_js.h
src/qjs.c
src/qjs.h

index 5101d92afe7d7dba943afcdde08bce639ac27b76..a85251b988eb6f065eb4db80174209c8eb6ce948 100644 (file)
@@ -1769,6 +1769,69 @@ ngx_qjs_header_value(JSContext *cx, ngx_pool_t *pool, JSValueConst val,
 }
 
 
+ngx_int_t
+ngx_qjs_bytes_copy(JSContext *cx, ngx_str_t *dst, const ngx_str_t *src)
+{
+    dst->data = js_malloc(cx, njs_max(src->len, 1));
+    if (dst->data == NULL) {
+        return NGX_ERROR;
+    }
+
+    dst->len = src->len;
+
+    if (src->len != 0) {
+        ngx_memcpy(dst->data, src->data, src->len);
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_qjs_value_bytes_copy(JSContext *cx, JSValueConst value, ngx_str_t *str)
+{
+    size_t       offset, length;
+    JSValue      buffer;
+    ngx_int_t    rc;
+    ngx_str_t    source;
+    const char  *p;
+
+    if (JS_IsNullOrUndefined(value)) {
+        ngx_str_null(&source);
+
+        return ngx_qjs_bytes_copy(cx, str, &source);
+    }
+
+    if (!JS_IsString(value)) {
+        buffer = JS_GetTypedArrayBuffer(cx, value, &offset, &length, NULL);
+        if (!JS_IsException(buffer)) {
+            source.data = JS_GetArrayBuffer(cx, &source.len, buffer);
+            if (source.data != NULL) {
+                source.data += offset;
+                source.len = length;
+                rc = ngx_qjs_bytes_copy(cx, str, &source);
+                JS_FreeValue(cx, buffer);
+
+                return rc;
+            }
+
+            JS_FreeValue(cx, buffer);
+        }
+    }
+
+    p = JS_ToCStringLen(cx, &source.len, value);
+    if (p == NULL) {
+        return NGX_ERROR;
+    }
+
+    source.data = (u_char *) p;
+    rc = ngx_qjs_bytes_copy(cx, str, &source);
+    JS_FreeCString(cx, p);
+
+    return rc;
+}
+
+
 static void
 ngx_qjs_timer_handler(ngx_event_t *ev)
 {
index ec1f536ab1033a03306185ec823ce17ea65c5732..7d5cd4e050fed673ecd502e0a6963c69c5f501ca 100644 (file)
@@ -404,6 +404,10 @@ ngx_int_t ngx_qjs_log_exception(ngx_engine_t *e, ngx_log_t *log,
 ngx_int_t ngx_qjs_integer(JSContext *cx, JSValueConst val, ngx_int_t *n);
 ngx_int_t ngx_qjs_string(JSContext *cx, ngx_pool_t *pool, JSValueConst val,
     ngx_str_t *dst);
+ngx_int_t ngx_qjs_bytes_copy(JSContext *cx, ngx_str_t *dst,
+    const ngx_str_t *src);
+ngx_int_t ngx_qjs_value_bytes_copy(JSContext *cx, JSValueConst value,
+    ngx_str_t *str);
 ngx_int_t ngx_qjs_header_value(JSContext *cx, ngx_pool_t *pool,
     JSValueConst val, ngx_str_t *dst);
 
index 99fdd9442d0853498d6088010a72b881b7ec3513..4c5e971ab0656da4fed1aa911e61e2d710d79e4a 100644 (file)
--- a/src/qjs.c
+++ b/src/qjs.c
@@ -338,6 +338,20 @@ qjs_chb_ctx_free(void *ctx, void *p)
 }
 
 
+void *
+qjs_chb_rt_alloc(void *rt, size_t size)
+{
+    return js_malloc_rt(rt, size);
+}
+
+
+void
+qjs_chb_rt_free(void *rt, void *p)
+{
+    js_free_rt(rt, p);
+}
+
+
 JSValue
 qjs_call_exit_hook(JSContext *ctx)
 {
index 41df904675a7ae9df354f396e2cc3c1333c2965a..3b89bb71e2285003a6e673ed52bf0830771844dc 100644 (file)
--- a/src/qjs.h
+++ b/src/qjs.h
@@ -63,6 +63,8 @@ JSContext *qjs_new_context(JSRuntime *rt, qjs_module_t **addons);
 JSValue qjs_call_exit_hook(JSContext *ctx);
 void *qjs_chb_ctx_alloc(void *ctx, size_t size);
 void qjs_chb_ctx_free(void *ctx, void *p);
+void *qjs_chb_rt_alloc(void *rt, size_t size);
+void qjs_chb_rt_free(void *rt, void *p);
 
 
 JSValue qjs_new_uint8_array(JSContext *ctx, int argc, JSValueConst *argv);