[njs] Modules: extending allowed context for js directives.

Dmitry Volyntsev xeioex at nginx.com
Wed Aug 3 05:16:04 UTC 2022


details:   https://hg.nginx.org/njs/rev/648a8092c05a
branches:  
changeset: 1921:648a8092c05a
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue Aug 02 20:45:17 2022 -0700
description:
Modules: extending allowed context for js directives.

HTTP: js_import, js_path, js_set and js_var are allowed in server and
location contexts. js_content, js_body_filter and js_header_filter
are allowed in 'if' context.
Stream: js_import, js_path, js_set and js_var are allowed in server context.

This closes #566 issue on Github.

diffstat:

 nginx/ngx_http_js_module.c   |  293 +++++++++++++++++++++++++++---------------
 nginx/ngx_stream_js_module.c |  281 ++++++++++++++++++++++++++--------------
 2 files changed, 372 insertions(+), 202 deletions(-)

diffs (truncated from 1008 to 1000 lines):

diff -r 076cdf8a1ced -r 648a8092c05a nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c	Tue Aug 02 20:42:04 2022 -0700
+++ b/nginx/ngx_http_js_module.c	Tue Aug 02 20:45:17 2022 -0700
@@ -21,10 +21,7 @@ typedef struct {
     njs_vm_t              *vm;
     ngx_array_t           *imports;
     ngx_array_t           *paths;
-} ngx_http_js_main_conf_t;
-
-
-typedef struct {
+
     ngx_str_t              content;
     ngx_str_t              header_filter;
     ngx_str_t              body_filter;
@@ -271,8 +268,10 @@ static char *ngx_http_js_content(ngx_con
     void *conf);
 static char *ngx_http_js_body_filter_set(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
-static void *ngx_http_js_create_main_conf(ngx_conf_t *cf);
-static char *ngx_http_js_init_main_conf(ngx_conf_t *cf, void *conf);
+static ngx_int_t ngx_http_js_merge_vm(ngx_conf_t *cf,
+    ngx_http_js_loc_conf_t *conf, ngx_http_js_loc_conf_t *prev);
+static ngx_int_t ngx_http_js_init_conf_vm(ngx_conf_t *cf,
+    ngx_http_js_loc_conf_t *conf);
 static void *ngx_http_js_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_js_merge_loc_conf(ngx_conf_t *cf, void *parent,
     void *child);
@@ -298,49 +297,49 @@ static ngx_conf_bitmask_t  ngx_http_js_s
 static ngx_command_t  ngx_http_js_commands[] = {
 
     { ngx_string("js_import"),
-      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE13,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13,
       ngx_http_js_import,
-      NGX_HTTP_MAIN_CONF_OFFSET,
+      NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
 
     { ngx_string("js_path"),
-      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_array_slot,
-      NGX_HTTP_MAIN_CONF_OFFSET,
-      offsetof(ngx_http_js_main_conf_t, paths),
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_js_loc_conf_t, paths),
       NULL },
 
     { ngx_string("js_set"),
-      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
       ngx_http_js_set,
       0,
       0,
       NULL },
 
     { ngx_string("js_var"),
-      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
       ngx_http_js_var,
       0,
       0,
       NULL },
 
     { ngx_string("js_content"),
-      NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
       ngx_http_js_content,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
 
     { ngx_string("js_header_filter"),
-      NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_js_loc_conf_t, header_filter),
       NULL },
 
     { ngx_string("js_body_filter"),
-      NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE12,
+      NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE12,
       ngx_http_js_body_filter_set,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -414,8 +413,8 @@ static ngx_http_module_t  ngx_http_js_mo
     NULL,                          /* preconfiguration */
     ngx_http_js_init,              /* postconfiguration */
 
-    ngx_http_js_create_main_conf,  /* create main configuration */
-    ngx_http_js_init_main_conf,    /* init main configuration */
+    NULL,                          /* create main configuration */
+    NULL,                          /* init main configuration */
 
     NULL,                          /* create server configuration */
     NULL,                          /* merge server configuration */
@@ -1212,14 +1211,14 @@ ngx_http_js_variable_var(ngx_http_reques
 static ngx_int_t
 ngx_http_js_init_vm(ngx_http_request_t *r)
 {
-    njs_int_t                 rc;
-    ngx_str_t                 exception;
-    ngx_http_js_ctx_t        *ctx;
-    ngx_pool_cleanup_t       *cln;
-    ngx_http_js_main_conf_t  *jmcf;
-
-    jmcf = ngx_http_get_module_main_conf(r, ngx_http_js_module);
-    if (jmcf->vm == NULL) {
+    njs_int_t                rc;
+    ngx_str_t                exception;
+    ngx_http_js_ctx_t       *ctx;
+    ngx_pool_cleanup_t      *cln;
+    ngx_http_js_loc_conf_t  *jlcf;
+
+    jlcf = ngx_http_get_module_loc_conf(r, ngx_http_js_module);
+    if (jlcf->vm == NULL) {
         return NGX_DECLINED;
     }
 
@@ -1240,7 +1239,7 @@ ngx_http_js_init_vm(ngx_http_request_t *
         return NGX_OK;
     }
 
-    ctx->vm = njs_vm_clone(jmcf->vm, r);
+    ctx->vm = njs_vm_clone(jlcf->vm, r);
     if (ctx->vm == NULL) {
         return NGX_ERROR;
     }
@@ -4150,11 +4149,116 @@ ngx_http_js_handle_event(ngx_http_reques
 }
 
 
-static char *
-ngx_http_js_init_main_conf(ngx_conf_t *cf, void *conf)
+static ngx_int_t
+ngx_http_js_merge_vm(ngx_conf_t *cf, ngx_http_js_loc_conf_t *conf,
+    ngx_http_js_loc_conf_t *prev)
 {
-    ngx_http_js_main_conf_t *jmcf = conf;
-
+    ngx_str_t             *path, *s;
+    ngx_uint_t             i;
+    ngx_array_t           *imports, *paths;
+    ngx_http_js_import_t  *import, *pi;
+
+    if (prev->imports != NGX_CONF_UNSET_PTR && prev->vm == NULL) {
+        if (ngx_http_js_init_conf_vm(cf, prev) != NGX_OK) {
+            return NGX_ERROR;
+        }
+    }
+
+    if (conf->imports == NGX_CONF_UNSET_PTR
+        && conf->paths == NGX_CONF_UNSET_PTR)
+    {
+        if (prev->vm != NULL) {
+            conf->imports = prev->imports;
+            conf->paths = prev->paths;
+            conf->vm = prev->vm;
+            return NGX_OK;
+        }
+    }
+
+    if (prev->imports != NGX_CONF_UNSET_PTR) {
+        if (conf->imports == NGX_CONF_UNSET_PTR) {
+            conf->imports = prev->imports;
+
+        } else {
+            imports = ngx_array_create(cf->pool, 4,
+                                       sizeof(ngx_http_js_import_t));
+            if (imports == NULL) {
+                return NGX_ERROR;
+            }
+
+            pi = prev->imports->elts;
+
+            for (i = 0; i < prev->imports->nelts; i++) {
+                import = ngx_array_push(imports);
+                if (import == NULL) {
+                    return NGX_ERROR;
+                }
+
+                *import = pi[i];
+            }
+
+            pi = conf->imports->elts;
+
+            for (i = 0; i < conf->imports->nelts; i++) {
+                import = ngx_array_push(imports);
+                if (import == NULL) {
+                    return NGX_ERROR;
+                }
+
+                *import = pi[i];
+            }
+
+            conf->imports = imports;
+        }
+    }
+
+    if (prev->paths != NGX_CONF_UNSET_PTR) {
+        if (conf->paths == NGX_CONF_UNSET_PTR) {
+            conf->paths = prev->paths;
+
+        } else {
+            paths = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
+            if (paths == NULL) {
+                return NGX_ERROR;
+            }
+
+            s = prev->imports->elts;
+
+            for (i = 0; i < prev->paths->nelts; i++) {
+                path = ngx_array_push(paths);
+                if (path == NULL) {
+                    return NGX_ERROR;
+                }
+
+                *path = s[i];
+            }
+
+            s = conf->imports->elts;
+
+            for (i = 0; i < conf->paths->nelts; i++) {
+                path = ngx_array_push(paths);
+                if (path == NULL) {
+                    return NGX_ERROR;
+                }
+
+                *path = s[i];
+            }
+
+            conf->paths = paths;
+        }
+    }
+
+    if (conf->imports == NGX_CONF_UNSET_PTR) {
+        return NGX_OK;
+    }
+
+    return ngx_http_js_init_conf_vm(cf, conf);
+}
+
+
+static ngx_int_t
+ngx_http_js_init_conf_vm(ngx_conf_t *cf, ngx_http_js_loc_conf_t *conf)
+{
     size_t                 size;
     u_char                *start, *end, *p;
     ngx_str_t             *m, file;
@@ -4170,14 +4274,10 @@ ngx_http_js_init_main_conf(ngx_conf_t *c
     static const njs_str_t line_number_key = njs_str("lineNumber");
     static const njs_str_t file_name_key = njs_str("fileName");
 
-    if (jmcf->imports == NGX_CONF_UNSET_PTR) {
-        return NGX_CONF_OK;
-    }
-
     size = 0;
 
-    import = jmcf->imports->elts;
-    for (i = 0; i < jmcf->imports->nelts; i++) {
+    import = conf->imports->elts;
+    for (i = 0; i < conf->imports->nelts; i++) {
 
         /* import <name> from '<path>'; globalThis.<name> = <name>; */
 
@@ -4188,12 +4288,12 @@ ngx_http_js_init_main_conf(ngx_conf_t *c
 
     start = ngx_pnalloc(cf->pool, size);
     if (start == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     p = start;
-    import = jmcf->imports->elts;
-    for (i = 0; i < jmcf->imports->nelts; i++) {
+    import = conf->imports->elts;
+    for (i = 0; i < conf->imports->nelts; i++) {
 
         /* import <name> from '<path>'; globalThis.<name> = <name>; */
 
@@ -4223,103 +4323,103 @@ ngx_http_js_init_main_conf(ngx_conf_t *c
     options.file.start = file.data;
     options.file.length = file.len;
 
-    jmcf->vm = njs_vm_create(&options);
-    if (jmcf->vm == NULL) {
+    conf->vm = njs_vm_create(&options);
+    if (conf->vm == NULL) {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "failed to create js VM");
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     cln = ngx_pool_cleanup_add(cf->pool, 0);
     if (cln == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     cln->handler = ngx_http_js_cleanup_vm;
-    cln->data = jmcf->vm;
+    cln->data = conf->vm;
 
     path.start = ngx_cycle->conf_prefix.data;
     path.length = ngx_cycle->conf_prefix.len;
 
-    rc = njs_vm_add_path(jmcf->vm, &path);
+    rc = njs_vm_add_path(conf->vm, &path);
     if (rc != NJS_OK) {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "failed to add \"js_path\"");
-        return NGX_CONF_ERROR;
-    }
-
-    if (jmcf->paths != NGX_CONF_UNSET_PTR) {
-        m = jmcf->paths->elts;
-
-        for (i = 0; i < jmcf->paths->nelts; i++) {
+        return NGX_ERROR;
+    }
+
+    if (conf->paths != NGX_CONF_UNSET_PTR) {
+        m = conf->paths->elts;
+
+        for (i = 0; i < conf->paths->nelts; i++) {
             if (ngx_conf_full_name(cf->cycle, &m[i], 1) != NGX_OK) {
-                return NGX_CONF_ERROR;
+                return NGX_ERROR;
             }
 
             path.start = m[i].data;
             path.length = m[i].len;
 
-            rc = njs_vm_add_path(jmcf->vm, &path);
+            rc = njs_vm_add_path(conf->vm, &path);
             if (rc != NJS_OK) {
                 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                               "failed to add \"js_path\"");
-                return NGX_CONF_ERROR;
+                return NGX_ERROR;
             }
         }
     }
 
-    ngx_http_js_request_proto_id = njs_vm_external_prototype(jmcf->vm,
+    ngx_http_js_request_proto_id = njs_vm_external_prototype(conf->vm,
                                            ngx_http_js_ext_request,
                                            njs_nitems(ngx_http_js_ext_request));
     if (ngx_http_js_request_proto_id < 0) {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                       "failed to add js request proto");
-        return NGX_CONF_ERROR;
-    }
-
-    rc = ngx_js_core_init(jmcf->vm, cf->log);
+        return NGX_ERROR;
+    }
+
+    rc = ngx_js_core_init(conf->vm, cf->log);
     if (njs_slow_path(rc != NJS_OK)) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     end = start + size;
 
-    rc = njs_vm_compile(jmcf->vm, &start, end);
+    rc = njs_vm_compile(conf->vm, &start, end);
 
     if (rc != NJS_OK) {
-        njs_value_assign(&exception, njs_vm_retval(jmcf->vm));
-        njs_vm_retval_string(jmcf->vm, &text);
-
-        value = njs_vm_object_prop(jmcf->vm, njs_value_arg(&exception),
+        njs_value_assign(&exception, njs_vm_retval(conf->vm));
+        njs_vm_retval_string(conf->vm, &text);
+
+        value = njs_vm_object_prop(conf->vm, njs_value_arg(&exception),
                                    &file_name_key, &lvalue);
         if (value == NULL) {
-            value = njs_vm_object_prop(jmcf->vm, njs_value_arg(&exception),
+            value = njs_vm_object_prop(conf->vm, njs_value_arg(&exception),
                                        &line_number_key, &lvalue);
 
             if (value != NULL) {
                 i = njs_value_number(value) - 1;
 
-                if (i < jmcf->imports->nelts) {
-                    import = jmcf->imports->elts;
+                if (i < conf->imports->nelts) {
+                    import = conf->imports->elts;
                     ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                                   "%*s, included in %s:%ui", text.length,
                                   text.start, import[i].file, import[i].line);
-                    return NGX_CONF_ERROR;
+                    return NGX_ERROR;
                 }
             }
         }
 
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "%*s", text.length,
                       text.start);
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     if (start != end) {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                       "extra characters in js script: \"%*s\"",
                       end - start, start);
-        return NGX_CONF_ERROR;
-    }
-
-    return NGX_CONF_OK;
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
 }
 
 
@@ -4339,7 +4439,7 @@ ngx_http_js_init(ngx_conf_t *cf)
 static char *
 ngx_http_js_import(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_js_main_conf_t *jmcf = conf;
+    ngx_http_js_loc_conf_t *jlcf = conf;
 
     u_char                *p, *end, c;
     ngx_int_t              from;
@@ -4420,15 +4520,15 @@ ngx_http_js_import(ngx_conf_t *cf, ngx_c
         return NGX_CONF_ERROR;
     }
 
-    if (jmcf->imports == NGX_CONF_UNSET_PTR) {
-        jmcf->imports = ngx_array_create(cf->pool, 4,
+    if (jlcf->imports == NGX_CONF_UNSET_PTR) {
+        jlcf->imports = ngx_array_create(cf->pool, 4,
                                          sizeof(ngx_http_js_import_t));
-        if (jmcf->imports == NULL) {
+        if (jlcf->imports == NULL) {
             return NGX_CONF_ERROR;
         }
     }
 
-    import = ngx_array_push(jmcf->imports);
+    import = ngx_array_push(jlcf->imports);
     if (import == NULL) {
         return NGX_CONF_ERROR;
     }
@@ -4595,29 +4695,6 @@ ngx_http_js_body_filter_set(ngx_conf_t *
 
 
 static void *
-ngx_http_js_create_main_conf(ngx_conf_t *cf)
-{
-    ngx_http_js_main_conf_t  *conf;
-
-    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_js_main_conf_t));
-    if (conf == NULL) {
-        return NULL;
-    }
-
-    /*
-     * set by ngx_pcalloc():
-     *
-     *     conf->vm = NULL;
-     */
-
-    conf->paths = NGX_CONF_UNSET_PTR;
-    conf->imports = NGX_CONF_UNSET_PTR;
-
-    return conf;
-}
-
-
-static void *
 ngx_http_js_create_loc_conf(ngx_conf_t *cf)
 {
     ngx_http_js_loc_conf_t  *conf;
@@ -4630,6 +4707,7 @@ ngx_http_js_create_loc_conf(ngx_conf_t *
     /*
      * set by ngx_pcalloc():
      *
+     *     conf->vm = NULL;
      *     conf->content = { 0, NULL };
      *     conf->header_filter = { 0, NULL };
      *     conf->body_filter = { 0, NULL };
@@ -4639,6 +4717,9 @@ ngx_http_js_create_loc_conf(ngx_conf_t *
      *     conf->ssl_trusted_certificate = { 0, NULL };
      */
 
+    conf->paths = NGX_CONF_UNSET_PTR;
+    conf->imports = NGX_CONF_UNSET_PTR;
+
     conf->buffer_size = NGX_CONF_UNSET_SIZE;
     conf->max_response_body_size = NGX_CONF_UNSET_SIZE;
     conf->timeout = NGX_CONF_UNSET_MSEC;
@@ -4669,6 +4750,10 @@ ngx_http_js_merge_loc_conf(ngx_conf_t *c
     ngx_conf_merge_size_value(conf->max_response_body_size,
                               prev->max_response_body_size, 1048576);
 
+    if (ngx_http_js_merge_vm(cf, conf, prev) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
 #if (NGX_HTTP_SSL)
     ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT");
 
diff -r 076cdf8a1ced -r 648a8092c05a nginx/ngx_stream_js_module.c
--- a/nginx/ngx_stream_js_module.c	Tue Aug 02 20:42:04 2022 -0700
+++ b/nginx/ngx_stream_js_module.c	Tue Aug 02 20:45:17 2022 -0700
@@ -13,13 +13,6 @@
 
 
 typedef struct {
-    njs_vm_t              *vm;
-    ngx_array_t           *imports;
-    ngx_array_t           *paths;
-} ngx_stream_js_main_conf_t;
-
-
-typedef struct {
     ngx_str_t              name;
     ngx_str_t              path;
     u_char                *file;
@@ -28,6 +21,10 @@ typedef struct {
 
 
 typedef struct {
+    njs_vm_t              *vm;
+    ngx_array_t           *imports;
+    ngx_array_t           *paths;
+
     ngx_str_t              access;
     ngx_str_t              preread;
     ngx_str_t              filter;
@@ -144,8 +141,10 @@ static char *ngx_stream_js_set(ngx_conf_
     void *conf);
 static char *ngx_stream_js_var(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
-static void *ngx_stream_js_create_main_conf(ngx_conf_t *cf);
-static char *ngx_stream_js_init_main_conf(ngx_conf_t *cf, void *conf);
+static ngx_int_t ngx_stream_js_merge_vm(ngx_conf_t *cf,
+    ngx_stream_js_srv_conf_t *conf, ngx_stream_js_srv_conf_t *prev);
+static ngx_int_t ngx_stream_js_init_conf_vm(ngx_conf_t *cf,
+    ngx_stream_js_srv_conf_t *conf);
 static void *ngx_stream_js_create_srv_conf(ngx_conf_t *cf);
 static char *ngx_stream_js_merge_srv_conf(ngx_conf_t *cf, void *parent,
     void *child);
@@ -174,28 +173,28 @@ static ngx_conf_bitmask_t  ngx_stream_js
 static ngx_command_t  ngx_stream_js_commands[] = {
 
     { ngx_string("js_import"),
-      NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE13,
+      NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE13,
       ngx_stream_js_import,
-      NGX_STREAM_MAIN_CONF_OFFSET,
+      NGX_STREAM_SRV_CONF_OFFSET,
       0,
       NULL },
 
     { ngx_string("js_path"),
-      NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
+      NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_array_slot,
-      NGX_STREAM_MAIN_CONF_OFFSET,
-      offsetof(ngx_stream_js_main_conf_t, paths),
+      NGX_STREAM_SRV_CONF_OFFSET,
+      offsetof(ngx_stream_js_srv_conf_t, paths),
       NULL },
 
     { ngx_string("js_set"),
-      NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE2,
+      NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE2,
       ngx_stream_js_set,
       0,
       0,
       NULL },
 
     { ngx_string("js_var"),
-      NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12,
+      NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE12,
       ngx_stream_js_var,
       0,
       0,
@@ -290,8 +289,8 @@ static ngx_stream_module_t  ngx_stream_j
     NULL,                           /* preconfiguration */
     ngx_stream_js_init,             /* postconfiguration */
 
-    ngx_stream_js_create_main_conf, /* create main configuration */
-    ngx_stream_js_init_main_conf,   /* init main configuration */
+    NULL,                           /* create main configuration */
+    NULL,                           /* init main configuration */
 
     ngx_stream_js_create_srv_conf,  /* create server configuration */
     ngx_stream_js_merge_srv_conf,   /* merge server configuration */
@@ -820,14 +819,14 @@ ngx_stream_js_variable_var(ngx_stream_se
 static ngx_int_t
 ngx_stream_js_init_vm(ngx_stream_session_t *s)
 {
-    njs_int_t                   rc;
-    ngx_str_t                   exception;
-    ngx_pool_cleanup_t         *cln;
-    ngx_stream_js_ctx_t        *ctx;
-    ngx_stream_js_main_conf_t  *jmcf;
-
-    jmcf = ngx_stream_get_module_main_conf(s, ngx_stream_js_module);
-    if (jmcf->vm == NULL) {
+    njs_int_t                  rc;
+    ngx_str_t                  exception;
+    ngx_pool_cleanup_t        *cln;
+    ngx_stream_js_ctx_t       *ctx;
+    ngx_stream_js_srv_conf_t  *jscf;
+
+    jscf = ngx_stream_get_module_srv_conf(s, ngx_stream_js_module);
+    if (jscf->vm == NULL) {
         return NGX_DECLINED;
     }
 
@@ -848,7 +847,7 @@ ngx_stream_js_init_vm(ngx_stream_session
         return NGX_OK;
     }
 
-    ctx->vm = njs_vm_clone(jmcf->vm, s);
+    ctx->vm = njs_vm_clone(jscf->vm, s);
     if (ctx->vm == NULL) {
         return NGX_ERROR;
     }
@@ -1569,11 +1568,116 @@ ngx_stream_js_handle_event(ngx_stream_se
 }
 
 
-static char *
-ngx_stream_js_init_main_conf(ngx_conf_t *cf, void *conf)
+static ngx_int_t
+ngx_stream_js_merge_vm(ngx_conf_t *cf, ngx_stream_js_srv_conf_t *conf,
+    ngx_stream_js_srv_conf_t *prev)
 {
-    ngx_stream_js_main_conf_t *jmcf = conf;
-
+    ngx_str_t               *path, *s;
+    ngx_uint_t               i;
+    ngx_array_t             *imports, *paths;
+    ngx_stream_js_import_t  *import, *pi;
+
+    if (prev->imports != NGX_CONF_UNSET_PTR && prev->vm == NULL) {
+        if (ngx_stream_js_init_conf_vm(cf, prev) != NGX_OK) {
+            return NGX_ERROR;
+        }
+    }
+
+    if (conf->imports == NGX_CONF_UNSET_PTR
+        && conf->paths == NGX_CONF_UNSET_PTR)
+    {
+        if (prev->vm != NULL) {
+            conf->imports = prev->imports;
+            conf->paths = prev->paths;
+            conf->vm = prev->vm;
+            return NGX_OK;
+        }
+    }
+
+    if (prev->imports != NGX_CONF_UNSET_PTR) {
+        if (conf->imports == NGX_CONF_UNSET_PTR) {
+            conf->imports = prev->imports;
+
+        } else {
+            imports = ngx_array_create(cf->pool, 4,
+                                       sizeof(ngx_stream_js_import_t));
+            if (imports == NULL) {
+                return NGX_ERROR;
+            }
+
+            pi = prev->imports->elts;
+
+            for (i = 0; i < prev->imports->nelts; i++) {
+                import = ngx_array_push(imports);
+                if (import == NULL) {
+                    return NGX_ERROR;
+                }
+
+                *import = pi[i];
+            }
+
+            pi = conf->imports->elts;
+
+            for (i = 0; i < conf->imports->nelts; i++) {
+                import = ngx_array_push(imports);
+                if (import == NULL) {
+                    return NGX_ERROR;
+                }
+
+                *import = pi[i];
+            }
+
+            conf->imports = imports;
+        }
+    }
+
+    if (prev->paths != NGX_CONF_UNSET_PTR) {
+        if (conf->paths == NGX_CONF_UNSET_PTR) {
+            conf->paths = prev->paths;
+
+        } else {
+            paths = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
+            if (paths == NULL) {
+                return NGX_ERROR;
+            }
+
+            s = prev->imports->elts;
+
+            for (i = 0; i < prev->paths->nelts; i++) {
+                path = ngx_array_push(paths);
+                if (path == NULL) {
+                    return NGX_ERROR;
+                }
+
+                *path = s[i];
+            }
+
+            s = conf->imports->elts;
+
+            for (i = 0; i < conf->paths->nelts; i++) {
+                path = ngx_array_push(paths);
+                if (path == NULL) {
+                    return NGX_ERROR;
+                }
+
+                *path = s[i];
+            }
+
+            conf->paths = paths;
+        }
+    }
+
+    if (conf->imports == NGX_CONF_UNSET_PTR) {
+        return NGX_OK;
+    }
+
+    return ngx_stream_js_init_conf_vm(cf, conf);
+}
+
+
+static ngx_int_t
+ngx_stream_js_init_conf_vm(ngx_conf_t *cf, ngx_stream_js_srv_conf_t *conf)
+{
     size_t                   size;
     u_char                  *start, *end, *p;
     ngx_str_t               *m, file;
@@ -1589,14 +1693,10 @@ ngx_stream_js_init_main_conf(ngx_conf_t 
     static const njs_str_t line_number_key = njs_str("lineNumber");
     static const njs_str_t file_name_key = njs_str("fileName");
 
-    if (jmcf->imports == NGX_CONF_UNSET_PTR) {
-        return NGX_CONF_OK;
-    }
-
     size = 0;
 
-    import = jmcf->imports->elts;
-    for (i = 0; i < jmcf->imports->nelts; i++) {
+    import = conf->imports->elts;
+    for (i = 0; i < conf->imports->nelts; i++) {
         /* import <name> from '<path>'; globalThis.<name> = <name>; */
 
         size += sizeof("import  from '';") - 1 + import[i].name.len * 3
@@ -1606,12 +1706,12 @@ ngx_stream_js_init_main_conf(ngx_conf_t 
 
     start = ngx_pnalloc(cf->pool, size);
     if (start == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     p = start;
-    import = jmcf->imports->elts;
-    for (i = 0; i < jmcf->imports->nelts; i++) {
+    import = conf->imports->elts;
+    for (i = 0; i < conf->imports->nelts; i++) {
 
         /* import <name> from '<path>'; globalThis.<name> = <name>; */
 
@@ -1641,110 +1741,110 @@ ngx_stream_js_init_main_conf(ngx_conf_t 
     options.file.start = file.data;
     options.file.length = file.len;
 
-    jmcf->vm = njs_vm_create(&options);
-    if (jmcf->vm == NULL) {
+    conf->vm = njs_vm_create(&options);
+    if (conf->vm == NULL) {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "failed to create js VM");
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     cln = ngx_pool_cleanup_add(cf->pool, 0);
     if (cln == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     cln->handler = ngx_stream_js_cleanup_vm;
-    cln->data = jmcf->vm;
+    cln->data = conf->vm;
 
     path.start = ngx_cycle->conf_prefix.data;
     path.length = ngx_cycle->conf_prefix.len;
 
-    rc = njs_vm_add_path(jmcf->vm, &path);
+    rc = njs_vm_add_path(conf->vm, &path);
     if (rc != NJS_OK) {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "failed to add \"js_path\"");
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
-    if (jmcf->paths != NGX_CONF_UNSET_PTR) {
-        m = jmcf->paths->elts;
-
-        for (i = 0; i < jmcf->paths->nelts; i++) {
+    if (conf->paths != NGX_CONF_UNSET_PTR) {
+        m = conf->paths->elts;
+
+        for (i = 0; i < conf->paths->nelts; i++) {
             if (ngx_conf_full_name(cf->cycle, &m[i], 1) != NGX_OK) {
-                return NGX_CONF_ERROR;
+                return NGX_ERROR;
             }
 
             path.start = m[i].data;
             path.length = m[i].len;
 
-            rc = njs_vm_add_path(jmcf->vm, &path);
+            rc = njs_vm_add_path(conf->vm, &path);
             if (rc != NJS_OK) {
                 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                               "failed to add \"js_path\"");
-                return NGX_CONF_ERROR;
+                return NGX_ERROR;
             }
         }
     }
 
-    ngx_stream_js_session_proto_id = njs_vm_external_prototype(jmcf->vm,
+    ngx_stream_js_session_proto_id = njs_vm_external_prototype(conf->vm,
                                          ngx_stream_js_ext_session,
                                          njs_nitems(ngx_stream_js_ext_session));
     if (ngx_stream_js_session_proto_id < 0) {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                       "failed to add js request proto");
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
-    rc = ngx_js_core_init(jmcf->vm, cf->log);
+    rc = ngx_js_core_init(conf->vm, cf->log);
     if (njs_slow_path(rc != NJS_OK)) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     end = start + size;
 
-    rc = njs_vm_compile(jmcf->vm, &start, end);
+    rc = njs_vm_compile(conf->vm, &start, end);
 
     if (rc != NJS_OK) {
-        njs_value_assign(&exception, njs_vm_retval(jmcf->vm));
-        njs_vm_retval_string(jmcf->vm, &text);
-
-        value = njs_vm_object_prop(jmcf->vm, njs_value_arg(&exception),
+        njs_value_assign(&exception, njs_vm_retval(conf->vm));
+        njs_vm_retval_string(conf->vm, &text);
+
+        value = njs_vm_object_prop(conf->vm, njs_value_arg(&exception),
                                    &file_name_key, &lvalue);
         if (value == NULL) {
-            value = njs_vm_object_prop(jmcf->vm, njs_value_arg(&exception),
+            value = njs_vm_object_prop(conf->vm, njs_value_arg(&exception),
                                        &line_number_key, &lvalue);
 
             if (value != NULL) {
                 i = njs_value_number(value) - 1;
 
-                if (i < jmcf->imports->nelts) {
-                    import = jmcf->imports->elts;
+                if (i < conf->imports->nelts) {
+                    import = conf->imports->elts;
                     ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                                   "%*s, included in %s:%ui", text.length,
                                   text.start, import[i].file, import[i].line);
-                    return NGX_CONF_ERROR;
+                    return NGX_ERROR;
                 }
             }
         }
 
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "%*s", text.length,
                       text.start);
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     if (start != end) {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                       "extra characters in js script: \"%*s\"",
                       end - start, start);
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
-    return NGX_CONF_OK;
+    return NGX_OK;
 }
 
 
 static char *
 ngx_stream_js_import(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_stream_js_main_conf_t *jmcf = conf;
+    ngx_stream_js_srv_conf_t *jscf = conf;
 
     u_char                  *p, *end, c;
     ngx_int_t               from;
@@ -1824,15 +1924,15 @@ ngx_stream_js_import(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    if (jmcf->imports == NGX_CONF_UNSET_PTR) {
-        jmcf->imports = ngx_array_create(cf->pool, 4,
+    if (jscf->imports == NGX_CONF_UNSET_PTR) {
+        jscf->imports = ngx_array_create(cf->pool, 4,
                                          sizeof(ngx_stream_js_import_t));
-        if (jmcf->imports == NULL) {
+        if (jscf->imports == NULL) {
             return NGX_CONF_ERROR;
         }
     }
 
-    import = ngx_array_push(jmcf->imports);
+    import = ngx_array_push(jscf->imports);
     if (import == NULL) {
         return NGX_CONF_ERROR;
     }
@@ -1939,29 +2039,6 @@ ngx_stream_js_var(ngx_conf_t *cf, ngx_co
 
 
 static void *
-ngx_stream_js_create_main_conf(ngx_conf_t *cf)
-{
-    ngx_stream_js_main_conf_t  *conf;
-
-    conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_js_main_conf_t));
-    if (conf == NULL) {
-        return NULL;
-    }
-
-    /*
-     * set by ngx_pcalloc():
-     *
-     *     conf->vm = NULL;
-     */
-
-    conf->paths = NGX_CONF_UNSET_PTR;
-    conf->imports = NGX_CONF_UNSET_PTR;
-
-    return conf;
-}
-
-
-static void *
 ngx_stream_js_create_srv_conf(ngx_conf_t *cf)
 {
     ngx_stream_js_srv_conf_t  *conf;
@@ -1974,6 +2051,7 @@ ngx_stream_js_create_srv_conf(ngx_conf_t
     /*
      * set by ngx_pcalloc():
      *
+     *     conf->vm = NULL;
      *     conf->access = { 0, NULL };
      *     conf->preread = { 0, NULL };
      *     conf->filter = { 0, NULL };
@@ -1982,6 +2060,9 @@ ngx_stream_js_create_srv_conf(ngx_conf_t
      *     conf->ssl_trusted_certificate = { 0, NULL };
      */
 
+    conf->paths = NGX_CONF_UNSET_PTR;
+    conf->imports = NGX_CONF_UNSET_PTR;
+
     conf->buffer_size = NGX_CONF_UNSET_SIZE;
     conf->max_response_body_size = NGX_CONF_UNSET_SIZE;
     conf->timeout = NGX_CONF_UNSET_MSEC;
@@ -2009,6 +2090,10 @@ ngx_stream_js_merge_srv_conf(ngx_conf_t 
     ngx_conf_merge_size_value(conf->max_response_body_size,
                               prev->max_response_body_size, 1048576);



More information about the nginx-devel mailing list