[njs] Refactor modules using external prototypes.

Dmitry Volyntsev xeioex at nginx.com
Tue Dec 21 17:46:06 UTC 2021


details:   https://hg.nginx.org/njs/rev/4d4657128baf
branches:  
changeset: 1772:4d4657128baf
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue Dec 21 17:42:26 2021 +0000
description:
Refactor modules using external prototypes.

diffstat:

 auto/init                     |     3 +
 auto/make                     |    45 +-
 auto/module                   |     6 +
 auto/modules                  |    34 +
 auto/options                  |     2 +
 auto/sources                  |     4 -
 configure                     |     1 +
 external/njs_crypto.c         |   650 ++++++++
 external/njs_fs.c             |  3094 +++++++++++++++++++++++++++++++++++++++++
 external/njs_query_string.c   |   971 ++++++++++++
 external/njs_webcrypto.c      |    13 +-
 external/njs_webcrypto.h      |    15 -
 nginx/config                  |     3 +-
 nginx/config.make             |     2 +-
 nginx/ngx_http_js_module.c    |     1 +
 nginx/ngx_js.c                |    16 +-
 nginx/ngx_js.h                |     3 +
 nginx/ngx_stream_js_module.c  |     1 +
 src/njs.h                     |     9 +
 src/njs_buffer.c              |   128 +-
 src/njs_buffer.h              |     1 -
 src/njs_builtin.c             |   118 +-
 src/njs_crypto.c              |   693 ---------
 src/njs_crypto.h              |    16 -
 src/njs_fs.c                  |  2946 ---------------------------------------
 src/njs_fs.h                  |    16 -
 src/njs_main.h                |     4 -
 src/njs_module.c              |    60 +-
 src/njs_module.h              |     4 +-
 src/njs_query_string.c        |   924 ------------
 src/njs_query_string.h        |    12 -
 src/njs_shell.c               |    41 +-
 src/njs_value.h               |     2 -
 src/njs_vm.c                  |    25 +-
 src/njs_vm.h                  |     4 -
 src/test/njs_externals_test.c |    14 -
 src/test/njs_unit_test.c      |    12 +-
 37 files changed, 5042 insertions(+), 4851 deletions(-)

diffs (truncated from 10539 to 1000 lines):

diff -r bea31b350b5e -r 4d4657128baf auto/init
--- a/auto/init	Tue Dec 21 15:49:21 2021 +0000
+++ b/auto/init	Tue Dec 21 17:42:26 2021 +0000
@@ -20,6 +20,9 @@ NJS_AUTOCONF_ERR=$NJS_BUILD_DIR/autoconf
 NJS_AUTO_CONFIG_H=$NJS_BUILD_DIR/njs_auto_config.h
 NJS_MAKEFILE=$NJS_BUILD_DIR/Makefile
 
+NJS_LIB_MODULES=
+NJS_LIB_INCS="src $NJS_BUILD_DIR"
+
 test -d $NJS_BUILD_DIR || mkdir $NJS_BUILD_DIR
 
 > $NJS_AUTOCONF_ERR
diff -r bea31b350b5e -r 4d4657128baf auto/make
--- a/auto/make	Tue Dec 21 15:49:21 2021 +0000
+++ b/auto/make	Tue Dec 21 17:42:26 2021 +0000
@@ -7,11 +7,44 @@
 echo "creating $NJS_MAKEFILE"
 
 mkdir -p $NJS_BUILD_DIR/src
+mkdir -p $NJS_BUILD_DIR/build
+mkdir -p $NJS_BUILD_DIR/external
 mkdir -p $NJS_BUILD_DIR/test
 
+njs_modules_c=$NJS_BUILD_DIR/njs_modules.c
+
+NJS_LIB_SRCS="$NJS_LIB_SRCS $njs_modules_c"
+
+njs_incs=`echo $NJS_LIB_INCS \
+        | sed -e "s# *\([^ ]*\)#$njs_regex_cont-I\1#g"`
 njs_objs=`echo $NJS_LIB_SRCS \
         | sed -e "s# *\([^ ]*\.\)c#$NJS_BUILD_DIR/\1o$njs_regex_cont#g"`
 
+cat << END                                    > $njs_modules_c
+
+#include <njs_main.h>
+
+END
+
+for mod in $NJS_LIB_MODULES
+do
+    echo "extern njs_module_t  $mod;"         >> $njs_modules_c
+done
+
+echo                                          >> $njs_modules_c
+echo 'njs_module_t *njs_modules[] = {'        >> $njs_modules_c
+
+for mod in $NJS_LIB_MODULES
+do
+    echo "    &$mod,"                         >> $njs_modules_c
+done
+
+cat << END                                    >> $njs_modules_c
+    NULL
+};
+
+END
+
 cat << END > $NJS_MAKEFILE
 
 # This file is auto-generated by configure
@@ -28,8 +61,7 @@ NPM = npm
 
 default: njs
 
-NJS_LIB_INCS = -Isrc -I$NJS_BUILD_DIR
-
+NJS_LIB_INCS = $njs_incs
 NJS_LIB_OBJS = $njs_objs
 
 libnjs: $NJS_BUILD_DIR/libnjs.a
@@ -46,9 +78,8 @@ END
 
 for njs_src in $NJS_LIB_SRCS
 do
-    fname=$(basename $njs_src)
-    njs_obj="src/${fname%.c}.o"
-    njs_dep="src/${fname%.c}.dep"
+    njs_obj="${njs_src%.c}.o"
+    njs_dep="${njs_src%.c}.dep"
     njs_dep_flags=`njs_gen_dep_flags $njs_dep $njs_obj`
     njs_dep_post=`njs_gen_dep_post $njs_dep $njs_obj`
     cat << END >> $NJS_MAKEFILE
@@ -73,7 +104,7 @@ cat << END >> $NJS_MAKEFILE
 
 $NJS_BUILD_DIR/njs: \\
 	$NJS_BUILD_DIR/libnjs.a \\
-	src/njs_shell.c external/njs_webcrypto.h external/njs_webcrypto.c
+	src/njs_shell.c
 	\$(NJS_LINK) -o $NJS_BUILD_DIR/njs \$(NJS_CFLAGS) \\
 		$NJS_LIB_AUX_CFLAGS \$(NJS_LIB_INCS) -Injs \\
 		src/njs_shell.c \\
@@ -143,7 +174,7 @@ njs_dep_post=`njs_gen_dep_post $njs_dep 
 cat << END >> $NJS_MAKEFILE
 
 $NJS_BUILD_DIR/$njs_externals_obj: \\
-    $njs_src external/njs_webcrypto.h external/njs_webcrypto.c
+    $njs_src external/njs_webcrypto.c
 	\$(NJS_CC) -c \$(NJS_CFLAGS) $NJS_LIB_AUX_CFLAGS \\
 		\$(NJS_LIB_INCS) -Injs \\
 		-o $NJS_BUILD_DIR/$njs_externals_obj \\
diff -r bea31b350b5e -r 4d4657128baf auto/module
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/auto/module	Tue Dec 21 17:42:26 2021 +0000
@@ -0,0 +1,6 @@
+# Copyright (C) Dmitry Volyntsev
+# Copyright (C) NGINX, Inc.
+
+NJS_LIB_MODULES="$NJS_LIB_MODULES $njs_module_name"
+NJS_LIB_SRCS="$NJS_LIB_SRCS $njs_module_srcs"
+NJS_LIB_INCS="$NJS_LIB_INCS $njs_module_incs"
diff -r bea31b350b5e -r 4d4657128baf auto/modules
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/auto/modules	Tue Dec 21 17:42:26 2021 +0000
@@ -0,0 +1,34 @@
+# Copyright (C) Dmitry Volyntsev
+# Copyright (C) NGINX, Inc.
+
+njs_module_name=njs_buffer_module
+njs_module_incs=
+njs_module_srcs=src/njs_buffer.c
+
+. auto/module
+
+njs_module_name=njs_crypto_module
+njs_module_incs=
+njs_module_srcs=external/njs_crypto.c
+
+. auto/module
+
+if [ $NJS_WEBCRYPTO = YES -a $NJS_HAVE_OPENSSL = YES ]; then
+	njs_module_name=njs_webcrypto_module
+	njs_module_incs=
+	njs_module_srcs=external/njs_webcrypto.c
+
+	. auto/module
+fi
+
+njs_module_name=njs_fs_module
+njs_module_incs=
+njs_module_srcs=external/njs_fs.c
+
+. auto/module
+
+njs_module_name=njs_query_string_module
+njs_module_incs=
+njs_module_srcs=external/njs_query_string.c
+
+. auto/module
diff -r bea31b350b5e -r 4d4657128baf auto/options
--- a/auto/options	Tue Dec 21 15:49:21 2021 +0000
+++ b/auto/options	Tue Dec 21 17:42:26 2021 +0000
@@ -11,6 +11,7 @@ NJS_DEBUG_MEMORY=NO
 NJS_ADDRESS_SANITIZER=NO
 NJS_TEST262=YES
 
+NJS_WEBCRYPTO=YES
 NJS_TRY_PCRE2=YES
 
 NJS_CONFIGURE_OPTIONS=
@@ -33,6 +34,7 @@ do
         --debug-memory=*)                NJS_DEBUG_MEMORY="$value"           ;;
         --test262=*)                     NJS_TEST262="$value"                ;;
 
+        --no-webcrypto)                  NJS_WEBCRYPTO=NO                    ;;
         --no-pcre2)                      NJS_TRY_PCRE2=NO                    ;;
 
         --help)
diff -r bea31b350b5e -r 4d4657128baf auto/sources
--- a/auto/sources	Tue Dec 21 15:49:21 2021 +0000
+++ b/auto/sources	Tue Dec 21 17:42:26 2021 +0000
@@ -42,8 +42,6 @@ NJS_LIB_SRCS=" \
    src/njs_timer.c \
    src/njs_module.c \
    src/njs_event.c \
-   src/njs_fs.c \
-   src/njs_crypto.c \
    src/njs_extern.c \
    src/njs_variable.c \
    src/njs_builtin.c \
@@ -55,9 +53,7 @@ NJS_LIB_SRCS=" \
    src/njs_array_buffer.c \
    src/njs_typed_array.c \
    src/njs_promise.c \
-   src/njs_query_string.c \
    src/njs_encoding.c \
-   src/njs_buffer.c \
    src/njs_iterator.c \
    src/njs_scope.c \
    src/njs_async.c \
diff -r bea31b350b5e -r 4d4657128baf configure
--- a/configure	Tue Dec 21 15:49:21 2021 +0000
+++ b/configure	Tue Dec 21 17:42:26 2021 +0000
@@ -35,6 +35,7 @@ NJS_LIB_AUX_CFLAGS="$NJS_PCRE_CFLAGS"
 NJS_LIBS="$NJS_LIBRT"
 NJS_LIB_AUX_LIBS="$NJS_PCRE_LIB $NJS_OPENSSL_LIB"
 
+. auto/modules
 . auto/make
 
 . auto/expect
diff -r bea31b350b5e -r 4d4657128baf external/njs_crypto.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/external/njs_crypto.c	Tue Dec 21 17:42:26 2021 +0000
@@ -0,0 +1,650 @@
+
+/*
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) NGINX, Inc.
+ */
+
+
+#include <njs_main.h>
+
+
+typedef void (*njs_hash_init)(void *ctx);
+typedef void (*njs_hash_update)(void *ctx, const void *data, size_t size);
+typedef void (*njs_hash_final)(u_char *result, void *ctx);
+
+typedef njs_int_t (*njs_digest_encode)(njs_vm_t *vm, njs_value_t *value,
+    const njs_str_t *src);
+
+
+typedef struct {
+    njs_str_t           name;
+
+    size_t              size;
+    njs_hash_init       init;
+    njs_hash_update     update;
+    njs_hash_final      final;
+} njs_hash_alg_t;
+
+typedef struct {
+    union {
+        njs_md5_t       md5;
+        njs_sha1_t      sha1;
+        njs_sha2_t      sha2;
+    } u;
+
+    njs_hash_alg_t      *alg;
+} njs_digest_t;
+
+typedef struct {
+    u_char              opad[64];
+
+    union {
+        njs_md5_t       md5;
+        njs_sha1_t      sha1;
+        njs_sha2_t      sha2;
+    } u;
+
+    njs_hash_alg_t      *alg;
+} njs_hmac_t;
+
+
+typedef struct {
+    njs_str_t             name;
+
+    njs_digest_encode     encode;
+} njs_crypto_enc_t;
+
+
+static njs_hash_alg_t *njs_crypto_algorithm(njs_vm_t *vm,
+    const njs_value_t *value);
+static njs_crypto_enc_t *njs_crypto_encoding(njs_vm_t *vm,
+    const njs_value_t *value);
+static njs_int_t njs_buffer_digest(njs_vm_t *vm, njs_value_t *value,
+    const njs_str_t *src);
+static njs_int_t njs_crypto_create_hash(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t unused);
+static njs_int_t njs_hash_prototype_update(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t hmac);
+static njs_int_t njs_hash_prototype_digest(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t hmac);
+static njs_int_t njs_crypto_create_hmac(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t unused);
+
+static njs_int_t njs_crypto_init(njs_vm_t *vm);
+
+
+static njs_hash_alg_t njs_hash_algorithms[] = {
+
+   {
+     njs_str("md5"),
+     16,
+     (njs_hash_init) njs_md5_init,
+     (njs_hash_update) njs_md5_update,
+     (njs_hash_final) njs_md5_final
+   },
+
+   {
+     njs_str("sha1"),
+     20,
+     (njs_hash_init) njs_sha1_init,
+     (njs_hash_update) njs_sha1_update,
+     (njs_hash_final) njs_sha1_final
+   },
+
+   {
+     njs_str("sha256"),
+     32,
+     (njs_hash_init) njs_sha2_init,
+     (njs_hash_update) njs_sha2_update,
+     (njs_hash_final) njs_sha2_final
+   },
+
+   {
+    njs_null_str,
+    0,
+    NULL,
+    NULL,
+    NULL
+   }
+
+};
+
+
+static njs_crypto_enc_t njs_encodings[] = {
+
+   {
+     njs_str("buffer"),
+     njs_buffer_digest
+   },
+
+   {
+     njs_str("hex"),
+     njs_string_hex
+   },
+
+   {
+     njs_str("base64"),
+     njs_string_base64
+   },
+
+   {
+     njs_str("base64url"),
+     njs_string_base64url
+   },
+
+   {
+    njs_null_str,
+    NULL
+   }
+};
+
+
+static njs_external_t  njs_ext_crypto_hash[] = {
+
+    {
+        .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
+        .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
+        .u.property = {
+            .value = "Hash",
+        }
+    },
+
+    {
+        .flags = NJS_EXTERN_METHOD,
+        .name.string = njs_str("update"),
+        .writable = 1,
+        .configurable = 1,
+        .u.method = {
+            .native = njs_hash_prototype_update,
+            .magic8 = 0,
+        }
+    },
+
+    {
+        .flags = NJS_EXTERN_METHOD,
+        .name.string = njs_str("digest"),
+        .writable = 1,
+        .configurable = 1,
+        .u.method = {
+            .native = njs_hash_prototype_digest,
+            .magic8 = 0,
+        }
+    },
+
+    {
+        .flags = NJS_EXTERN_METHOD,
+        .name.string = njs_str("constructor"),
+        .writable = 1,
+        .configurable = 1,
+        .u.method = {
+            .native = njs_crypto_create_hash,
+        }
+    },
+};
+
+
+static njs_external_t  njs_ext_crypto_hmac[] = {
+
+    {
+        .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
+        .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
+        .u.property = {
+            .value = "Hmac",
+        }
+    },
+
+    {
+        .flags = NJS_EXTERN_METHOD,
+        .name.string = njs_str("update"),
+        .writable = 1,
+        .configurable = 1,
+        .u.method = {
+            .native = njs_hash_prototype_update,
+            .magic8 = 1,
+        }
+    },
+
+    {
+        .flags = NJS_EXTERN_METHOD,
+        .name.string = njs_str("digest"),
+        .writable = 1,
+        .configurable = 1,
+        .u.method = {
+            .native = njs_hash_prototype_digest,
+            .magic8 = 1,
+        }
+    },
+
+    {
+        .flags = NJS_EXTERN_METHOD,
+        .name.string = njs_str("constructor"),
+        .writable = 1,
+        .configurable = 1,
+        .u.method = {
+            .native = njs_crypto_create_hmac,
+            .magic8 = 0,
+        }
+    },
+};
+
+
+static njs_external_t  njs_ext_crypto_crypto[] = {
+
+    {
+        .flags = NJS_EXTERN_METHOD,
+        .name.string = njs_str("createHash"),
+        .writable = 1,
+        .configurable = 1,
+        .enumerable = 1,
+        .u.method = {
+            .native = njs_crypto_create_hash,
+            .magic8 = 0,
+        }
+    },
+
+    {
+        .flags = NJS_EXTERN_METHOD,
+        .name.string = njs_str("createHmac"),
+        .writable = 1,
+        .configurable = 1,
+        .enumerable = 1,
+        .u.method = {
+            .native = njs_crypto_create_hmac,
+            .magic8 = 0,
+        }
+    },
+};
+
+
+static njs_int_t    njs_crypto_hash_proto_id;
+static njs_int_t    njs_crypto_hmac_proto_id;
+
+
+njs_module_t  njs_crypto_module = {
+    .name = njs_str("crypto"),
+    .init = njs_crypto_init,
+};
+
+
+static njs_int_t
+njs_crypto_create_hash(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
+{
+    njs_digest_t    *dgst;
+    njs_hash_alg_t  *alg;
+
+    alg = njs_crypto_algorithm(vm, njs_arg(args, nargs, 1));
+    if (njs_slow_path(alg == NULL)) {
+        return NJS_ERROR;
+    }
+
+    dgst = njs_mp_alloc(vm->mem_pool, sizeof(njs_digest_t));
+    if (njs_slow_path(dgst == NULL)) {
+        njs_memory_error(vm);
+        return NJS_ERROR;
+    }
+
+    dgst->alg = alg;
+
+    alg->init(&dgst->u);
+
+    return njs_vm_external_create(vm, &vm->retval, njs_crypto_hash_proto_id,
+                                  dgst, 0);
+}
+
+
+static njs_int_t
+njs_hash_prototype_update(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t hmac)
+{
+    njs_str_t                    data;
+    njs_int_t                    ret;
+    njs_hmac_t                   *ctx;
+    njs_value_t                  *this, dst;
+    njs_digest_t                 *dgst;
+    njs_typed_array_t            *array;
+    const njs_value_t            *value;
+    njs_array_buffer_t           *buffer;
+    const njs_buffer_encoding_t  *encoding;
+
+    this = njs_argument(args, 0);
+
+    if (!hmac) {
+        dgst = njs_vm_external(vm, njs_crypto_hash_proto_id, this);
+        if (njs_slow_path(dgst == NULL)) {
+            njs_type_error(vm, "\"this\" is not a hash object");
+            return NJS_ERROR;
+        }
+
+        if (njs_slow_path(dgst->alg == NULL)) {
+            njs_error(vm, "Digest already called");
+            return NJS_ERROR;
+        }
+
+        ctx = NULL;
+
+    } else {
+        ctx = njs_vm_external(vm, njs_crypto_hmac_proto_id, this);
+        if (njs_slow_path(ctx == NULL)) {
+            njs_type_error(vm, "\"this\" is not a hmac object");
+            return NJS_ERROR;
+        }
+
+        if (njs_slow_path(ctx->alg == NULL)) {
+            njs_error(vm, "Digest already called");
+            return NJS_ERROR;
+        }
+
+        dgst = NULL;
+    }
+
+    value = njs_arg(args, nargs, 1);
+
+    switch (value->type) {
+    case NJS_STRING:
+        encoding = njs_buffer_encoding(vm, njs_arg(args, nargs, 2));
+        if (njs_slow_path(encoding == NULL)) {
+            return NJS_ERROR;
+        }
+
+        ret = njs_buffer_decode_string(vm, value, &dst, encoding);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return NJS_ERROR;
+        }
+
+        njs_string_get(&dst, &data);
+        break;
+
+    case NJS_TYPED_ARRAY:
+    case NJS_DATA_VIEW:
+        array = njs_typed_array(value);
+        buffer = array->buffer;
+        if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+            njs_type_error(vm, "detached buffer");
+            return NJS_ERROR;
+        }
+
+        data.start = &buffer->u.u8[array->offset];
+        data.length = array->byte_length;
+        break;
+
+    default:
+        njs_type_error(vm, "data argument \"%s\" is not a string "
+                       "or Buffer-like object", njs_type_string(value->type));
+
+        return NJS_ERROR;
+    }
+
+    if (!hmac) {
+        dgst->alg->update(&dgst->u, data.start, data.length);
+
+    } else {
+        ctx->alg->update(&ctx->u, data.start, data.length);
+    }
+
+    vm->retval = *this;
+
+    return NJS_OK;
+}
+
+
+static njs_int_t
+njs_hash_prototype_digest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t hmac)
+{
+    njs_str_t         str;
+    njs_hmac_t        *ctx;
+    njs_value_t       *this;
+    njs_digest_t      *dgst;
+    njs_hash_alg_t    *alg;
+    njs_crypto_enc_t  *enc;
+    u_char            hash1[32], digest[32];
+
+    this = njs_argument(args, 0);
+
+    if (!hmac) {
+        dgst = njs_vm_external(vm, njs_crypto_hash_proto_id, this);
+        if (njs_slow_path(dgst == NULL)) {
+            njs_type_error(vm, "\"this\" is not a hash object");
+            return NJS_ERROR;
+        }
+
+        if (njs_slow_path(dgst->alg == NULL)) {
+            goto exception;
+        }
+
+        ctx = NULL;
+
+    } else {
+        ctx = njs_vm_external(vm, njs_crypto_hmac_proto_id, this);
+        if (njs_slow_path(ctx == NULL)) {
+            njs_type_error(vm, "\"this\" is not a hmac object");
+            return NJS_ERROR;
+        }
+
+        if (njs_slow_path(ctx->alg == NULL)) {
+            goto exception;
+        }
+
+        dgst = NULL;
+    }
+
+    enc = njs_crypto_encoding(vm, njs_arg(args, nargs, 1));
+    if (njs_slow_path(enc == NULL)) {
+        return NJS_ERROR;
+    }
+
+    if (!hmac) {
+        alg = dgst->alg;
+        alg->final(digest, &dgst->u);
+        dgst->alg = NULL;
+
+    } else {
+        alg = ctx->alg;
+        alg->final(hash1, &ctx->u);
+
+        alg->init(&ctx->u);
+        alg->update(&ctx->u, ctx->opad, 64);
+        alg->update(&ctx->u, hash1, alg->size);
+        alg->final(digest, &ctx->u);
+        ctx->alg = NULL;
+    }
+
+    str.start = digest;
+    str.length = alg->size;
+
+    return enc->encode(vm, &vm->retval, &str);
+
+exception:
+
+    njs_error(vm, "Digest already called");
+    return NJS_ERROR;
+}
+
+
+static njs_int_t
+njs_crypto_create_hmac(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
+{
+    njs_str_t           key;
+    njs_uint_t          i;
+    njs_hmac_t          *ctx;
+    njs_hash_alg_t      *alg;
+    njs_typed_array_t   *array;
+    const njs_value_t   *value;
+    njs_array_buffer_t  *buffer;
+    u_char              digest[32], key_buf[64];
+
+    alg = njs_crypto_algorithm(vm, njs_arg(args, nargs, 1));
+    if (njs_slow_path(alg == NULL)) {
+        return NJS_ERROR;
+    }
+
+    value = njs_arg(args, nargs, 2);
+
+    switch (value->type) {
+    case NJS_STRING:
+        njs_string_get(value, &key);
+        break;
+
+    case NJS_TYPED_ARRAY:
+    case NJS_DATA_VIEW:
+        array = njs_typed_array(value);
+        buffer = array->buffer;
+        if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+            njs_type_error(vm, "detached buffer");
+            return NJS_ERROR;
+        }
+
+        key.start = &buffer->u.u8[array->offset];
+        key.length = array->byte_length;
+        break;
+
+    default:
+        njs_type_error(vm, "key argument \"%s\" is not a string "
+                       "or Buffer-like object", njs_type_string(value->type));
+
+        return NJS_ERROR;
+    }
+
+    ctx = njs_mp_alloc(vm->mem_pool, sizeof(njs_hmac_t));
+    if (njs_slow_path(ctx == NULL)) {
+        njs_memory_error(vm);
+        return NJS_ERROR;
+    }
+
+    ctx->alg = alg;
+
+    if (key.length > sizeof(key_buf)) {
+        alg->init(&ctx->u);
+        alg->update(&ctx->u, key.start, key.length);
+        alg->final(digest, &ctx->u);
+
+        memcpy(key_buf, digest, alg->size);
+        njs_explicit_memzero(key_buf + alg->size, sizeof(key_buf) - alg->size);
+
+    } else {
+        memcpy(key_buf, key.start, key.length);
+        njs_explicit_memzero(key_buf + key.length,
+                             sizeof(key_buf) - key.length);
+    }
+
+    for (i = 0; i < 64; i++) {
+        ctx->opad[i] = key_buf[i] ^ 0x5c;
+    }
+
+    for (i = 0; i < 64; i++) {
+         key_buf[i] ^= 0x36;
+    }
+
+    alg->init(&ctx->u);
+    alg->update(&ctx->u, key_buf, 64);
+
+    return njs_vm_external_create(vm, &vm->retval, njs_crypto_hmac_proto_id,
+                                  ctx, 0);
+}
+
+
+static njs_hash_alg_t *
+njs_crypto_algorithm(njs_vm_t *vm, const njs_value_t *value)
+{
+    njs_str_t       name;
+    njs_hash_alg_t  *e;
+
+    if (njs_slow_path(!njs_is_string(value))) {
+        njs_type_error(vm, "algorithm must be a string");
+        return NULL;
+    }
+
+    njs_string_get(value, &name);
+
+    for (e = &njs_hash_algorithms[0]; e->name.length != 0; e++) {
+        if (njs_strstr_eq(&name, &e->name)) {
+            return e;
+        }
+    }
+
+    njs_type_error(vm, "not supported algorithm: \"%V\"", &name);
+
+    return NULL;
+}
+
+
+static njs_crypto_enc_t *
+njs_crypto_encoding(njs_vm_t *vm, const njs_value_t *value)
+{
+    njs_str_t         name;
+    njs_crypto_enc_t  *e;
+
+    if (njs_slow_path(!njs_is_string(value))) {
+        if (njs_is_defined(value)) {
+            njs_type_error(vm, "encoding must be a string");
+            return NULL;
+        }
+
+        return &njs_encodings[0];
+    }
+
+    njs_string_get(value, &name);
+
+    for (e = &njs_encodings[1]; e->name.length != 0; e++) {
+        if (njs_strstr_eq(&name, &e->name)) {
+            return e;
+        }
+    }
+
+    njs_type_error(vm, "Unknown digest encoding: \"%V\"", &name);
+
+    return NULL;
+}
+
+
+static njs_int_t
+njs_buffer_digest(njs_vm_t *vm, njs_value_t *value, const njs_str_t *src)
+{
+    return njs_buffer_new(vm, value, src->start, src->length);
+}
+
+
+static njs_int_t
+njs_crypto_init(njs_vm_t *vm)
+{
+    njs_int_t           ret, proto_id;
+    njs_mod_t           *module;
+    njs_opaque_value_t  value;
+
+    njs_crypto_hash_proto_id =
+                     njs_vm_external_prototype(vm, njs_ext_crypto_hash,
+                                               njs_nitems(njs_ext_crypto_hash));
+    if (njs_slow_path(njs_crypto_hash_proto_id < 0)) {
+        return NJS_ERROR;
+    }
+
+    njs_crypto_hmac_proto_id =
+                     njs_vm_external_prototype(vm, njs_ext_crypto_hmac,
+                                               njs_nitems(njs_ext_crypto_hmac));
+    if (njs_slow_path(njs_crypto_hmac_proto_id < 0)) {
+        return NJS_ERROR;
+    }
+
+    proto_id = njs_vm_external_prototype(vm, njs_ext_crypto_crypto,
+                                         njs_nitems(njs_ext_crypto_crypto));
+    if (njs_slow_path(proto_id < 0)) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_vm_external_create(vm, njs_value_arg(&value), proto_id, NULL, 1);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    module = njs_module_add(vm, &njs_str_value("crypto"), 1);
+    if (njs_slow_path(module == NULL)) {
+        return NJS_ERROR;
+    }
+
+    njs_value_assign(&module->value, &value);
+    module->function.native = 1;
+
+    return NJS_OK;
+}
diff -r bea31b350b5e -r 4d4657128baf external/njs_fs.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/external/njs_fs.c	Tue Dec 21 17:42:26 2021 +0000
@@ -0,0 +1,3094 @@
+
+/*
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) NGINX, Inc.
+ */
+
+
+#include <njs_main.h>
+
+#include <dirent.h>
+
+#if (NJS_SOLARIS)
+
+#define DT_DIR         0
+#define DT_REG         1
+#define DT_CHR         2
+#define DT_LNK         3
+#define DT_BLK         4
+#define DT_FIFO        5
+#define DT_SOCK        6
+#define NJS_DT_INVALID 0xffffffff
+
+#define njs_dentry_type(_dentry)                                             \
+    (NJS_DT_INVALID)
+
+#else
+
+#define NJS_DT_INVALID 0xffffffff
+
+#define njs_dentry_type(_dentry)                                             \
+    ((_dentry)->d_type)
+
+#endif
+
+
+#define njs_fs_magic(calltype, mode)                                         \
+    (((mode) << 2) | calltype)
+
+#define njs_fs_magic2(field, type)                                           \
+    (((type) << 4) | field)
+
+
+typedef enum {
+    NJS_FS_DIRECT,
+    NJS_FS_PROMISE,
+    NJS_FS_CALLBACK,
+} njs_fs_calltype_t;
+
+
+typedef enum {
+    NJS_FS_TRUNC,
+    NJS_FS_APPEND,
+} njs_fs_writemode_t;
+
+
+typedef enum {
+    NJS_FS_STAT,
+    NJS_FS_LSTAT,
+} njs_fs_statmode_t;
+
+
+typedef struct {
+    njs_str_t       name;
+    int             value;
+} njs_fs_entry_t;
+
+
+typedef enum {
+    NJS_FTW_PHYS = 1,
+    NJS_FTW_MOUNT = 2,
+    NJS_FTW_DEPTH = 8,
+} njs_ftw_flags_t;
+
+
+typedef enum {
+    NJS_FTW_F,
+    NJS_FTW_D,
+    NJS_FTW_DNR,
+    NJS_FTW_NS,
+    NJS_FTW_SL,
+    NJS_FTW_DP,
+    NJS_FTW_SLN,
+} njs_ftw_type_t;
+
+
+typedef struct {
+    long tv_sec;
+    long tv_nsec;
+} njs_timespec_t;
+
+
+typedef struct {
+    uint64_t        st_dev;
+    uint64_t        st_mode;
+    uint64_t        st_nlink;
+    uint64_t        st_uid;
+    uint64_t        st_gid;
+    uint64_t        st_rdev;
+    uint64_t        st_ino;
+    uint64_t        st_size;
+    uint64_t        st_blksize;
+    uint64_t        st_blocks;
+    njs_timespec_t  st_atim;
+    njs_timespec_t  st_mtim;
+    njs_timespec_t  st_ctim;
+    njs_timespec_t  st_birthtim;
+} njs_stat_t;
+
+
+typedef enum {
+    NJS_FS_STAT_DEV,
+    NJS_FS_STAT_INO,
+    NJS_FS_STAT_MODE,
+    NJS_FS_STAT_NLINK,
+    NJS_FS_STAT_UID,
+    NJS_FS_STAT_GID,
+    NJS_FS_STAT_RDEV,
+    NJS_FS_STAT_SIZE,
+    NJS_FS_STAT_BLKSIZE,
+    NJS_FS_STAT_BLOCKS,
+    NJS_FS_STAT_ATIME,
+    NJS_FS_STAT_BIRTHTIME,
+    NJS_FS_STAT_CTIME,
+    NJS_FS_STAT_MTIME,
+} njs_stat_prop_t;
+
+
+typedef njs_int_t (*njs_file_tree_walk_cb_t)(const char *, const struct stat *,
+     njs_ftw_type_t);
+
+
+static njs_int_t njs_fs_access(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t calltype);
+static njs_int_t njs_fs_mkdir(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t calltype);
+static njs_int_t njs_fs_read(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t calltype);
+static njs_int_t njs_fs_readdir(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t calltype);
+static njs_int_t njs_fs_realpath(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t calltype);


More information about the nginx-devel mailing list