]> git.kaiwu.me - njs.git/commitdiff
Modules: embed the common opaque prefix in QuickJS wrappers
authorDmitry Volyntsev <xeioex@nginx.com>
Tue, 10 Nov 2026 02:47:44 +0000 (18:47 -0800)
committerDmitry Volyntsev <xeioexception@gmail.com>
Wed, 11 Nov 2026 21:33:45 +0000 (13:33 -0800)
Context detach accesses the native pointer through a shared opaque
layout.  Embed that layout explicitly in HTTP and stream wrappers
instead of relying on unrelated first pointer fields.

This prepares shared lifetime invalidation without changing behavior.

nginx/ngx_http_js_module.c
nginx/ngx_stream_js_module.c

index 1ed20f10b90ab92df908213a91415070ae24b6cd..93a9422527ff279edc1dbab29ea87d662882397c 100644 (file)
@@ -159,10 +159,10 @@ typedef int (*njs_http_qjs_header_handler_t)(JSContext *cx,
 
 
 typedef struct {
-    ngx_http_request_t  *request;
-    JSValue              args;
-    JSValue              request_body;
-    JSValue              response_body;
+    ngx_js_opaque_t  opaque;
+    JSValue          args;
+    JSValue          request_body;
+    JSValue          response_body;
 } ngx_http_qjs_request_t;
 
 #endif
@@ -6173,7 +6173,7 @@ ngx_http_qjs_ext_args(JSContext *cx, JSValueConst this_val)
 
     NJS_CHB_CTX_INIT(&chain, cx);
 
-    r = req->request;
+    r = req->opaque.external;
 
     rc = ngx_http_qjs_query_string_decode(&chain, r->args.data, r->args.len);
     if (rc != NGX_OK) {
@@ -6530,7 +6530,8 @@ ngx_http_qjs_ext_periodic_variables(JSContext *cx,
      * Using lowest bit of the pointer to store the buffer type.
      */
     type = (type == NGX_JS_BUFFER) ? 1 : 0;
-    JS_SetOpaque(obj, (void *) ((uintptr_t) req->request | (uintptr_t) type));
+    JS_SetOpaque(obj, (void *) ((uintptr_t) req->opaque.external
+                              | (uintptr_t) type));
 
     return obj;
 }
@@ -6602,7 +6603,7 @@ ngx_http_qjs_ext_response_body(JSContext *cx, JSValueConst this_val, int type)
         req->response_body = JS_UNDEFINED;
     }
 
-    r = req->request;
+    r = req->opaque.external;
 
     b = r->out ? r->out->buf : NULL;
 
@@ -6656,7 +6657,7 @@ ngx_http_qjs_ext_request_body(JSContext *cx, JSValueConst this_val, int type)
         JS_FreeValue(cx, req->request_body);
     }
 
-    r = req->request;
+    r = req->opaque.external;
 
     if (r->request_body == NULL || r->request_body->bufs == NULL) {
         return JS_UNDEFINED;
@@ -6778,7 +6779,7 @@ ngx_http_qjs_ext_read_request_body(JSContext *cx, JSValueConst this_val,
         return JS_ThrowTypeError(cx, "\"this\" is not a request object");
     }
 
-    r = req->request;
+    r = req->opaque.external;
     ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);
 
     if (r->request_body) {
@@ -6931,7 +6932,7 @@ ngx_http_qjs_ext_read_request_form(JSContext *cx, JSValueConst this_val,
         return JS_EXCEPTION;
     }
 
-    r = req->request;
+    r = req->opaque.external;
     ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);
 
     if (r->request_body) {
@@ -9399,7 +9400,7 @@ ngx_http_qjs_request(JSValueConst val)
         return NULL;
     }
 
-    return req->request;
+    return req->opaque.external;
 }
 
 
@@ -9421,7 +9422,7 @@ ngx_http_qjs_request_make(JSContext *cx, ngx_int_t proto_id,
         return JS_ThrowOutOfMemory(cx);
     }
 
-    req->request = r;
+    req->opaque.external = r;
     req->args = JS_UNDEFINED;
     req->request_body = JS_UNDEFINED;
     req->response_body = JS_UNDEFINED;
index f544e108e9d0f36c1792d1a554967d026203c3f8..bd6e6a794744c219d2b7bfeaabc8ea2904518045 100644 (file)
@@ -87,8 +87,8 @@ typedef struct {
 } ngx_stream_qjs_event_t;
 
 typedef struct {
-    ngx_stream_session_t   *session;
-    JSValue                 callbacks[NGX_JS_EVENT_MAX];
+    ngx_js_opaque_t  opaque;
+    JSValue          callbacks[NGX_JS_EVENT_MAX];
 } ngx_stream_qjs_session_t;
 
 #endif
@@ -2287,6 +2287,7 @@ ngx_stream_qjs_ext_on(JSContext *cx, JSValueConst this_val, int argc,
     JSValueConst *argv)
 {
     ngx_stream_js_ctx_t           *ctx;
+    ngx_stream_session_t          *s;
     ngx_stream_qjs_session_t      *ses;
     const ngx_stream_qjs_event_t  *e;
 
@@ -2295,9 +2296,10 @@ ngx_stream_qjs_ext_on(JSContext *cx, JSValueConst this_val, int argc,
         return JS_ThrowTypeError(cx, "\"this\" is not a session object");
     }
 
-    ctx = ngx_stream_get_module_ctx(ses->session, ngx_stream_js_module);
+    s = ses->opaque.external;
+    ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
 
-    e = ngx_stream_qjs_event(ses->session, cx, argv[0]);
+    e = ngx_stream_qjs_event(s, cx, argv[0]);
     if (e == NULL) {
         return JS_EXCEPTION;
     }
@@ -2365,7 +2367,8 @@ ngx_stream_qjs_ext_periodic_variables(JSContext *cx,
      * Using lowest bit of the pointer to store the buffer type.
      */
     type = (type == NGX_JS_BUFFER) ? 1 : 0;
-    JS_SetOpaque(obj, (void *) ((uintptr_t) ses->session | (uintptr_t) type));
+    JS_SetOpaque(obj, (void *) ((uintptr_t) ses->opaque.external
+                              | (uintptr_t) type));
 
     return obj;
 }
@@ -3015,7 +3018,7 @@ ngx_stream_qjs_session(JSValueConst val)
         return NULL;
     }
 
-    return ses->session;
+    return ses->opaque.external;
 }
 
 
@@ -3038,7 +3041,7 @@ ngx_stream_qjs_session_make(JSContext *cx, ngx_int_t proto_id,
         return JS_ThrowOutOfMemory(cx);
     }
 
-    ses->session = s;
+    ses->opaque.external = s;
 
     for (i = 0; i < NGX_JS_EVENT_MAX; i++) {
         ses->callbacks[i] = JS_UNDEFINED;