[njs] Modules: added js_import directive.
Dmitry Volyntsev
xeioex at nginx.com
Tue Apr 14 12:41:34 UTC 2020
details: https://hg.nginx.org/njs/rev/777ed1eb1918
branches:
changeset: 1371:777ed1eb1918
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Tue Apr 14 12:18:25 2020 +0000
description:
Modules: added js_import directive.
diffstat:
nginx/ngx_http_js_module.c | 352 +++++++++++++++++++++++++++++++++-------
nginx/ngx_stream_js_module.c | 361 ++++++++++++++++++++++++++++++++++--------
2 files changed, 573 insertions(+), 140 deletions(-)
diffs (truncated from 1010 to 1000 lines):
diff -r a46c221089c0 -r 777ed1eb1918 nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c Sun Apr 12 12:56:25 2020 +0000
+++ b/nginx/ngx_http_js_module.c Tue Apr 14 12:18:25 2020 +0000
@@ -1,6 +1,7 @@
/*
* Copyright (C) Roman Arutyunyan
+ * Copyright (C) Dmitry Volyntsev
* Copyright (C) NGINX, Inc.
*/
@@ -14,6 +15,10 @@
typedef struct {
njs_vm_t *vm;
+ ngx_str_t include;
+ u_char *file;
+ ngx_uint_t line;
+ ngx_array_t *imports;
ngx_array_t *paths;
njs_external_proto_t req_proto;
} ngx_http_js_main_conf_t;
@@ -25,6 +30,14 @@ typedef struct {
typedef struct {
+ ngx_str_t name;
+ ngx_str_t path;
+ u_char *file;
+ ngx_uint_t line;
+} ngx_http_js_import_t;
+
+
+typedef struct {
njs_vm_t *vm;
ngx_log_t *log;
ngx_uint_t done;
@@ -131,10 +144,13 @@ static njs_int_t ngx_http_js_string(njs_
static char *ngx_http_js_include(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_js_import(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static char *ngx_http_js_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_http_js_content(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 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);
@@ -146,6 +162,13 @@ static ngx_command_t ngx_http_js_comman
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_http_js_include,
NGX_HTTP_MAIN_CONF_OFFSET,
+ offsetof(ngx_http_js_main_conf_t, include),
+ NULL },
+
+ { ngx_string("js_import"),
+ NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE13,
+ ngx_http_js_import,
+ NGX_HTTP_MAIN_CONF_OFFSET,
0,
NULL },
@@ -179,7 +202,7 @@ static ngx_http_module_t ngx_http_js_mo
NULL, /* postconfiguration */
ngx_http_js_create_main_conf, /* create main configuration */
- NULL, /* init main configuration */
+ ngx_http_js_init_main_conf, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
@@ -2328,82 +2351,113 @@ ngx_http_js_string(njs_vm_t *vm, njs_val
static char *
-ngx_http_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+ngx_http_js_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_js_main_conf_t *jmcf = conf;
size_t size;
- u_char *start, *end;
+ u_char *start, *end, *p;
ssize_t n;
ngx_fd_t fd;
- ngx_str_t *m, *value, file;
+ ngx_str_t *m, file;
njs_int_t rc;
njs_str_t text, path;
ngx_uint_t i;
+ njs_value_t *value;
njs_vm_opt_t options;
ngx_file_info_t fi;
ngx_pool_cleanup_t *cln;
+ njs_opaque_value_t lvalue, exception;
njs_external_proto_t proto;
-
- if (jmcf->vm) {
- return "is duplicate";
- }
-
- value = cf->args->elts;
- file = value[1];
-
- if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
- return NGX_CONF_ERROR;
+ ngx_http_js_import_t *import;
+
+ static const njs_str_t line_number_key = njs_str("lineNumber");
+ static const njs_str_t file_name_key = njs_str("fileName");
+
+ if (jmcf->include.len == 0 && jmcf->imports == NGX_CONF_UNSET_PTR) {
+ return NGX_CONF_OK;
}
- fd = ngx_open_file(file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
- if (fd == NGX_INVALID_FILE) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
- ngx_open_file_n " \"%s\" failed", file.data);
- return NGX_CONF_ERROR;
+ size = 0;
+ fd = NGX_INVALID_FILE;
+
+ if (jmcf->include.len != 0) {
+ file = jmcf->include;
+
+ if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ fd = ngx_open_file(file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+ if (fd == NGX_INVALID_FILE) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
+ ngx_open_file_n " \"%s\" failed", file.data);
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
+ ngx_fd_info_n " \"%s\" failed", file.data);
+ (void) ngx_close_file(fd);
+ return NGX_CONF_ERROR;
+ }
+
+ size = ngx_file_size(&fi);
+
+ } else {
+ import = jmcf->imports->elts;
+ for (i = 0; i < jmcf->imports->nelts; i++) {
+ size += sizeof("import from '';\n") - 1 + import[i].name.len
+ + import[i].path.len;
+ }
}
- if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
- ngx_fd_info_n " \"%s\" failed", file.data);
- (void) ngx_close_file(fd);
- return NGX_CONF_ERROR;
- }
-
- size = ngx_file_size(&fi);
-
start = ngx_pnalloc(cf->pool, size);
if (start == NULL) {
- (void) ngx_close_file(fd);
- return NGX_CONF_ERROR;
- }
-
- n = ngx_read_fd(fd, start, size);
-
- if (n == -1) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
- ngx_read_fd_n " \"%s\" failed", file.data);
-
- (void) ngx_close_file(fd);
+ if (fd != NGX_INVALID_FILE) {
+ (void) ngx_close_file(fd);
+ }
+
return NGX_CONF_ERROR;
}
- if ((size_t) n != size) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- ngx_read_fd_n " has read only %z of %O from \"%s\"",
- n, size, file.data);
-
- (void) ngx_close_file(fd);
- return NGX_CONF_ERROR;
+ if (jmcf->include.len != 0) {
+ n = ngx_read_fd(fd, start, size);
+
+ if (n == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
+ ngx_read_fd_n " \"%s\" failed", file.data);
+
+ (void) ngx_close_file(fd);
+ return NGX_CONF_ERROR;
+ }
+
+ if ((size_t) n != size) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ ngx_read_fd_n " has read only %z "
+ "of %O from \"%s\"", n, size, file.data);
+
+ (void) ngx_close_file(fd);
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
+ ngx_close_file_n " %s failed", file.data);
+ }
+
+ } else {
+ p = start;
+ import = jmcf->imports->elts;
+ for (i = 0; i < jmcf->imports->nelts; i++) {
+ p = ngx_cpymem(p, "import ", sizeof("import ") - 1);
+ p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
+ p = ngx_cpymem(p, " from '", sizeof(" from '") - 1);
+ p = ngx_cpymem(p, import[i].path.data, import[i].path.len);
+ p = ngx_cpymem(p, "';\n", sizeof("';\n") - 1);
+ }
}
- if (ngx_close_file(fd) == NGX_FILE_ERROR) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
- ngx_close_file_n " %s failed", file.data);
- }
-
- end = start + size;
-
njs_vm_opt_init(&options);
options.backtrace = 1;
@@ -2411,13 +2465,19 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_
options.argv = ngx_argv;
options.argc = ngx_argc;
- file = value[1];
+ if (jmcf->include.len != 0) {
+ file = jmcf->include;
+
+ } else {
+ file = ngx_cycle->conf_prefix;
+ }
+
options.file.start = file.data;
options.file.length = file.len;
jmcf->vm = njs_vm_create(&options);
if (jmcf->vm == NULL) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to create JS VM");
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "failed to create js VM");
return NGX_CONF_ERROR;
}
@@ -2429,12 +2489,12 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_
cln->handler = ngx_http_js_cleanup_vm;
cln->data = jmcf->vm;
- path.start = ngx_cycle->prefix.data;
- path.length = ngx_cycle->prefix.len;
+ path.start = ngx_cycle->conf_prefix.data;
+ path.length = ngx_cycle->conf_prefix.len;
rc = njs_vm_add_path(jmcf->vm, &path);
if (rc != NJS_OK) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to add path");
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "failed to add \"js_path\"");
return NGX_CONF_ERROR;
}
@@ -2442,7 +2502,7 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_
m = jmcf->paths->elts;
for (i = 0; i < jmcf->paths->nelts; i++) {
- if (ngx_conf_full_name(cf->cycle, &m[i], 0) != NGX_OK) {
+ if (ngx_conf_full_name(cf->cycle, &m[i], 1) != NGX_OK) {
return NGX_CONF_ERROR;
}
@@ -2451,7 +2511,8 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_
rc = njs_vm_add_path(jmcf->vm, &path);
if (rc != NJS_OK) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to add path");
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "failed to add \"js_path\"");
return NGX_CONF_ERROR;
}
}
@@ -2460,27 +2521,54 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_
proto = njs_vm_external_prototype(jmcf->vm, ngx_http_js_ext_request,
njs_nitems(ngx_http_js_ext_request));
if (proto == NULL) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to add request proto");
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "failed to add js request proto");
return NGX_CONF_ERROR;
}
jmcf->req_proto = proto;
+ end = start + size;
rc = njs_vm_compile(jmcf->vm, &start, end);
if (rc != NJS_OK) {
+ njs_value_assign(&exception, njs_vm_retval(jmcf->vm));
njs_vm_retval_string(jmcf->vm, &text);
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "%*s, included",
- text.length, text.start);
+ if (jmcf->include.len != 0) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "%*s, included in %s:%ui",
+ text.length, text.start, jmcf->file, jmcf->line);
+ return NGX_CONF_ERROR;
+ }
+
+ value = njs_vm_object_prop(jmcf->vm, njs_value_arg(&exception),
+ &file_name_key, &lvalue);
+ if (value == NULL) {
+ value = njs_vm_object_prop(jmcf->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;
+ 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;
+ }
+ }
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "%*s", text.length,
+ text.start);
return NGX_CONF_ERROR;
}
if (start != end) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "extra characters in js script: \"%*s\", included",
- end - start, start);
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "extra characters in js script: \"%*s\"",
+ end - start, start);
return NGX_CONF_ERROR;
}
@@ -2489,6 +2577,132 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_
static char *
+ngx_http_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_js_main_conf_t *jmcf = conf;
+
+ if (jmcf->imports != NGX_CONF_UNSET_PTR) {
+ return "is incompatible with \"js_import\"";
+ }
+
+ jmcf->file = cf->conf_file->file.name.data;
+ jmcf->line = cf->conf_file->line;
+
+ return ngx_conf_set_str_slot(cf, cmd, conf);
+}
+
+
+static char *
+ngx_http_js_import(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_js_main_conf_t *jmcf = conf;
+
+ u_char *p, *end, c;
+ ngx_int_t from;
+ ngx_str_t *value, name, path;
+ ngx_http_js_import_t *import;
+
+ if (jmcf->include.len != 0) {
+ return "is incompatible with \"js_include\"";
+ }
+
+ value = cf->args->elts;
+ from = (cf->args->nelts == 4);
+
+ if (from) {
+ if (ngx_strcmp(value[2].data, "from") != 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[2]);
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ name = value[1];
+ path = (from ? value[3] : value[1]);
+
+ if (!from) {
+ end = name.data + name.len;
+
+ for (p = end - 1; p >= name.data; p--) {
+ if (*p == '/') {
+ break;
+ }
+ }
+
+ name.data = p + 1;
+ name.len = end - p - 1;
+
+ if (name.len < 3
+ || ngx_memcmp(&name.data[name.len - 3], ".js", 3) != 0)
+ {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "cannot extract export name from file path "
+ "\"%V\", use extended \"from\" syntax", &path);
+ return NGX_CONF_ERROR;
+ }
+
+ name.len -= 3;
+ }
+
+ if (name.len == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty export name");
+ return NGX_CONF_ERROR;
+ }
+
+ p = name.data;
+ end = name.data + name.len;
+
+ while (p < end) {
+ c = ngx_tolower(*p);
+
+ if (*p != '_' && (c < 'a' || c > 'z')) {
+ if (p == name.data) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "cannot start "
+ "with \"%c\" in export name \"%V\"", *p,
+ &name);
+ return NGX_CONF_ERROR;
+ }
+
+ if (*p < '0' || *p > '9') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid character "
+ "\"%c\" in export name \"%V\"", *p,
+ &name);
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ p++;
+ }
+
+ if (ngx_strchr(path.data, '\'') != NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid character \"'\" "
+ "in file path \"%V\"", &path);
+ return NGX_CONF_ERROR;
+ }
+
+ if (jmcf->imports == NGX_CONF_UNSET_PTR) {
+ jmcf->imports = ngx_array_create(cf->pool, 4,
+ sizeof(ngx_http_js_import_t));
+ if (jmcf->imports == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ import = ngx_array_push(jmcf->imports);
+ if (import == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ import->name = name;
+ import->path = path;
+ import->file = cf->conf_file->file.name.data;
+ import->line = cf->conf_file->line;
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
ngx_http_js_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_str_t *value, *fname;
@@ -2560,10 +2774,14 @@ ngx_http_js_create_main_conf(ngx_conf_t
* set by ngx_pcalloc():
*
* conf->vm = NULL;
+ * conf->include = { 0, NULL };
+ * conf->file = NULL;
+ * conf->line = 0;
* conf->req_proto = NULL;
*/
conf->paths = NGX_CONF_UNSET_PTR;
+ conf->imports = NGX_CONF_UNSET_PTR;
return conf;
}
diff -r a46c221089c0 -r 777ed1eb1918 nginx/ngx_stream_js_module.c
--- a/nginx/ngx_stream_js_module.c Sun Apr 12 12:56:25 2020 +0000
+++ b/nginx/ngx_stream_js_module.c Tue Apr 14 12:18:25 2020 +0000
@@ -15,12 +15,24 @@
typedef struct {
njs_vm_t *vm;
+ ngx_str_t include;
+ u_char *file;
+ ngx_uint_t line;
+ ngx_array_t *imports;
ngx_array_t *paths;
njs_external_proto_t proto;
} ngx_stream_js_main_conf_t;
typedef struct {
+ ngx_str_t name;
+ ngx_str_t path;
+ u_char *file;
+ ngx_uint_t line;
+} ngx_stream_js_import_t;
+
+
+typedef struct {
ngx_str_t access;
ngx_str_t preread;
ngx_str_t filter;
@@ -103,9 +115,12 @@ static njs_int_t ngx_stream_js_string(nj
static char *ngx_stream_js_include(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_stream_js_import(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static char *ngx_stream_js_set(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 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);
@@ -118,6 +133,13 @@ static ngx_command_t ngx_stream_js_comm
NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
ngx_stream_js_include,
NGX_STREAM_MAIN_CONF_OFFSET,
+ offsetof(ngx_stream_js_main_conf_t, include),
+ NULL },
+
+ { ngx_string("js_import"),
+ NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE13,
+ ngx_stream_js_import,
+ NGX_STREAM_MAIN_CONF_OFFSET,
0,
NULL },
@@ -165,7 +187,7 @@ static ngx_stream_module_t ngx_stream_j
ngx_stream_js_init, /* postconfiguration */
ngx_stream_js_create_main_conf, /* create main configuration */
- NULL, /* init main configuration */
+ ngx_stream_js_init_main_conf, /* init main configuration */
ngx_stream_js_create_srv_conf, /* create server configuration */
ngx_stream_js_merge_srv_conf, /* merge server configuration */
@@ -1336,82 +1358,113 @@ ngx_stream_js_string(njs_vm_t *vm, njs_v
static char *
-ngx_stream_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+ngx_stream_js_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_stream_js_main_conf_t *jmcf = conf;
- size_t size;
- u_char *start, *end;
- ssize_t n;
- ngx_fd_t fd;
- ngx_str_t *m, *value, file;
- njs_int_t rc;
- njs_str_t text, path;
- ngx_uint_t i;
- njs_vm_opt_t options;
- ngx_file_info_t fi;
- ngx_pool_cleanup_t *cln;
- njs_external_proto_t proto;
+ size_t size;
+ u_char *start, *end, *p;
+ ssize_t n;
+ ngx_fd_t fd;
+ ngx_str_t *m, file;
+ njs_int_t rc;
+ njs_str_t text, path;
+ ngx_uint_t i;
+ njs_value_t *value;
+ njs_vm_opt_t options;
+ ngx_file_info_t fi;
+ ngx_pool_cleanup_t *cln;
+ njs_opaque_value_t lvalue, exception;
+ njs_external_proto_t proto;
+ ngx_stream_js_import_t *import;
- if (jmcf->vm) {
- return "is duplicate";
+ static const njs_str_t line_number_key = njs_str("lineNumber");
+ static const njs_str_t file_name_key = njs_str("fileName");
+
+ if (jmcf->include.len == 0 && jmcf->imports == NGX_CONF_UNSET_PTR) {
+ return NGX_CONF_OK;
}
- value = cf->args->elts;
- file = value[1];
+ size = 0;
+ fd = NGX_INVALID_FILE;
+
+ if (jmcf->include.len != 0) {
+ file = jmcf->include;
+
+ if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
- if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
- return NGX_CONF_ERROR;
+ fd = ngx_open_file(file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+ if (fd == NGX_INVALID_FILE) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
+ ngx_open_file_n " \"%s\" failed", file.data);
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
+ ngx_fd_info_n " \"%s\" failed", file.data);
+ (void) ngx_close_file(fd);
+ return NGX_CONF_ERROR;
+ }
+
+ size = ngx_file_size(&fi);
+
+ } else {
+ import = jmcf->imports->elts;
+ for (i = 0; i < jmcf->imports->nelts; i++) {
+ size += sizeof("import from '';\n") - 1 + import[i].name.len
+ + import[i].path.len;
+ }
}
- fd = ngx_open_file(file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
- if (fd == NGX_INVALID_FILE) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
- ngx_open_file_n " \"%s\" failed", file.data);
+ start = ngx_pnalloc(cf->pool, size);
+ if (start == NULL) {
+ if (fd != NGX_INVALID_FILE) {
+ (void) ngx_close_file(fd);
+ }
+
return NGX_CONF_ERROR;
}
- if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
- ngx_fd_info_n " \"%s\" failed", file.data);
- (void) ngx_close_file(fd);
- return NGX_CONF_ERROR;
- }
+ if (jmcf->include.len != 0) {
+ n = ngx_read_fd(fd, start, size);
+
+ if (n == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
+ ngx_read_fd_n " \"%s\" failed", file.data);
- size = ngx_file_size(&fi);
+ (void) ngx_close_file(fd);
+ return NGX_CONF_ERROR;
+ }
- start = ngx_pnalloc(cf->pool, size);
- if (start == NULL) {
- (void) ngx_close_file(fd);
- return NGX_CONF_ERROR;
- }
-
- n = ngx_read_fd(fd, start, size);
+ if ((size_t) n != size) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ ngx_read_fd_n " has read only %z "
+ "of %O from \"%s\"", n, size, file.data);
- if (n == -1) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
- ngx_read_fd_n " \"%s\" failed", file.data);
+ (void) ngx_close_file(fd);
+ return NGX_CONF_ERROR;
+ }
- (void) ngx_close_file(fd);
- return NGX_CONF_ERROR;
- }
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
+ ngx_close_file_n " %s failed", file.data);
+ }
- if ((size_t) n != size) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- ngx_read_fd_n " has read only %z of %uz from \"%s\"",
- n, size, file.data);
-
- (void) ngx_close_file(fd);
- return NGX_CONF_ERROR;
+ } else {
+ p = start;
+ import = jmcf->imports->elts;
+ for (i = 0; i < jmcf->imports->nelts; i++) {
+ p = ngx_cpymem(p, "import ", sizeof("import ") - 1);
+ p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
+ p = ngx_cpymem(p, " from '", sizeof(" from '") - 1);
+ p = ngx_cpymem(p, import[i].path.data, import[i].path.len);
+ p = ngx_cpymem(p, "';\n", sizeof("';\n") - 1);
+ }
}
- if (ngx_close_file(fd) == NGX_FILE_ERROR) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
- ngx_close_file_n " %s failed", file.data);
- }
-
- end = start + size;
-
njs_vm_opt_init(&options);
options.backtrace = 1;
@@ -1419,13 +1472,19 @@ ngx_stream_js_include(ngx_conf_t *cf, ng
options.argv = ngx_argv;
options.argc = ngx_argc;
- file = value[1];
+ if (jmcf->include.len != 0) {
+ file = jmcf->include;
+
+ } else {
+ file = ngx_cycle->conf_prefix;
+ }
+
options.file.start = file.data;
options.file.length = file.len;
jmcf->vm = njs_vm_create(&options);
if (jmcf->vm == NULL) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to create JS VM");
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "failed to create js VM");
return NGX_CONF_ERROR;
}
@@ -1437,12 +1496,12 @@ ngx_stream_js_include(ngx_conf_t *cf, ng
cln->handler = ngx_stream_js_cleanup_vm;
cln->data = jmcf->vm;
- path.start = ngx_cycle->prefix.data;
- path.length = ngx_cycle->prefix.len;
+ path.start = ngx_cycle->conf_prefix.data;
+ path.length = ngx_cycle->conf_prefix.len;
rc = njs_vm_add_path(jmcf->vm, &path);
if (rc != NJS_OK) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to add path");
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "failed to add \"js_path\"");
return NGX_CONF_ERROR;
}
@@ -1450,7 +1509,7 @@ ngx_stream_js_include(ngx_conf_t *cf, ng
m = jmcf->paths->elts;
for (i = 0; i < jmcf->paths->nelts; i++) {
- if (ngx_conf_full_name(cf->cycle, &m[i], 0) != NGX_OK) {
+ if (ngx_conf_full_name(cf->cycle, &m[i], 1) != NGX_OK) {
return NGX_CONF_ERROR;
}
@@ -1459,7 +1518,8 @@ ngx_stream_js_include(ngx_conf_t *cf, ng
rc = njs_vm_add_path(jmcf->vm, &path);
if (rc != NJS_OK) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to add path");
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "failed to add \"js_path\"");
return NGX_CONF_ERROR;
}
}
@@ -1467,29 +1527,55 @@ ngx_stream_js_include(ngx_conf_t *cf, ng
proto = njs_vm_external_prototype(jmcf->vm, ngx_stream_js_ext_session,
njs_nitems(ngx_stream_js_ext_session));
-
if (proto == NULL) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to add stream proto");
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "failed to add js request proto");
return NGX_CONF_ERROR;
}
jmcf->proto = proto;
+ end = start + size;
rc = njs_vm_compile(jmcf->vm, &start, end);
if (rc != NJS_OK) {
+ njs_value_assign(&exception, njs_vm_retval(jmcf->vm));
njs_vm_retval_string(jmcf->vm, &text);
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "%*s, included",
- text.length, text.start);
+ if (jmcf->include.len != 0) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "%*s, included in %s:%ui",
+ text.length, text.start, jmcf->file, jmcf->line);
+ return NGX_CONF_ERROR;
+ }
+
+ value = njs_vm_object_prop(jmcf->vm, njs_value_arg(&exception),
+ &file_name_key, &lvalue);
+ if (value == NULL) {
+ value = njs_vm_object_prop(jmcf->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;
+ 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;
+ }
+ }
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "%*s", text.length,
+ text.start);
return NGX_CONF_ERROR;
}
if (start != end) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "extra characters in js script: \"%*s\", included",
- end - start, start);
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "extra characters in js script: \"%*s\"",
+ end - start, start);
return NGX_CONF_ERROR;
}
@@ -1498,6 +1584,131 @@ ngx_stream_js_include(ngx_conf_t *cf, ng
static char *
+ngx_stream_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_stream_js_main_conf_t *jmcf = conf;
+
+ if (jmcf->imports != NGX_CONF_UNSET_PTR) {
+ return "is incompatible with \"js_import\"";
+ }
+
+ jmcf->file = cf->conf_file->file.name.data;
+ jmcf->line = cf->conf_file->line;
+
+ return ngx_conf_set_str_slot(cf, cmd, conf);
+}
+
+
+static char *
+ngx_stream_js_import(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_stream_js_main_conf_t *jmcf = conf;
+
+ u_char *p, *end, c;
+ ngx_int_t from;
+ ngx_str_t *value, name, path;
+ ngx_stream_js_import_t *import;
+
+ if (jmcf->include.len != 0) {
+ return "is incompatible with \"js_include\"";
+ }
+
+ value = cf->args->elts;
+ from = (cf->args->nelts == 4);
+
+ if (from) {
+ if (ngx_strcmp(value[2].data, "from") != 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[2]);
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ name = value[1];
+ path = (from ? value[3] : value[1]);
+
+ if (!from) {
+ end = name.data + name.len;
+
+ for (p = end - 1; p >= name.data; p--) {
+ if (*p == '/') {
+ break;
+ }
+ }
+
+ name.data = p + 1;
+ name.len = end - p - 1;
+
+ if (name.len < 3
+ || ngx_memcmp(&name.data[name.len - 3], ".js", 3) != 0)
+ {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "cannot extract export name from file path "
+ "\"%V\", use extended \"from\" syntax", &path);
+ return NGX_CONF_ERROR;
+ }
+
+ name.len -= 3;
+ }
+
+ if (name.len == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty \"name\" parameter");
+ return NGX_CONF_ERROR;
+ }
+
+ p = name.data;
+ end = name.data + name.len;
+
+ while (p < end) {
+ c = ngx_tolower(*p);
+
+ if (*p != '_' && (c < 'a' || c > 'z')) {
+ if (p == name.data) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "cannot start "
+ "with \"%c\" in export name \"%V\"", *p,
+ &name);
+ return NGX_CONF_ERROR;
+ }
+
+ if (*p < '0' || *p > '9') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid character "
+ "\"%c\" in export name \"%V\"", *p, &name);
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ p++;
+ }
+
+ if (ngx_strchr(path.data, '\'') != NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid character \"'\" "
+ "in file path \"%V\"", &path);
+ return NGX_CONF_ERROR;
+ }
+
+ if (jmcf->imports == NGX_CONF_UNSET_PTR) {
+ jmcf->imports = ngx_array_create(cf->pool, 4,
+ sizeof(ngx_stream_js_import_t));
+ if (jmcf->imports == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ import = ngx_array_push(jmcf->imports);
+ if (import == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ import->name = name;
+ import->path = path;
+ import->file = cf->conf_file->file.name.data;
+ import->line = cf->conf_file->line;
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
ngx_stream_js_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_str_t *value, *fname;
@@ -1547,10 +1758,14 @@ ngx_stream_js_create_main_conf(ngx_conf_
* set by ngx_pcalloc():
*
* conf->vm = NULL;
+ * conf->include = { 0, NULL };
More information about the nginx-devel
mailing list