Skip to content

Commit

Permalink
Modules: introduced QuickJS engine.
Browse files Browse the repository at this point in the history
"js_engine" directive is introduced which sets JavaScript engine.
When the module is built with QuickJS library "js_engine qjs;" sets
QuickJS engine for the current block. By default njs engine is used.

For example,

nginx.conf:

    location /a {
        js_engine qjs;
        # will be handled by QuickJS
        js_content main.handler;
    }

    location /b {
        # will be handled by njs
        js_content main.handler;
    }

QuickJS engine implements drop-in replacement for nginx/njs objects
with the following exceptions:

    * nginx module API to be added later: ngx.fetch(), ngx.shared.dict.
    * Built-in modules to be added later: fs, crypto, WebCrypto, xml.
    * NJS specific API: njs.dump(), njs.on(), console.dump().
    * js_preload_object directive.
  • Loading branch information
xeioex committed Sep 18, 2024
1 parent 9b67441 commit 201b127
Show file tree
Hide file tree
Showing 30 changed files with 6,751 additions and 259 deletions.
65 changes: 65 additions & 0 deletions .github/workflows/check-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,68 @@ jobs:
TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
TEST_NGINX_GLOBALS: "load_module ${{ github.workspace }}/nginx-source/objs/ngx_http_js_module.so; load_module ${{ github.workspace }}/nginx-source/objs/ngx_stream_js_module.so;"
TEST_NGINX_VERBOSE: 1

- name: Create LSAN suppression file
run: |
cat << EOF > lsan_suppressions.txt
leak:ngx_event_process_init
EOF
- name: Configure and build nginx and njs modules with quickjs, static modules
run: |
cd nginx-source
$NGINX_CONFIGURE_CMD --with-cc-opt="$CC_OPT -I${{ github.workspace }}/quickjs -fsanitize=address" --with-ld-opt="$LD_OPT -L${{ github.workspace }}/quickjs -fsanitize=address" --add-module=../nginx || cat objs/autoconf.err
$MAKE_UTILITY -j$(nproc)
- name: Test njs modules, static modules
run: |
ulimit -c unlimited
prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
env:
TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
TEST_NGINX_VERBOSE: 1
ASAN_OPTIONS: "detect_odr_violation=0:report_globals=0"
LSAN_OPTIONS: "suppressions=${{ github.workspace }}/lsan_suppressions.txt"

- name: Test njs modules (js_engine qjs), static modules
run: |
ulimit -c unlimited
prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
env:
TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
TEST_NGINX_GLOBALS_HTTP: "js_engine qjs;"
TEST_NGINX_GLOBALS_STREAM: "js_engine qjs;"
TEST_NGINX_VERBOSE: 1
ASAN_OPTIONS: "detect_odr_violation=0:report_globals=0"
LSAN_OPTIONS: "suppressions=${{ github.workspace }}/lsan_suppressions.txt"

- name: Configure and build nginx and njs modules with quickjs, dynamic modules
run: |
cd nginx-source
$NGINX_CONFIGURE_CMD --with-debug --with-cc-opt="$CC_OPT -I${{ github.workspace }}/quickjs -fsanitize=address" --with-ld-opt="$LD_OPT -L${{ github.workspace }}/quickjs -fsanitize=address" --add-dynamic-module=../nginx || cat objs/autoconf.err
$MAKE_UTILITY -j$(nproc) modules
$MAKE_UTILITY -j$(nproc)
- name: Test njs modules, dynamic modules
run: |
ulimit -c unlimited
prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
env:
TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
TEST_NGINX_GLOBALS: "load_module ${{ github.workspace }}/nginx-source/objs/ngx_http_js_module.so; load_module ${{ github.workspace }}/nginx-source/objs/ngx_stream_js_module.so;"
TEST_NGINX_VERBOSE: 1
ASAN_OPTIONS: "detect_odr_violation=0:report_globals=0:fast_unwind_on_malloc=0"
LSAN_OPTIONS: "suppressions=${{ github.workspace }}/lsan_suppressions.txt"

- name: Test njs modules (js_engine qjs), dynamic modules
run: |
ulimit -c unlimited
prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
env:
TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
TEST_NGINX_GLOBALS: "load_module ${{ github.workspace }}/nginx-source/objs/ngx_stream_js_module.so; load_module ${{ github.workspace }}/nginx-source/objs/ngx_http_js_module.so;"
TEST_NGINX_GLOBALS_HTTP: "js_engine qjs;"
TEST_NGINX_GLOBALS_STREAM: "js_engine qjs;"
TEST_NGINX_VERBOSE: 1
ASAN_OPTIONS: "detect_odr_violation=0:report_globals=0:fast_unwind_on_malloc=0"
LSAN_OPTIONS: "suppressions=${{ github.workspace }}/lsan_suppressions.txt"
100 changes: 92 additions & 8 deletions nginx/config
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ ngx_addon_name="ngx_js_module"
NJS_OPENSSL=${NJS_OPENSSL:-YES}
NJS_LIBXSLT=${NJS_LIBXSLT:-YES}
NJS_ZLIB=${NJS_ZLIB:-YES}
NJS_QUICKJS=${NJS_QUICKJS:-YES}

NJS_DEPS="$ngx_addon_dir/ngx_js.h \
$ngx_addon_dir/ngx_js_fetch.h \
Expand All @@ -12,9 +13,78 @@ NJS_SRCS="$ngx_addon_dir/ngx_js.c \
$ngx_addon_dir/ngx_js_regex.c \
$ngx_addon_dir/ngx_js_shared_dict.c"

QJS_DEPS=""
QJS_SRCS=""

NJS_OPENSSL_LIB=
NJS_XSLT_LIB=
NJS_ZLIB_LIB=
NJS_QUICKJS_LIB=
NJS_QUICKJS_INC=
NJS_HAVE_QUICKJS=

if [ $NJS_QUICKJS != NO ]; then

ngx_feature="QuickJS library -lquickjs.lto"
ngx_feature_name=NJS_HAVE_QUICKJS
ngx_feature_run=yes
ngx_feature_incs="#if defined(__GNUC__) && (__GNUC__ >= 8)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored \"-Wcast-function-type\"
#endif

#include <quickjs.h>"
ngx_feature_path=""
ngx_feature_libs="-lquickjs.lto -lm -ldl -lpthread"
ngx_feature_test="JSRuntime *rt;

rt = JS_NewRuntime();
(void) JS_GetClassID;
JS_FreeRuntime(rt);
return 0;"
. auto/feature

if [ $ngx_found = no ]; then
ngx_feature="QuickJS library -lquickjs"
ngx_feature_libs="-lquickjs -lm -ldl -lpthread"

. auto/feature
fi

if [ $ngx_found = no ]; then
ngx_feature="QuickJS library -I/usr/include/quickjs/ -L/usr/lib/quickjs/ -lquickjs.lto"
ngx_feature_path="/usr/include/quickjs/"
ngx_feature_libs="-L/usr/lib/quickjs/ -lquickjs.lto -lm -ldl -lpthread"

. auto/feature
fi

if [ $ngx_found = no ]; then
ngx_feature="QuickJS library -I/usr/include/quickjs/ -L/usr/lib/quickjs/ -lquickjs"
ngx_feature_libs="-L/usr/lib/quickjs/ -lquickjs -lm -ldl -lpthread"

. auto/feature
fi

if [ $ngx_found = yes ]; then

ngx_feature="QuickJS JS_NewTypedArray()"
ngx_feature_test="(void) JS_NewTypedArray;
return 0;"

. auto/feature

if [ $ngx_found = yes ]; then
have=NJS_HAVE_QUICKJS_NEW_TYPED_ARRAY . auto/have
fi

NJS_HAVE_QUICKJS=YES
NJS_QUICKJS_LIB="$ngx_feature_libs"
NJS_QUICKJS_INC="$ngx_feature_path"

echo " enabled QuickJS engine"
fi
fi

if [ $NJS_OPENSSL != NO ]; then
NJS_OPENSSL_LIB=OPENSSL
Expand All @@ -37,17 +107,30 @@ if [ $NJS_ZLIB != NO ]; then
have=NJS_HAVE_ZLIB . auto/have
NJS_SRCS="$NJS_SRCS $ngx_addon_dir/../external/njs_zlib_module.c"

if [ "$NJS_HAVE_QUICKJS" = "YES" ]; then
NJS_SRCS="$NJS_SRCS $ngx_addon_dir/../external/qjs_zlib_module.c"
fi

echo " enabled zlib module"
fi


NJS_ENGINE_DEP="$ngx_addon_dir/../build/libnjs.a"
NJS_ENGINE_LIB="$ngx_addon_dir/../build/libnjs.a"
if [ "$NJS_HAVE_QUICKJS" = "YES" ]; then
NJS_ENGINE_DEP="$ngx_addon_dir/../build/libqjs.a"
NJS_ENGINE_LIB="$ngx_addon_dir/../build/libnjs.a $ngx_addon_dir/../build/libqjs.a"
fi

if [ $HTTP != NO ]; then
ngx_module_type=HTTP_AUX_FILTER
ngx_module_name=ngx_http_js_module
ngx_module_incs="$ngx_addon_dir/../src $ngx_addon_dir/../build"
ngx_module_deps="$ngx_addon_dir/../build/libnjs.a $NJS_DEPS"
ngx_module_srcs="$ngx_addon_dir/ngx_http_js_module.c $NJS_SRCS"
ngx_module_incs="$ngx_addon_dir/../src $ngx_addon_dir/../build \
$NJS_QUICKJS_INC"
ngx_module_deps="$NJS_ENGINE_DEP $NJS_DEPS $QJS_DEPS"
ngx_module_srcs="$ngx_addon_dir/ngx_http_js_module.c $NJS_SRCS $QJS_SRCS"
ngx_module_libs="PCRE $NJS_OPENSSL_LIB $NJS_XSLT_LIB $NJS_ZLIB_LIB \
$ngx_addon_dir/../build/libnjs.a -lm"
$NJS_QUICKJS_LIB $NJS_ENGINE_LIB -lm"

. auto/module

Expand All @@ -59,11 +142,12 @@ fi
if [ $STREAM != NO ]; then
ngx_module_type=STREAM
ngx_module_name=ngx_stream_js_module
ngx_module_incs="$ngx_addon_dir/../src $ngx_addon_dir/../build"
ngx_module_deps="$ngx_addon_dir/../build/libnjs.a $NJS_DEPS"
ngx_module_srcs="$ngx_addon_dir/ngx_stream_js_module.c $NJS_SRCS"
ngx_module_incs="$ngx_addon_dir/../src $ngx_addon_dir/../build \
$NJS_QUICKJS_INC"
ngx_module_deps="$NJS_ENGINE_DEP $NJS_DEPS $QJS_DEPS"
ngx_module_srcs="$ngx_addon_dir/ngx_stream_js_module.c $NJS_SRCS $QJS_SRCS"
ngx_module_libs="PCRE $NJS_OPENSSL_LIB $NJS_XSLT_LIB $NJS_ZLIB_LIB \
$ngx_addon_dir/../build/libnjs.a -lm"
$NJS_QUICKJS_LIB $NJS_ENGINE_LIB -lm"

. auto/module
fi
10 changes: 9 additions & 1 deletion nginx/config.make
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@ cat << END >> $NGX_MAKEFILE
$ngx_addon_dir/../build/libnjs.a: $NGX_MAKEFILE
cd $ngx_addon_dir/.. \\
&& if [ -f build/Makefile ]; then \$(MAKE) clean; fi \\
&& CFLAGS="\$(CFLAGS)" CC="\$(CC)" ./configure --no-openssl --no-libxml2 --no-zlib --no-pcre \\
&& CFLAGS="\$(CFLAGS)" CC="\$(CC)" ./configure --no-openssl \\
--no-libxml2 --no-zlib --no-pcre --no-quickjs \\
&& \$(MAKE) libnjs

$ngx_addon_dir/../build/libqjs.a: $NGX_MAKEFILE
cd $ngx_addon_dir/.. \\
&& if [ -f build/Makefile ]; then \$(MAKE) clean; fi \\
&& CFLAGS="\$(CFLAGS)" CC="\$(CC)" ./configure --no-openssl \\
--no-libxml2 --no-zlib --no-pcre \\
&& \$(MAKE) libnjs libqjs

END
Loading

0 comments on commit 201b127

Please sign in to comment.