From xeioex at nginx.com Thu May 2 00:31:39 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Thu, 02 May 2024 00:31:39 +0000 Subject: [njs] QuickJS: added zlib module. Message-ID: details: https://hg.nginx.org/njs/rev/f146b5dc21cc branches: changeset: 2325:f146b5dc21cc user: Dmitry Volyntsev date: Wed May 01 17:31:01 2024 -0700 description: QuickJS: added zlib module. diffstat: auto/init | 1 + auto/make | 42 +- auto/qjs_module | 6 + auto/qjs_modules | 20 + auto/quickjs | 21 + auto/sources | 4 + configure | 3 +- external/njs_shell.c | 15 +- external/qjs_zlib_module.c | 512 +++++++++++++++++++ src/qjs.c | 109 ++++ src/qjs.h | 79 ++ src/qjs_buffer.c | 1174 ++++++++++++++++++++++++++++++++++++++++++++ src/test/njs_unit_test.c | 301 ----------- test/buffer.t.js | 236 ++++++++ test/harness/runTsuite.js | 10 +- test/setup | 2 +- test/zlib.t.mjs | 109 ++++ 17 files changed, 2322 insertions(+), 322 deletions(-) diffs (truncated from 2828 to 1000 lines): diff -r 18fc657411ca -r f146b5dc21cc auto/init --- a/auto/init Fri Apr 26 16:48:19 2024 -0700 +++ b/auto/init Wed May 01 17:31:01 2024 -0700 @@ -16,6 +16,7 @@ NJS_CFLAGS=${NJS_CFLAGS=} NJS_BUILD_DIR=${NJS_BUILD_DIR:-build} NJS_LIB_MODULES= +QJS_LIB_MODULES= NJS_LIBRT= diff -r 18fc657411ca -r f146b5dc21cc auto/make --- a/auto/make Fri Apr 26 16:48:19 2024 -0700 +++ b/auto/make Wed May 01 17:31:01 2024 -0700 @@ -15,11 +15,6 @@ njs_modules_c=$NJS_BUILD_DIR/njs_modules 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 @@ -45,6 +40,43 @@ cat << END END +if [ $NJS_HAVE_QUICKJS = YES ]; then + +qjs_modules_c=$NJS_BUILD_DIR/qjs_modules.c + +NJS_LIB_SRCS="$NJS_LIB_SRCS $qjs_modules_c" + +cat << END > $qjs_modules_c + +#include + +END + +for mod in $QJS_LIB_MODULES +do + echo "extern qjs_module_t $mod;" >> $qjs_modules_c +done + +echo >> $qjs_modules_c +echo 'qjs_module_t *qjs_modules[] = {' >> $qjs_modules_c + +for mod in $QJS_LIB_MODULES +do + echo " &$mod," >> $qjs_modules_c +done + +cat << END >> $qjs_modules_c + NULL +}; + +END +fi + +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_MAKEFILE # This file is auto-generated by configure diff -r 18fc657411ca -r f146b5dc21cc auto/qjs_module --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/auto/qjs_module Wed May 01 17:31:01 2024 -0700 @@ -0,0 +1,6 @@ +# Copyright (C) Dmitry Volyntsev +# Copyright (C) F5, Inc + +QJS_LIB_MODULES="$QJS_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 18fc657411ca -r f146b5dc21cc auto/qjs_modules --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/auto/qjs_modules Wed May 01 17:31:01 2024 -0700 @@ -0,0 +1,20 @@ +# Copyright (C) Dmitry Volyntsev +# Copyright (C) F5, Inc + +if [ $NJS_HAVE_QUICKJS = YES ]; then + + njs_module_name=qjs_buffer_module + njs_module_incs= + njs_module_srcs=src/qjs_buffer.c + + . auto/qjs_module + + if [ $NJS_ZLIB = YES -a $NJS_HAVE_ZLIB = YES ]; then + njs_module_name=qjs_zlib_module + njs_module_incs= + njs_module_srcs=external/qjs_zlib_module.c + + . auto/qjs_module + fi + +fi diff -r 18fc657411ca -r f146b5dc21cc auto/quickjs --- a/auto/quickjs Fri Apr 26 16:48:19 2024 -0700 +++ b/auto/quickjs Wed May 01 17:31:01 2024 -0700 @@ -25,6 +25,7 @@ if [ $NJS_TRY_QUICKJS = YES ]; then JSRuntime *rt; rt = JS_NewRuntime(); + (void) JS_GetClassID; JS_FreeRuntime(rt); return 0; }" @@ -54,6 +55,26 @@ if [ $NJS_TRY_QUICKJS = YES ]; then fi if [ $njs_found = yes ]; then + + njs_feature="QuickJS JS_NewTypedArray()" + njs_feature_test="#if defined(__GNUC__) && (__GNUC__ >= 8) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored \"-Wcast-function-type\" + #endif + + #include + + int main() { + (void) JS_NewTypedArray; + return 0; + }" + + . auto/feature + + if [ $njs_found = yes ]; then + njs_define=NJS_HAVE_QUICKJS_NEW_TYPED_ARRAY . auto/define + fi + NJS_HAVE_QUICKJS=YES NJS_QUICKJS_LIB="$njs_feature_libs" NJS_LIB_INCS="$NJS_LIB_INCS $njs_feature_incs" diff -r 18fc657411ca -r f146b5dc21cc auto/sources --- a/auto/sources Fri Apr 26 16:48:19 2024 -0700 +++ b/auto/sources Wed May 01 17:31:01 2024 -0700 @@ -72,6 +72,10 @@ if [ "$NJS_HAVE_LIBBFD" = "YES" -a "$NJS NJS_LIB_SRCS="$NJS_LIB_SRCS src/njs_addr2line.c" fi +if [ "$NJS_HAVE_QUICKJS" = "YES" ]; then + NJS_LIB_SRCS="$NJS_LIB_SRCS src/qjs.c" +fi + NJS_TS_SRCS=$(find ts/ -name "*.d.ts" -o -name "*.json") NJS_TEST_TS_SRCS=$(find test/ts/ -name "*.ts" -o -name "*.json") diff -r 18fc657411ca -r f146b5dc21cc configure --- a/configure Fri Apr 26 16:48:19 2024 -0700 +++ b/configure Wed May 01 17:31:01 2024 -0700 @@ -21,7 +21,7 @@ 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_INCS="src $NJS_BUILD_DIR" +NJS_LIB_INCS="src external $NJS_BUILD_DIR" test -d $NJS_BUILD_DIR || mkdir $NJS_BUILD_DIR @@ -59,6 +59,7 @@ NJS_LIB_AUX_LIBS= . auto/sources . auto/modules +. auto/qjs_modules . auto/make . auto/expect . auto/summary diff -r 18fc657411ca -r f146b5dc21cc external/njs_shell.c --- a/external/njs_shell.c Fri Apr 26 16:48:19 2024 -0700 +++ b/external/njs_shell.c Wed May 01 17:31:01 2024 -0700 @@ -12,18 +12,7 @@ #include #if (NJS_HAVE_QUICKJS) -#if defined(__GNUC__) && (__GNUC__ >= 8) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-function-type" -#endif - -#include - -#if defined(__GNUC__) && (__GNUC__ >= 8) -#pragma GCC diagnostic pop -#endif -#define NJS_QUICKJS_VERSION "Unknown version" -#include +#include #endif #if (!defined NJS_FUZZER_TARGET && defined NJS_HAVE_READLINE) @@ -2822,7 +2811,7 @@ njs_engine_qjs_init(njs_engine_t *engine return NJS_ERROR; } - engine->u.qjs.ctx = JS_NewContext(engine->u.qjs.rt); + engine->u.qjs.ctx = qjs_new_context(engine->u.qjs.rt); if (engine->u.qjs.ctx == NULL) { njs_stderror("JS_NewContext() failed\n"); return NJS_ERROR; diff -r 18fc657411ca -r f146b5dc21cc external/qjs_zlib_module.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/external/qjs_zlib_module.c Wed May 01 17:31:01 2024 -0700 @@ -0,0 +1,512 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) F5, Inc. + */ + +#include +#include + +#define NJS_ZLIB_CHUNK_SIZE 1024 + +static JSValue qjs_zlib_ext_deflate(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int raw); +static JSValue qjs_zlib_ext_inflate(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int raw); + +static JSModuleDef *qjs_zlib_init(JSContext *ctx, const char *name); +static void *qjs_zlib_alloc(void *opaque, u_int items, u_int size); +static void qjs_zlib_free(void *opaque, void *address); + + +static const JSCFunctionListEntry qjs_zlib_constants[] = { + JS_PROP_INT32_DEF("Z_NO_COMPRESSION", + Z_NO_COMPRESSION, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_BEST_SPEED", + Z_BEST_SPEED, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_BEST_COMPRESSION", + Z_BEST_COMPRESSION, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_FILTERED", + Z_FILTERED, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_HUFFMAN_ONLY", + Z_HUFFMAN_ONLY, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_RLE", + Z_RLE, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_FIXED", + Z_FIXED, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_DEFAULT_STRATEGY", + Z_DEFAULT_STRATEGY, + JS_PROP_ENUMERABLE), +}; + +static const JSCFunctionListEntry qjs_zlib_export[] = { + JS_CFUNC_MAGIC_DEF("deflateRawSync", 2, qjs_zlib_ext_deflate, 1), + JS_CFUNC_MAGIC_DEF("deflateSync", 2, qjs_zlib_ext_deflate, 0), + JS_CFUNC_MAGIC_DEF("inflateRawSync", 2, qjs_zlib_ext_inflate, 1), + JS_CFUNC_MAGIC_DEF("inflateSync", 2, qjs_zlib_ext_inflate, 0), + JS_OBJECT_DEF("constants", + qjs_zlib_constants, + njs_nitems(qjs_zlib_constants), + JS_PROP_CONFIGURABLE), +}; + + +qjs_module_t qjs_zlib_module = { + .name = "zlib", + .init = qjs_zlib_init, +}; + + +static JSValue +qjs_zlib_ext_deflate(JSContext *ctx, JSValueConst this_val, int argc, + JSValueConst *argv, int raw) +{ + int rc, chunk_size, level, mem_level, strategy, window_bits; + JSValue ret, options; + z_stream stream; + njs_chb_t chain; + qjs_bytes_t bytes, dictionary; + + chunk_size = NJS_ZLIB_CHUNK_SIZE; + mem_level = 8; + level = Z_DEFAULT_COMPRESSION; + strategy = Z_DEFAULT_STRATEGY; + window_bits = raw ? -MAX_WBITS : MAX_WBITS; + + NJS_CHB_CTX_INIT(&chain, ctx); + dictionary.start = NULL; + dictionary.length = 0; + stream.opaque = NULL; + + options = argv[1]; + + if (JS_IsObject(options)) { + ret = JS_GetPropertyStr(ctx, options, "chunkSize"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &chunk_size, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + if (chunk_size < 64) { + JS_ThrowRangeError(ctx, "chunkSize must be >= 64"); + return JS_EXCEPTION; + } + } + + ret = JS_GetPropertyStr(ctx, options, "level"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &level, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + if (level < Z_DEFAULT_COMPRESSION || level > Z_BEST_COMPRESSION) { + JS_ThrowRangeError(ctx, "level must be in the range %d..%d", + Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION); + return JS_EXCEPTION; + } + } + + ret = JS_GetPropertyStr(ctx, options, "windowBits"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &window_bits, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + if (raw) { + if (window_bits < -15 || window_bits > -9) { + JS_ThrowRangeError(ctx, "windowBits must be in the range " + "-15..-9"); + return JS_EXCEPTION; + } + + } else { + if (window_bits < 9 || window_bits > 15) { + JS_ThrowRangeError(ctx, "windowBits must be in the range " + "9..15"); + return JS_EXCEPTION; + } + } + } + + ret = JS_GetPropertyStr(ctx, options, "memLevel"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &mem_level, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + if (mem_level < 1 || mem_level > 9) { + JS_ThrowRangeError(ctx, "memLevel must be in the range 1..9"); + return JS_EXCEPTION; + } + } + + ret = JS_GetPropertyStr(ctx, options, "strategy"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &strategy, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + switch (strategy) { + case Z_FILTERED: + case Z_HUFFMAN_ONLY: + case Z_RLE: + case Z_FIXED: + case Z_DEFAULT_STRATEGY: + break; + + default: + JS_ThrowRangeError(ctx, "unknown strategy: %d", strategy); + return JS_EXCEPTION; + } + } + + ret = JS_GetPropertyStr(ctx, options, "dictionary"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = qjs_to_bytes(ctx, &dictionary, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + } + } + + rc = qjs_to_bytes(ctx, &bytes, argv[0]); + if (rc != 0) { + return JS_EXCEPTION; + } + + stream.next_in = bytes.start; + stream.avail_in = bytes.length; + + stream.zalloc = qjs_zlib_alloc; + stream.zfree = qjs_zlib_free; + stream.opaque = ctx; + + rc = deflateInit2(&stream, level, Z_DEFLATED, window_bits, mem_level, + strategy); + if (njs_slow_path(rc != Z_OK)) { + JS_ThrowInternalError(ctx, "deflateInit2() failed"); + goto fail; + } + + if (dictionary.start != NULL) { + rc = deflateSetDictionary(&stream, dictionary.start, dictionary.length); + if (rc != Z_OK) { + JS_ThrowInternalError(ctx, "deflateSetDictionary() failed"); + goto fail; + } + } + + do { + stream.next_out = njs_chb_reserve(&chain, chunk_size); + if (njs_slow_path(stream.next_out == NULL)) { + JS_ThrowOutOfMemory(ctx); + goto fail; + } + + stream.avail_out = chunk_size; + + rc = deflate(&stream, Z_FINISH); + if (njs_slow_path(rc < 0)) { + JS_ThrowInternalError(ctx, "failed to deflate the data: %s", + stream.msg); + goto fail; + } + + njs_chb_written(&chain, chunk_size - stream.avail_out); + + } while (stream.avail_out == 0); + + deflateEnd(&stream); + + qjs_bytes_free(ctx, &bytes); + + if (dictionary.start != NULL) { + qjs_bytes_free(ctx, &dictionary); + } + + ret = qjs_buffer_chb_alloc(ctx, &chain); + + njs_chb_destroy(&chain); + + return ret; + +fail: + + qjs_bytes_free(ctx, &bytes); + + if (dictionary.start != NULL) { + qjs_bytes_free(ctx, &dictionary); + } + + if (stream.opaque != NULL) { + deflateEnd(&stream); + } + + if (chain.pool != NULL) { + njs_chb_destroy(&chain); + } + + return JS_EXCEPTION; +} + + +static JSValue +qjs_zlib_ext_inflate(JSContext *ctx, JSValueConst this_val, int argc, + JSValueConst *argv, int raw) +{ + int rc, chunk_size, window_bits; + JSValue ret, options; + z_stream stream; + njs_chb_t chain; + qjs_bytes_t bytes, dictionary; + + chunk_size = NJS_ZLIB_CHUNK_SIZE; + window_bits = raw ? -MAX_WBITS : MAX_WBITS; + + NJS_CHB_CTX_INIT(&chain, ctx); + dictionary.start = NULL; + dictionary.length = 0; + stream.opaque = NULL; + + options = argv[1]; + + if (JS_IsObject(options)) { + ret = JS_GetPropertyStr(ctx, options, "chunkSize"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &chunk_size, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + if (chunk_size < 64) { + JS_ThrowRangeError(ctx, "chunkSize must be >= 64"); + return JS_EXCEPTION; + } + } + + ret = JS_GetPropertyStr(ctx, options, "windowBits"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &window_bits, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + if (raw) { + if (window_bits < -15 || window_bits > -8) { + JS_ThrowRangeError(ctx, "windowBits must be in the range " + "-15..-8"); + return JS_EXCEPTION; + } + + } else { + if (window_bits < 8 || window_bits > 15) { + JS_ThrowRangeError(ctx, "windowBits must be in the range " + "8..15"); + return JS_EXCEPTION; + } + } + } + + ret = JS_GetPropertyStr(ctx, options, "dictionary"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = qjs_to_bytes(ctx, &dictionary, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + } + } + + rc = qjs_to_bytes(ctx, &bytes, argv[0]); + if (rc != 0) { + return JS_EXCEPTION; + } + + stream.next_in = bytes.start; + stream.avail_in = bytes.length; + + stream.zalloc = qjs_zlib_alloc; + stream.zfree = qjs_zlib_free; + stream.opaque = ctx; + + rc = inflateInit2(&stream, window_bits); + if (njs_slow_path(rc != Z_OK)) { + JS_ThrowInternalError(ctx, "inflateInit2() failed"); + goto fail; + } + + if (dictionary.start != NULL) { + rc = inflateSetDictionary(&stream, dictionary.start, dictionary.length); + if (rc != Z_OK) { + JS_ThrowInternalError(ctx, "inflateSetDictionary() failed"); + goto fail; + } + } + + while (rc != Z_STREAM_END) { + stream.next_out = njs_chb_reserve(&chain, chunk_size); + if (njs_slow_path(stream.next_out == NULL)) { + JS_ThrowOutOfMemory(ctx); + goto fail; + } + + stream.avail_out = chunk_size; + + rc = inflate(&stream, Z_NO_FLUSH); + if (njs_slow_path(rc < 0)) { + JS_ThrowInternalError(ctx, "failed to inflate the data: %s", + stream.msg); + goto fail; + } + + njs_chb_written(&chain, chunk_size - stream.avail_out); + } + + rc = inflateEnd(&stream); + if (njs_slow_path(rc != Z_OK)) { + JS_ThrowInternalError(ctx, "inflateEnd() failed"); + goto fail; + } + + qjs_bytes_free(ctx, &bytes); + + if (dictionary.start != NULL) { + qjs_bytes_free(ctx, &dictionary); + } + + ret = qjs_buffer_chb_alloc(ctx, &chain); + + njs_chb_destroy(&chain); + + return ret; + +fail: + + qjs_bytes_free(ctx, &bytes); + + if (dictionary.start != NULL) { + qjs_bytes_free(ctx, &dictionary); + } + + if (stream.opaque != NULL) { + inflateEnd(&stream); + } + + if (chain.pool != NULL) { + njs_chb_destroy(&chain); + } + + return JS_EXCEPTION; +} + + +static int +qjs_zlib_module_init(JSContext *ctx, JSModuleDef *m) +{ + int rc; + JSValue proto; + + proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, proto, qjs_zlib_export, + njs_nitems(qjs_zlib_export)); + + rc = JS_SetModuleExport(ctx, m, "default", proto); + if (rc != 0) { + return -1; + } + + return JS_SetModuleExportList(ctx, m, qjs_zlib_export, + njs_nitems(qjs_zlib_export)); +} + + +static JSModuleDef * +qjs_zlib_init(JSContext *ctx, const char *name) +{ + int rc; + JSModuleDef *m; + + m = JS_NewCModule(ctx, name, qjs_zlib_module_init); + if (m == NULL) { + return NULL; + } + + JS_AddModuleExport(ctx, m, "default"); + rc = JS_AddModuleExportList(ctx, m, qjs_zlib_export, + njs_nitems(qjs_zlib_export)); + if (rc != 0) { + return NULL; + } + + return m; +} + + +static void * +qjs_zlib_alloc(void *opaque, u_int items, u_int size) +{ + return js_malloc(opaque, items * size); +} + + +static void +qjs_zlib_free(void *opaque, void *address) +{ + js_free(opaque, address); +} diff -r 18fc657411ca -r f146b5dc21cc src/qjs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/qjs.c Wed May 01 17:31:01 2024 -0700 @@ -0,0 +1,109 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) F5, Inc. + */ + +#include + + +JSContext * +qjs_new_context(JSRuntime *rt) +{ + JSContext *ctx; + qjs_module_t **module; + + ctx = JS_NewContext(rt); + if (ctx == NULL) { + return NULL; + } + + for (module = qjs_modules; *module != NULL; module++) { + if ((*module)->init(ctx, (*module)->name) == NULL) { + return NULL; + } + } + + return ctx; +} + + +int +qjs_to_bytes(JSContext *ctx, qjs_bytes_t *bytes, JSValueConst value) +{ + size_t byte_offset, byte_length; + JSValue val; + + val = JS_GetTypedArrayBuffer(ctx, value, &byte_offset, &byte_length, NULL); + if (!JS_IsException(val)) { + bytes->start = JS_GetArrayBuffer(ctx, &bytes->length, val); + + JS_FreeValue(ctx, val); + + if (bytes->start != NULL) { + bytes->tag = JS_TAG_OBJECT; + bytes->start += byte_offset; + bytes->length = byte_length; + return 0; + } + } + + bytes->start = JS_GetArrayBuffer(ctx, &bytes->length, value); + if (bytes->start != NULL) { + bytes->tag = JS_TAG_OBJECT; + return 0; + } + + bytes->tag = JS_TAG_STRING; + + if (!JS_IsString(value)) { + val = JS_ToString(ctx, value); + + bytes->start = (u_char *) JS_ToCStringLen(ctx, &bytes->length, val); + + JS_FreeValue(ctx, val); + + if (bytes->start == NULL) { + return -1; + } + } + + bytes->start = (u_char *) JS_ToCStringLen(ctx, &bytes->length, value); + + return (bytes->start != NULL) ? 0 : -1; +} + + +void +qjs_bytes_free(JSContext *ctx, qjs_bytes_t *bytes) +{ + if (bytes->tag == JS_TAG_STRING) { + JS_FreeCString(ctx, (char *) bytes->start); + } +} + + +JSValue +qjs_typed_array_data(JSContext *ctx, JSValueConst value, njs_str_t *data) +{ + size_t byte_offset, byte_length; + + value = JS_GetTypedArrayBuffer(ctx, value, &byte_offset, &byte_length, + NULL); + if (JS_IsException(value)) { + return value; + } + + data->start = JS_GetArrayBuffer(ctx, &data->length, value); + + JS_FreeValue(ctx, value); + + if (data->start == NULL) { + return JS_EXCEPTION; + } + + data->start += byte_offset; + data->length = byte_length; + + return JS_UNDEFINED; +} diff -r 18fc657411ca -r f146b5dc21cc src/qjs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/qjs.h Wed May 01 17:31:01 2024 -0700 @@ -0,0 +1,79 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) F5, Inc. + */ + +#ifndef _QJS_H_INCLUDED_ +#define _QJS_H_INCLUDED_ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__GNUC__) && (__GNUC__ >= 8) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + +#include + +#if defined(__GNUC__) && (__GNUC__ >= 8) +#pragma GCC diagnostic pop +#endif +#define NJS_QUICKJS_VERSION "Unknown version" +#include + + +typedef JSModuleDef *(*qjs_addon_init_pt)(JSContext *ctx, const char *name); + +typedef struct { + const char *name; + qjs_addon_init_pt init; +} qjs_module_t; + + +JSContext *qjs_new_context(JSRuntime *rt); + + +JSValue qjs_buffer_alloc(JSContext *ctx, size_t size); +JSValue qjs_buffer_chb_alloc(JSContext *ctx, njs_chb_t *chain); + +typedef int (*qjs_buffer_encode_t)(JSContext *ctx, const njs_str_t *src, + njs_str_t *dst); +typedef size_t (*qjs_buffer_encode_length_t)(JSContext *ctx, + const njs_str_t *src); + +typedef struct { + njs_str_t name; + qjs_buffer_encode_t encode; + qjs_buffer_encode_length_t encode_length; + qjs_buffer_encode_t decode; + qjs_buffer_encode_length_t decode_length; +} qjs_buffer_encoding_t; + +const qjs_buffer_encoding_t *qjs_buffer_encoding(JSContext *ctx, + JSValueConst value, JS_BOOL thrw); + + +typedef struct { + int tag; + size_t length; + u_char *start; +} qjs_bytes_t; + +int qjs_to_bytes(JSContext *ctx, qjs_bytes_t *data, JSValueConst value); +void qjs_bytes_free(JSContext *ctx, qjs_bytes_t *data); +JSValue qjs_typed_array_data(JSContext *ctx, JSValueConst value, + njs_str_t *data); + + +extern qjs_module_t *qjs_modules[]; + +#endif /* _QJS_H_INCLUDED_ */ diff -r 18fc657411ca -r f146b5dc21cc src/qjs_buffer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/qjs_buffer.c Wed May 01 17:31:01 2024 -0700 @@ -0,0 +1,1174 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) F5, Inc. + */ + +#include + +static JSValue qjs_buffer(JSContext *ctx, JSValueConst this_val, int argc, + JSValueConst *argv); +static JSValue qjs_buffer_from(JSContext *ctx, JSValueConst this_val, int argc, + JSValueConst *argv); +static JSValue qjs_buffer_is_buffer(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv); +static JSValue qjs_buffer_prototype_to_json(JSContext *ctx, + JSValueConst this_val, int argc, JSValueConst *argv); +static JSValue qjs_buffer_prototype_to_string(JSContext *ctx, + JSValueConst this_val, int argc, JSValueConst *argv); +static JSValue qjs_buffer_from_string(JSContext *ctx, JSValueConst str, + JSValueConst encoding); +static JSValue qjs_buffer_from_typed_array(JSContext *ctx, JSValueConst obj, + size_t offset, size_t size, size_t bytes, int float32); +static JSValue qjs_buffer_from_array_buffer(JSContext *ctx, u_char *buf, + size_t size, JSValueConst offset, JSValueConst length); +static JSValue qjs_buffer_from_object(JSContext *ctx, JSValueConst obj); +static int qjs_base64_encode(JSContext *ctx, const njs_str_t *src, + njs_str_t *dst); +static size_t qjs_base64_encode_length(JSContext *ctx, const njs_str_t *src); +static int qjs_base64_decode(JSContext *ctx, const njs_str_t *src, + njs_str_t *dst); +static size_t qjs_base64_decode_length(JSContext *ctx, const njs_str_t *src); +static int qjs_base64url_encode(JSContext *ctx, const njs_str_t *src, + njs_str_t *dst); +static int qjs_base64url_decode(JSContext *ctx, const njs_str_t *src, + njs_str_t *dst); +static size_t qjs_base64url_decode_length(JSContext *ctx, const njs_str_t *src); +static int qjs_hex_encode(JSContext *ctx, const njs_str_t *src, njs_str_t *dst); +static size_t qjs_hex_encode_length(JSContext *ctx, const njs_str_t *src); +static int qjs_hex_decode(JSContext *ctx, const njs_str_t *src, njs_str_t *dst); +static size_t qjs_hex_decode_length(JSContext *ctx, const njs_str_t *src); +static JSValue qjs_new_uint8_array(JSContext *ctx, size_t size); +static JSModuleDef *qjs_buffer_init(JSContext *ctx, const char *name); + + +static qjs_buffer_encoding_t qjs_buffer_encodings[] = +{ + { + njs_str("utf-8"), + NULL, + NULL, + NULL, + NULL, + }, + + { + njs_str("utf8"), + NULL, + NULL, + NULL, + NULL, + }, + + { + njs_str("base64"), + qjs_base64_encode, + qjs_base64_encode_length, + qjs_base64_decode, + qjs_base64_decode_length, + }, + + { + njs_str("base64url"), + qjs_base64url_encode, + qjs_base64_encode_length, + qjs_base64url_decode, + qjs_base64url_decode_length, From P.Pautov at F5.com Thu May 2 07:59:44 2024 From: P.Pautov at F5.com (Pavel Pautov) Date: Thu, 2 May 2024 07:59:44 +0000 Subject: I think I found a fix for the memory leak issue on gRPC module In-Reply-To: References: Message-ID: Hi Sangmin, Your analysis looks correct. Client streaming RPCs can lead to unbound accumulation of ngx_chain_t objects (although, at very slow rate). Gzip module had a similar issue (https://trac.nginx.org/nginx/ticket/1046). Attaching somewhat simplified patch based on yours. I was able to reproduce the issue locally and the patch fixes it. From: nginx-devel On Behalf Of Sangmin Lee Sent: Thursday, April 4, 2024 19:29 To: nginx-devel at nginx.org Subject: I think I found a fix for the memory leak issue on gRPC module CAUTION: This email has been sent from an external source. Do not click links, open attachments, or provide sensitive business information unless you can verify the sender's legitimacy. I am sending this mail again because I did a mistake while I was writing a mail. I didn't know, in gmail, "Ctrl - Enter" would send a mail immediately even without a title! I am sorry for that, so I am sending again. Hello, I think I found the main cause of the memory leak issue when using gRPC stream so I made a patch for it. Please find the test scenario and details here -- This is what I wrote.: https://trac.nginx.org/nginx/ticket/2614 After I changed the memory pool totally on nginx and tested our workload -- long-lived gRPC streams with many connections -- using Valgrind and massif, I was able to find what brought up the memory leak issue. like the picture below. [cid:image001.png at 01DA9C29.C792CD90] ( I am not sure whether this picture will be sent properly ) After I patched one part, it seems okay now I have tested it for 1 week with out workload. [cid:image002.png at 01DA9C29.C792CD90] ( I am not sure whether this picture will be sent properly ) But because I am not familiar with Mercurial, I couldn't find a way to create PR like on github. I guess this mailing list is for this patch. >From my point of view, it is more like a workaround and I think the way of using ngx_chain_add_copy() or itself needs to be changed because it allocates a ngx_chain_t structure using ngx_alloc_chain_link() but inside of that, it just copies pointer, like cl->buf = in->buf; so this ngx_chain_t instance should be dealt with differently unlike other ngx_chain_t instances. But I am quite new to nginx codes so my view might be wrong. Anyhow, please go over this patch and I would like to further talk here. -------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index dfe49c586..1db67bd0a 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -1462,6 +1462,12 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) in = in->next; } + ngx_chain_t *nl; + for (ngx_chain_t *dl = ctx->in; dl != in; dl = nl ) { + nl = dl->next; + ngx_free_chain(r->pool, dl); + } + ctx->in = in; if (last) { -------------------------------------------------------------------------------------------------------------------------------------------- Best regards, Sangmin -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image001.png Type: image/png Size: 371470 bytes Desc: image001.png URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image002.png Type: image/png Size: 65011 bytes Desc: image002.png URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: grpc_leak.patch Type: application/octet-stream Size: 718 bytes Desc: grpc_leak.patch URL: From piotr.sikora at frickle.com Thu May 2 21:32:20 2024 From: piotr.sikora at frickle.com (=?iso-8859-1?q?Piotr_Sikora?=) Date: Thu, 02 May 2024 21:32:20 +0000 Subject: [PATCH] QUIC: fix build against musl-libc when using Clang Message-ID: <962cddbaecf02b9c213d.1714685540@devbox.my.domain> # HG changeset patch # User Piotr Sikora # Date 1714589495 0 # Wed May 01 18:51:35 2024 +0000 # Node ID 962cddbaecf02b9c213dca492a74b23924b8f24c # Parent 49dce50fad40bf09db81ca2a35983ecd7b740e43 QUIC: fix build against musl-libc when using Clang. Signed-off-by: Piotr Sikora diff -r 49dce50fad40 -r 962cddbaecf0 src/event/ngx_event_udp.c --- a/src/event/ngx_event_udp.c Tue Apr 16 18:29:59 2024 +0400 +++ b/src/event/ngx_event_udp.c Wed May 01 18:51:35 2024 +0000 @@ -138,6 +138,14 @@ ngx_memcpy(&lsa, local_sockaddr, local_socklen); local_sockaddr = &lsa.sockaddr; +#ifndef __GLIBC__ + /* Silence warnings from expanded CMSG_NXTHDR macro when using musl-libc. */ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunknown-pragmas" + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wsign-compare" +#endif + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) @@ -148,6 +156,11 @@ } } +#ifndef __GLIBC__ + #pragma clang diagnostic pop + #pragma GCC diagnostic pop +#endif + #endif c = ngx_lookup_udp_connection(ls, sockaddr, socklen, local_sockaddr, diff -r 49dce50fad40 -r 962cddbaecf0 src/event/quic/ngx_event_quic_output.c --- a/src/event/quic/ngx_event_quic_output.c Tue Apr 16 18:29:59 2024 +0400 +++ b/src/event/quic/ngx_event_quic_output.c Wed May 01 18:51:35 2024 +0000 @@ -434,10 +434,25 @@ *valp = segment; #if (NGX_HAVE_ADDRINFO_CMSG) + +#ifndef __GLIBC__ + /* Silence warnings from expanded CMSG_NXTHDR macro when using musl-libc. */ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunknown-pragmas" + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wsign-compare" +#endif + if (c->listening && c->listening->wildcard && c->local_sockaddr) { cmsg = CMSG_NXTHDR(&msg, cmsg); clen += ngx_set_srcaddr_cmsg(cmsg, c->local_sockaddr); } + +#ifndef __GLIBC__ + #pragma clang diagnostic pop + #pragma GCC diagnostic pop +#endif + #endif msg.msg_controllen = clen; diff -r 49dce50fad40 -r 962cddbaecf0 src/event/quic/ngx_event_quic_udp.c --- a/src/event/quic/ngx_event_quic_udp.c Tue Apr 16 18:29:59 2024 +0400 +++ b/src/event/quic/ngx_event_quic_udp.c Wed May 01 18:51:35 2024 +0000 @@ -140,6 +140,14 @@ ngx_memcpy(&lsa, local_sockaddr, local_socklen); local_sockaddr = &lsa.sockaddr; +#ifndef __GLIBC__ + /* Silence warnings from expanded CMSG_NXTHDR macro when using musl-libc. */ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunknown-pragmas" + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wsign-compare" +#endif + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) @@ -150,6 +158,11 @@ } } +#ifndef __GLIBC__ + #pragma clang diagnostic pop + #pragma GCC diagnostic pop +#endif + #endif if (ngx_quic_get_packet_dcid(ev->log, buffer, n, &key) != NGX_OK) { From piotr.sikora at frickle.com Thu May 2 21:32:58 2024 From: piotr.sikora at frickle.com (=?iso-8859-1?q?Piotr_Sikora?=) Date: Thu, 02 May 2024 21:32:58 +0000 Subject: [PATCH] Configure: test --with-cc-opt options Message-ID: <0d5498e86bf8a7f119ed.1714685578@devbox.my.domain> # HG changeset patch # User Piotr Sikora # Date 1714589524 0 # Wed May 01 18:52:04 2024 +0000 # Node ID 0d5498e86bf8a7f119ed83dbc0789be37d728334 # Parent 49dce50fad40bf09db81ca2a35983ecd7b740e43 Configure: test --with-cc-opt options. Previously, invalid C compiler options would fail with an unrelated error much later in the ./configure tests. This matches the existing test for --with-ld-opt options. Signed-off-by: Piotr Sikora diff -r 49dce50fad40 -r 0d5498e86bf8 auto/cc/conf --- a/auto/cc/conf Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/cc/conf Wed May 01 18:52:04 2024 +0000 @@ -142,6 +142,29 @@ fi CFLAGS="$CFLAGS $NGX_CC_OPT" + +if [ "$NGX_PLATFORM" != win32 ]; then + + if test -n "$NGX_CC_OPT"; then + ngx_feature=--with-cc-opt=\"$NGX_CC_OPT\" + ngx_feature_name= + ngx_feature_run=no + ngx_feature_incs= + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test= + . auto/feature + + if [ $ngx_found = no ]; then + echo + echo $0: error: the invalid value in --with-cc-opt=\"$NGX_CC_OPT\" + echo + exit 1 + fi + fi + +fi + NGX_TEST_LD_OPT="$NGX_LD_OPT" if [ "$NGX_PLATFORM" != win32 ]; then From piotr.sikora at frickle.com Thu May 2 21:33:00 2024 From: piotr.sikora at frickle.com (=?iso-8859-1?q?Piotr_Sikora?=) Date: Thu, 02 May 2024 21:33:00 +0000 Subject: [PATCH] Configure: fix warnings in a few feature tests Message-ID: # HG changeset patch # User Piotr Sikora # Date 1714589586 0 # Wed May 01 18:53:06 2024 +0000 # Node ID c083cd8ead811426c6f7bd7c4ab58a413d80be52 # Parent 49dce50fad40bf09db81ca2a35983ecd7b740e43 Configure: fix warnings in a few feature tests. Signed-off-by: Piotr Sikora diff -r 49dce50fad40 -r c083cd8ead81 auto/unix --- a/auto/unix Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/unix Wed May 01 18:53:06 2024 +0000 @@ -731,7 +731,7 @@ ngx_feature_incs= ngx_feature_path= ngx_feature_libs= -ngx_feature_test="char buf[1]; ssize_t n; n = pwrite(1, buf, 1, 0); +ngx_feature_test="const char buf[1] = \"\"; ssize_t n; n = pwrite(1, buf, 1, 0); if (n == -1) return 1" . auto/feature @@ -760,7 +760,7 @@ ngx_feature_incs='#include ' ngx_feature_path= ngx_feature_libs= -ngx_feature_test="char *p; p = strerrordesc_np(0); +ngx_feature_test="const char *p; p = strerrordesc_np(0); if (p == NULL) return 1" . auto/feature From piotr.sikora at frickle.com Thu May 2 21:33:07 2024 From: piotr.sikora at frickle.com (=?iso-8859-1?q?Piotr_Sikora?=) Date: Thu, 02 May 2024 21:33:07 +0000 Subject: [PATCH] Configure: always test with provided C compiler options Message-ID: # HG changeset patch # User Piotr Sikora # Date 1714589692 0 # Wed May 01 18:54:52 2024 +0000 # Node ID df39b5d3c3a0c670f3d94e623351b6c659f5be84 # Parent 49dce50fad40bf09db81ca2a35983ecd7b740e43 Configure: always test with provided C compiler options. Previously, build in auto/include didn't use C compiler options, which didn't allow using a custom sysroot. While there, update auto/types/uintptr_t to match others. Signed-off-by: Piotr Sikora diff -r 49dce50fad40 -r df39b5d3c3a0 auto/include --- a/auto/include Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/include Wed May 01 18:54:52 2024 +0000 @@ -27,7 +27,8 @@ END -ngx_test="$CC -o $NGX_AUTOTEST $NGX_AUTOTEST.c" +ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ + -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs" eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1" diff -r 49dce50fad40 -r df39b5d3c3a0 auto/types/uintptr_t --- a/auto/types/uintptr_t Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/types/uintptr_t Wed May 01 18:54:52 2024 +0000 @@ -27,7 +27,7 @@ END ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ - -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT" + -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs" eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1" From piotr.sikora at frickle.com Thu May 2 21:33:17 2024 From: piotr.sikora at frickle.com (=?iso-8859-1?q?Piotr_Sikora?=) Date: Thu, 02 May 2024 21:33:17 +0000 Subject: [PATCH] Configure: fix build on Windows using non-MSVC compilers Message-ID: <43b04ece77b7132db868.1714685597@devbox.my.domain> # HG changeset patch # User Piotr Sikora # Date 1714589717 0 # Wed May 01 18:55:17 2024 +0000 # Node ID 43b04ece77b7132db868122a20c99c8ba89adfb5 # Parent 49dce50fad40bf09db81ca2a35983ecd7b740e43 Configure: fix build on Windows using non-MSVC compilers. Previously, kernel32 and user32 libraries were linked only when using MSVC, but they are needed regardless of the compiler. Signed-off-by: Piotr Sikora diff -r 49dce50fad40 -r 43b04ece77b7 auto/cc/msvc --- a/auto/cc/msvc Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/cc/msvc Wed May 01 18:55:17 2024 +0000 @@ -114,8 +114,6 @@ CFLAGS="$CFLAGS $LIBC" -CORE_LIBS="$CORE_LIBS kernel32.lib user32.lib" - # Win32 GUI mode application #CORE_LINK="$CORE_LINK -subsystem:windows -entry:mainCRTStartup" diff -r 49dce50fad40 -r 43b04ece77b7 auto/os/win32 --- a/auto/os/win32 Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/os/win32 Wed May 01 18:55:17 2024 +0000 @@ -19,14 +19,14 @@ case "$NGX_CC_NAME" in clang | gcc) - CORE_LIBS="$CORE_LIBS -ladvapi32 -lws2_32" + CORE_LIBS="$CORE_LIBS -lkernel32 -luser32 -ladvapi32 -lws2_32" MAIN_LINK="$MAIN_LINK -Wl,--export-all-symbols" MAIN_LINK="$MAIN_LINK -Wl,--out-implib=$NGX_OBJS/libnginx.a" MODULE_LINK="-shared -L $NGX_OBJS -lnginx" ;; *) - CORE_LIBS="$CORE_LIBS advapi32.lib ws2_32.lib" + CORE_LIBS="$CORE_LIBS kernel32.lib user32.lib advapi32.lib ws2_32.lib" ;; esac From piotr.sikora at frickle.com Thu May 2 21:33:21 2024 From: piotr.sikora at frickle.com (=?iso-8859-1?q?Piotr_Sikora?=) Date: Thu, 02 May 2024 21:33:21 +0000 Subject: [PATCH] Configure: build C++ test module using C++ compiler Message-ID: <787e1adea9aa7f681884.1714685601@devbox.my.domain> # HG changeset patch # User Piotr Sikora # Date 1714589815 0 # Wed May 01 18:56:55 2024 +0000 # Node ID 787e1adea9aa7f681884657f119e864af0be3e0d # Parent 49dce50fad40bf09db81ca2a35983ecd7b740e43 Configure: build C++ test module using C++ compiler. This fixes build when using C compiler that doesn't support C++. Signed-off-by: Piotr Sikora diff -r 49dce50fad40 -r 787e1adea9aa auto/cc/conf --- a/auto/cc/conf Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/cc/conf Wed May 01 18:56:55 2024 +0000 @@ -142,6 +142,7 @@ fi CFLAGS="$CFLAGS $NGX_CC_OPT" +CXXFLAGS="$CXXFLAGS $NGX_CXX_OPT" NGX_TEST_LD_OPT="$NGX_LD_OPT" if [ "$NGX_PLATFORM" != win32 ]; then diff -r 49dce50fad40 -r 787e1adea9aa auto/make --- a/auto/make Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/make Wed May 01 18:56:55 2024 +0000 @@ -23,6 +23,8 @@ CC = $CC CFLAGS = $CFLAGS +CXX = $CXX +CXXFLAGS = $CXXFLAGS CPP = $CPP LINK = $LINK @@ -384,22 +386,36 @@ if test -n "$MISC_SRCS"; then ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)" + ngx_cxx="\$(CXX) $ngx_compile_opt \$(CXXFLAGS) $ngx_use_pch \$(ALL_INCS)" - for ngx_src in $MISC_SRCS + for ngx_source in $MISC_SRCS do - ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"` + ngx_src=`echo $ngx_source | sed -e "s/\//$ngx_regex_dirsep/g"` ngx_obj=`echo $ngx_src \ | sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \ -e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \ -e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \ -e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"` - cat << END >> $NGX_MAKEFILE + if [ $ngx_source = src/misc/ngx_cpp_test_module.cpp ]; then + + cat << END >> $NGX_MAKEFILE + +$ngx_obj: \$(CORE_DEPS) $ngx_cont$ngx_src + $ngx_cxx$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX + +END + + else + + cat << END >> $NGX_MAKEFILE $ngx_obj: \$(CORE_DEPS) $ngx_cont$ngx_src $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX END + + fi done fi diff -r 49dce50fad40 -r 787e1adea9aa auto/options --- a/auto/options Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/options Wed May 01 18:56:55 2024 +0000 @@ -18,11 +18,13 @@ NGX_BUILD= CC=${CC:-cc} +CXX=${CXX:-c++} CPP= NGX_OBJS=objs NGX_DEBUG=NO NGX_CC_OPT= +NGX_CXX_OPT= NGX_LD_OPT= CPU=NO @@ -358,8 +360,10 @@ --with-compat) NGX_COMPAT=YES ;; --with-cc=*) CC="$value" ;; + --with-cxx=*) CXX="$value" ;; --with-cpp=*) CPP="$value" ;; --with-cc-opt=*) NGX_CC_OPT="$value" ;; + --with-cxx-opt=*) NGX_CXX_OPT="$value" ;; --with-ld-opt=*) NGX_LD_OPT="$value" ;; --with-cpu-opt=*) CPU="$value" ;; --with-debug) NGX_DEBUG=YES ;; @@ -578,8 +582,10 @@ --with-compat dynamic modules compatibility --with-cc=PATH set C compiler pathname + --with-cxx=PATH set C++ compiler pathname --with-cpp=PATH set C preprocessor pathname --with-cc-opt=OPTIONS set additional C compiler options + --with-cxx-opt=OPTIONS set additional C++ compiler options --with-ld-opt=OPTIONS set additional linker options --with-cpu-opt=CPU build for the specified CPU, valid values: pentium, pentiumpro, pentium3, pentium4, From piotr.sikora at frickle.com Thu May 2 21:33:28 2024 From: piotr.sikora at frickle.com (=?iso-8859-1?q?Piotr_Sikora?=) Date: Thu, 02 May 2024 21:33:28 +0000 Subject: [PATCH] Configure: postpone running the test binary Message-ID: <2d5e754e3a4e7a59eaf7.1714685608@devbox.my.domain> # HG changeset patch # User Piotr Sikora # Date 1714589827 0 # Wed May 01 18:57:07 2024 +0000 # Node ID 2d5e754e3a4e7a59eaf7f653ad4fd5346f53eab4 # Parent 49dce50fad40bf09db81ca2a35983ecd7b740e43 Configure: postpone running the test binary. Previously, the ./configure script would attempt to execute the test binary during the C compiler check, and it would abort with an error saying that the compiler doesn't work if there was any issue running the test binary (e.g. due to missing compiler and/or linker flags). This change delays that check and runs the test binary compiled with all provided compiler and linker flags. Signed-off-by: Piotr Sikora diff -r 49dce50fad40 -r 2d5e754e3a4e auto/cc/conf --- a/auto/cc/conf Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/cc/conf Wed May 01 18:57:07 2024 +0000 @@ -164,6 +164,23 @@ fi + ngx_feature="working test binary" + ngx_feature_name= + ngx_feature_run=yes + ngx_feature_incs= + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test= + . auto/feature + + if [ $ngx_found = no ]; then + echo + echo $0: error: cannot execute test binary + echo + exit 1 + fi + + ngx_feature="-Wl,-E switch" ngx_feature_name= ngx_feature_run=no diff -r 49dce50fad40 -r 2d5e754e3a4e auto/cc/name --- a/auto/cc/name Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/cc/name Wed May 01 18:57:07 2024 +0000 @@ -7,7 +7,7 @@ ngx_feature="C compiler" ngx_feature_name= - ngx_feature_run=yes + ngx_feature_run=no ngx_feature_incs= ngx_feature_path= ngx_feature_libs= From piotr.sikora at frickle.com Thu May 2 21:33:38 2024 From: piotr.sikora at frickle.com (=?iso-8859-1?q?Piotr_Sikora?=) Date: Thu, 02 May 2024 21:33:38 +0000 Subject: [PATCH] Configure: increase the default optimization level to -O2 Message-ID: <429191aad8d3ab8f70d4.1714685618@devbox.my.domain> # HG changeset patch # User Piotr Sikora # Date 1714589900 0 # Wed May 01 18:58:20 2024 +0000 # Node ID 429191aad8d3ab8f70d40dfdd7684a256357bc48 # Parent 49dce50fad40bf09db81ca2a35983ecd7b740e43 Configure: increase the default optimization level to -O2. Signed-off-by: Piotr Sikora diff -r 49dce50fad40 -r 429191aad8d3 auto/cc/clang --- a/auto/cc/clang Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/cc/clang Wed May 01 18:58:20 2024 +0000 @@ -19,9 +19,9 @@ # optimizations -#NGX_CLANG_OPT="-O2" +NGX_CLANG_OPT="-O2" #NGX_CLANG_OPT="-Oz" -NGX_CLANG_OPT="-O" +#NGX_CLANG_OPT="-O" case $CPU in pentium) diff -r 49dce50fad40 -r 429191aad8d3 auto/cc/gcc --- a/auto/cc/gcc Tue Apr 16 18:29:59 2024 +0400 +++ b/auto/cc/gcc Wed May 01 18:58:20 2024 +0000 @@ -48,9 +48,9 @@ # optimizations -#NGX_GCC_OPT="-O2" +NGX_GCC_OPT="-O2" #NGX_GCC_OPT="-Os" -NGX_GCC_OPT="-O" +#NGX_GCC_OPT="-O" #CFLAGS="$CFLAGS -fomit-frame-pointer" From pluknet at nginx.com Fri May 3 00:28:17 2024 From: pluknet at nginx.com (=?iso-8859-1?q?Sergey_Kandaurov?=) Date: Fri, 03 May 2024 04:28:17 +0400 Subject: [PATCH] SSL: fixed possible configuration overwrite loading "engine:" keys Message-ID: # HG changeset patch # User Sergey Kandaurov # Date 1714670294 -14400 # Thu May 02 21:18:14 2024 +0400 # Node ID e00aeabf2b29b891891fd150a01c82b0763c57c0 # Parent 49dce50fad40bf09db81ca2a35983ecd7b740e43 SSL: fixed possible configuration overwrite loading "engine:" keys. When loading certificate keys via ENGINE_load_private_key() in runtime, it was possible to overwrite configuration on ENGINE_by_id() failure. OpenSSL documention doesn't describe errors in details, the only reason I found in the comment to example is when the engine is not available. diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -764,13 +764,13 @@ ngx_ssl_load_certificate_key(ngx_pool_t engine = ENGINE_by_id((char *) p); + *last++ = ':'; + if (engine == NULL) { *err = "ENGINE_by_id() failed"; return NULL; } - *last++ = ':'; - pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0); if (pkey == NULL) { From arut at nginx.com Fri May 3 16:15:29 2024 From: arut at nginx.com (Roman Arutyunyan) Date: Fri, 3 May 2024 20:15:29 +0400 Subject: [PATCH] SSL: fixed possible configuration overwrite loading "engine:" keys In-Reply-To: References: Message-ID: <20240503161529.ivbbztqi56mvni57@N00W24XTQX> Hi, On Fri, May 03, 2024 at 04:28:17AM +0400, Sergey Kandaurov wrote: > # HG changeset patch > # User Sergey Kandaurov > # Date 1714670294 -14400 > # Thu May 02 21:18:14 2024 +0400 > # Node ID e00aeabf2b29b891891fd150a01c82b0763c57c0 > # Parent 49dce50fad40bf09db81ca2a35983ecd7b740e43 > SSL: fixed possible configuration overwrite loading "engine:" keys. > > When loading certificate keys via ENGINE_load_private_key() in runtime, > it was possible to overwrite configuration on ENGINE_by_id() failure. > OpenSSL documention doesn't describe errors in details, the only reason > I found in the comment to example is when the engine is not available. > > diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c > --- a/src/event/ngx_event_openssl.c > +++ b/src/event/ngx_event_openssl.c > @@ -764,13 +764,13 @@ ngx_ssl_load_certificate_key(ngx_pool_t > > engine = ENGINE_by_id((char *) p); > > + *last++ = ':'; > + > if (engine == NULL) { > *err = "ENGINE_by_id() failed"; > return NULL; > } > > - *last++ = ':'; > - > pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0); > > if (pkey == NULL) { > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://mailman.nginx.org/mailman/listinfo/nginx-devel Looks ok -- Roman Arutyunyan From pluknet at nginx.com Fri May 3 16:24:16 2024 From: pluknet at nginx.com (Sergey Kandaurov) Date: Fri, 3 May 2024 20:24:16 +0400 Subject: [PATCH] Stream pass: disabled passing from or to udp In-Reply-To: References: Message-ID: <46C42918-F76D-4477-BE32-B000658128AE@nginx.com> > On 26 Apr 2024, at 15:15, Roman Arutyunyan wrote: > > # HG changeset patch > # User Roman Arutyunyan > # Date 1714057362 -14400 > # Thu Apr 25 19:02:42 2024 +0400 > # Branch stable-1.26 wrong branch > # Node ID a60cd9c99efcc1204e6d395104beb39883308c93 > # Parent cdf74ac25b47ec928b53aa82ccc1c3d288a2f81c > Stream pass: disabled passing from or to udp. > > Passing from udp was not possible for the most part due to preread buffer > restriction. Passing to udp could occasionally work, but the connection would > still be bound to the orignial listen rbtree, which prevented it from being typo in "original" > deleted on connection closure. > > Also, passing to a QUIC listen socket is disabled by this change as well. disabled for the same reasons? > > diff --git a/src/stream/ngx_stream_pass_module.c b/src/stream/ngx_stream_pass_module.c > --- a/src/stream/ngx_stream_pass_module.c > +++ b/src/stream/ngx_stream_pass_module.c > @@ -83,6 +83,11 @@ ngx_stream_pass_handler(ngx_stream_sessi > > c->log->action = "passing connection to port"; > > + if (c->type == SOCK_DGRAM) { > + ngx_log_error(NGX_LOG_ERR, c->log, 0, "cannot pass udp connection"); > + goto failed; > + } > + > if (c->buffer && c->buffer->pos != c->buffer->last) { > ngx_log_error(NGX_LOG_ERR, c->log, 0, > "cannot pass connection with preread data"); > @@ -217,6 +222,10 @@ ngx_stream_pass_cleanup(void *data) > static ngx_int_t > ngx_stream_pass_match(ngx_listening_t *ls, ngx_addr_t *addr) > { > + if (ls->type == SOCK_DGRAM) { > + return NGX_DECLINED; > + } > + > if (!ls->wildcard) { > return ngx_cmp_sockaddr(ls->sockaddr, ls->socklen, > addr->sockaddr, addr->socklen, 1); The change is good. -- Sergey Kandaurov From pluknet at nginx.com Fri May 3 16:30:31 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Fri, 03 May 2024 16:30:31 +0000 Subject: [nginx] Version bump. Message-ID: details: https://hg.nginx.org/nginx/rev/ff0312de0112 branches: changeset: 9243:ff0312de0112 user: Sergey Kandaurov date: Fri May 03 20:28:22 2024 +0400 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff -r 49dce50fad40 -r ff0312de0112 src/core/nginx.h --- a/src/core/nginx.h Tue Apr 16 18:29:59 2024 +0400 +++ b/src/core/nginx.h Fri May 03 20:28:22 2024 +0400 @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1025005 -#define NGINX_VERSION "1.25.5" +#define nginx_version 1027000 +#define NGINX_VERSION "1.27.0" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From pluknet at nginx.com Fri May 3 16:30:34 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Fri, 03 May 2024 16:30:34 +0000 Subject: [nginx] HTTP/3: fixed handling of malformed request body length. Message-ID: details: https://hg.nginx.org/nginx/rev/690f46d3bc1f branches: changeset: 9244:690f46d3bc1f user: Sergey Kandaurov date: Fri May 03 20:28:32 2024 +0400 description: HTTP/3: fixed handling of malformed request body length. Previously, a request body larger than declared in Content-Length resulted in a 413 status code, because Content-Length was mistakenly used as the maximum allowed request body, similar to client_max_body_size. Following the HTTP/3 specification, such requests are now rejected with the 400 error as malformed. diffstat: src/http/v3/ngx_http_v3_request.c | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diffs (19 lines): diff -r ff0312de0112 -r 690f46d3bc1f src/http/v3/ngx_http_v3_request.c --- a/src/http/v3/ngx_http_v3_request.c Fri May 03 20:28:22 2024 +0400 +++ b/src/http/v3/ngx_http_v3_request.c Fri May 03 20:28:32 2024 +0400 @@ -1575,6 +1575,15 @@ ngx_http_v3_request_body_filter(ngx_http /* rc == NGX_OK */ if (max != -1 && (uint64_t) (max - rb->received) < st->length) { + + if (r->headers_in.content_length_n != -1) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client intended to send body data " + "larger than declared"); + + return NGX_HTTP_BAD_REQUEST; + } + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client intended to send too large " "body: %O+%ui bytes", From pluknet at nginx.com Fri May 3 16:30:37 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Fri, 03 May 2024 16:30:37 +0000 Subject: [nginx] SSL: fixed possible configuration overwrite loading "engine:" keys. Message-ID: details: https://hg.nginx.org/nginx/rev/c4792b0f1976 branches: changeset: 9245:c4792b0f1976 user: Sergey Kandaurov date: Fri May 03 20:29:01 2024 +0400 description: SSL: fixed possible configuration overwrite loading "engine:" keys. When loading certificate keys via ENGINE_load_private_key() in runtime, it was possible to overwrite configuration on ENGINE_by_id() failure. OpenSSL documention doesn't describe errors in details, the only reason I found in the comment to example is when the engine is not available. diffstat: src/event/ngx_event_openssl.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (19 lines): diff -r 690f46d3bc1f -r c4792b0f1976 src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c Fri May 03 20:28:32 2024 +0400 +++ b/src/event/ngx_event_openssl.c Fri May 03 20:29:01 2024 +0400 @@ -764,13 +764,13 @@ ngx_ssl_load_certificate_key(ngx_pool_t engine = ENGINE_by_id((char *) p); + *last++ = ':'; + if (engine == NULL) { *err = "ENGINE_by_id() failed"; return NULL; } - *last++ = ':'; - pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0); if (pkey == NULL) { From arut at nginx.com Fri May 3 16:30:53 2024 From: arut at nginx.com (Roman Arutyunyan) Date: Fri, 3 May 2024 20:30:53 +0400 Subject: [PATCH] Stream pass: disabled passing from or to udp In-Reply-To: <46C42918-F76D-4477-BE32-B000658128AE@nginx.com> References: <46C42918-F76D-4477-BE32-B000658128AE@nginx.com> Message-ID: <20240503163053.oectdr7ouboco73p@N00W24XTQX> Hi, On Fri, May 03, 2024 at 08:24:16PM +0400, Sergey Kandaurov wrote: > > > On 26 Apr 2024, at 15:15, Roman Arutyunyan wrote: > > > > # HG changeset patch > > # User Roman Arutyunyan > > # Date 1714057362 -14400 > > # Thu Apr 25 19:02:42 2024 +0400 > > # Branch stable-1.26 > > wrong branch Yes, already noticed this. > > # Node ID a60cd9c99efcc1204e6d395104beb39883308c93 > > # Parent cdf74ac25b47ec928b53aa82ccc1c3d288a2f81c > > Stream pass: disabled passing from or to udp. > > > > Passing from udp was not possible for the most part due to preread buffer > > restriction. Passing to udp could occasionally work, but the connection would > > still be bound to the orignial listen rbtree, which prevented it from being > > typo in "original" Thanks. > > deleted on connection closure. > > > > Also, passing to a QUIC listen socket is disabled by this change as well. > > disabled for the same reasons? Let's just remove this part. I think no explanation is needed in this version of the patch. Final version: Stream pass: disabled passing from or to udp. Passing from udp was not possible for the most part due to preread buffer restriction. Passing to udp could occasionally work, but the connection would still be bound to the original listen rbtree, which prevented it from being deleted on connection closure. [..] -- Roman Arutyunyan From arut at nginx.com Fri May 3 16:33:10 2024 From: arut at nginx.com (=?utf-8?q?Roman_Arutyunyan?=) Date: Fri, 03 May 2024 16:33:10 +0000 Subject: [nginx] Stream pass: disabled passing from or to udp. Message-ID: details: https://hg.nginx.org/nginx/rev/89093b003fcb branches: changeset: 9246:89093b003fcb user: Roman Arutyunyan date: Fri May 03 20:26:05 2024 +0400 description: Stream pass: disabled passing from or to udp. Passing from udp was not possible for the most part due to preread buffer restriction. Passing to udp could occasionally work, but the connection would still be bound to the original listen rbtree, which prevented it from being deleted on connection closure. diffstat: src/stream/ngx_stream_pass_module.c | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diffs (26 lines): diff -r c4792b0f1976 -r 89093b003fcb src/stream/ngx_stream_pass_module.c --- a/src/stream/ngx_stream_pass_module.c Fri May 03 20:29:01 2024 +0400 +++ b/src/stream/ngx_stream_pass_module.c Fri May 03 20:26:05 2024 +0400 @@ -83,6 +83,11 @@ ngx_stream_pass_handler(ngx_stream_sessi c->log->action = "passing connection to port"; + if (c->type == SOCK_DGRAM) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, "cannot pass udp connection"); + goto failed; + } + if (c->buffer && c->buffer->pos != c->buffer->last) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "cannot pass connection with preread data"); @@ -217,6 +222,10 @@ ngx_stream_pass_cleanup(void *data) static ngx_int_t ngx_stream_pass_match(ngx_listening_t *ls, ngx_addr_t *addr) { + if (ls->type == SOCK_DGRAM) { + return NGX_DECLINED; + } + if (!ls->wildcard) { return ngx_cmp_sockaddr(ls->sockaddr, ls->socklen, addr->sockaddr, addr->socklen, 1); From pluknet at nginx.com Fri May 3 16:33:05 2024 From: pluknet at nginx.com (Sergey Kandaurov) Date: Fri, 3 May 2024 20:33:05 +0400 Subject: [PATCH] Stream pass: disabled passing from or to udp In-Reply-To: <20240503163053.oectdr7ouboco73p@N00W24XTQX> References: <46C42918-F76D-4477-BE32-B000658128AE@nginx.com> <20240503163053.oectdr7ouboco73p@N00W24XTQX> Message-ID: > On 3 May 2024, at 20:30, Roman Arutyunyan wrote: > > Hi, > > On Fri, May 03, 2024 at 08:24:16PM +0400, Sergey Kandaurov wrote: >> >>> On 26 Apr 2024, at 15:15, Roman Arutyunyan wrote: >>> >>> # HG changeset patch >>> # User Roman Arutyunyan >>> # Date 1714057362 -14400 >>> # Thu Apr 25 19:02:42 2024 +0400 >>> # Branch stable-1.26 >> >> wrong branch > > Yes, already noticed this. > >>> # Node ID a60cd9c99efcc1204e6d395104beb39883308c93 >>> # Parent cdf74ac25b47ec928b53aa82ccc1c3d288a2f81c >>> Stream pass: disabled passing from or to udp. >>> >>> Passing from udp was not possible for the most part due to preread buffer >>> restriction. Passing to udp could occasionally work, but the connection would >>> still be bound to the orignial listen rbtree, which prevented it from being >> >> typo in "original" > > Thanks. > >>> deleted on connection closure. >>> >>> Also, passing to a QUIC listen socket is disabled by this change as well. >> >> disabled for the same reasons? > > Let's just remove this part. I think no explanation is needed in this > version of the patch. > > Final version: > > Stream pass: disabled passing from or to udp. > > Passing from udp was not possible for the most part due to preread buffer > restriction. Passing to udp could occasionally work, but the connection would > still be bound to the original listen rbtree, which prevented it from being > deleted on connection closure. > > [..] Looks fine. -- Sergey Kandaurov From kasei at kasei.im Mon May 6 03:14:24 2024 From: kasei at kasei.im (kasei at kasei.im) Date: Mon, 06 May 2024 11:14:24 +0800 Subject: [PATCH]HTTP/2 connection not properly closing during graceful shutdown In-Reply-To: <20240430152746.bksaeztpdhlo22uv@N00W24XTQX> References: <20240430152746.bksaeztpdhlo22uv@N00W24XTQX> Message-ID: <5fe2f2ca476eab484ed54c00e02f321a2b84b1bc.camel@kasei.im> Hello, Thanks for your confirmation and explanations. The following is a modified patch. In my test it would send GOAWAY(on stream id 0), same as the previous one, but call ngx_http_v2_finalize_connection instead of set c->close. # HG changeset patch # User Kasei Wang # Date 1714965008 -28800 # Mon May 06 11:10:08 2024 +0800 # Branch help # Node ID 70b6b6b69e6fd3a0d03de004acf45bad16b03a9c # Parent 8618e4d900cc71082fbe7dc72af087937d64faf5 HTTP/2: close http2 connections initialized during graceful shutdown. In some rare cases, a HTTP/2 connections can be initialized during a graceful shutdown. Now close such an connection to avoid unexcepted delays in the graceful shutdown. diff -r 8618e4d900cc -r 70b6b6b69e6f src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c Tue Apr 16 18:27:50 2024 +0400 +++ b/src/http/v2/ngx_http_v2.c Mon May 06 11:10:08 2024 +0800 @@ -304,6 +304,11 @@ c->idle = 1; ngx_reusable_connection(c, 0); + if (ngx_exiting) { + ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); + return; + } + if (c->buffer) { p = c->buffer->pos; end = c->buffer->last; From o.deeva at wbsrv.ru Tue May 7 20:32:45 2024 From: o.deeva at wbsrv.ru (o.deeva at wbsrv.ru) Date: Tue, 07 May 2024 23:32:45 +0300 Subject: [PATCH] Tests: ssl_engine_keys.t improved Message-ID: # HG changeset patch # User Oksana Deeva # Date 1715111756 -10800 # Tue May 07 22:55:56 2024 +0300 # Node ID e5014b423e1391dd1078d064361a0b28d1a488d0 # Parent 2a607a31f583add7adfa1ac434a3f793d327ca6b Tests: ssl_engine_keys.t improved diff -r 2a607a31f583 -r e5014b423e13 ssl_engine_keys.t --- a/ssl_engine_keys.t Tue Apr 23 17:59:53 2024 +0400 +++ b/ssl_engine_keys.t Tue May 07 22:55:56 2024 +0300 @@ -28,7 +28,7 @@ unless $ENV{TEST_NGINX_UNSAFE}; my $t = Test::Nginx->new()->has(qw/http proxy http_ssl/)->has_daemon('openssl') - ->has_daemon('softhsm2-util')->has_daemon('pkcs11-tool')->plan(2); + ->has_daemon('softhsm2-util')->has_daemon('pkcs11-tool'); $t->write_file_expand('nginx.conf', <<'EOF'); @@ -86,9 +86,29 @@ # # http://mailman.nginx.org/pipermail/nginx-devel/2014-October/006151.html # -# Note that library paths may differ on different systems, +# Note that library paths vary on different systems, # and may need to be adjusted. +my $libsofthsm2_path; +my @so_paths = ( + '/usr/lib/softhsm/', # alpine, astrase, debian, ubuntu + '/usr/lib64/softhsm/', # rosachrome, rosafresh + '/usr/local/lib/softhsm/', # freebsd + '/lib64/', # redos, almalinux, centos, oracle, rocky +); +for my $so_path (@so_paths) { + my $path = $so_path . 'libsofthsm2.so'; + if (-e $path) { + $libsofthsm2_path = $path; + last; + } +}; + +die 'Can\'t determine libsofthsm2.so path' + unless $libsofthsm2_path; + +note("libsofthsm2_path: $libsofthsm2_path"); + $t->write_file('openssl.conf', <>$d/openssl.out 2>&1"); + . ">>$d/openssl.out 2>&1"; + + note("SOFTHSM2_CONF=$d/softhsm2.conf OPENSSL_CONF=$d/openssl.conf $cmd"); + + system($cmd); - system('pkcs11-tool --module=/usr/local/lib/softhsm/libsofthsm2.so ' + $cmd = "pkcs11-tool --module=$libsofthsm2_path " . '-p 1234 -l -k -d 0 -a nx_key_0 --key-type rsa:2048 ' - . ">>$d/openssl.out 2>&1"); + . ">>$d/openssl.out 2>&1"; + + note("SOFTHSM2_CONF=$d/softhsm2.conf OPENSSL_CONF=$d/openssl.conf $cmd"); - system('openssl req -x509 -new ' + system($cmd); + + $cmd = 'openssl req -x509 -new ' . "-subj /CN=$name/ -out $d/$name.crt -text " . "-engine pkcs11 -keyform engine -key id_00 " - . ">>$d/openssl.out 2>&1") == 0 - or die "Can't create certificate for $name: $!\n"; + . ">>$d/openssl.out 2>&1"; + + note("SOFTHSM2_CONF=$d/softhsm2.conf OPENSSL_CONF=$d/openssl.conf $cmd"); + + my $openssl_call_result = system($cmd); + + plan(skip_all => "Can't create certificate for $name: $!\n") + unless $openssl_call_result == 0; } +$t->plan(2); + $t->run(); $t->write_file('index.html', ''); From maksim.yevmenkin at gmail.com Tue May 7 21:32:23 2024 From: maksim.yevmenkin at gmail.com (Maksim Yevmenkin) Date: Tue, 7 May 2024 14:32:23 -0700 Subject: [patch] reject http header without colon (:) in the header name Message-ID: hello, it appears that nginx would happily accept http header without colon (:) in the header name. the patch below tries to address this. thanks max == --- a/ports/netflix/nginx/files/nginx/src/http/ngx_http_parse.c +++ b/ports/netflix/nginx/files/nginx/src/http/ngx_http_parse.c @@ -941,14 +941,14 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, r->header_start = p; r->header_end = p; state = sw_almost_done; - break; + return NGX_HTTP_PARSE_INVALID_HEADER; } if (ch == LF) { r->header_name_end = p; r->header_start = p; r->header_end = p; - goto done; + return NGX_HTTP_PARSE_INVALID_HEADER; } /* IIS may send the duplicate "HTTP/1.1 ..." lines */ From benjamin.p.kallus.gr at dartmouth.edu Tue May 7 21:58:34 2024 From: benjamin.p.kallus.gr at dartmouth.edu (Ben Kallus) Date: Tue, 7 May 2024 17:58:34 -0400 Subject: [patch] reject http header without colon (:) in the header name In-Reply-To: References: Message-ID: Nginx is the only widely-used HTTP server that ignores invalid field-lines. This behavior makes it trivial to fingerprint. I never reported this in the past because I assumed Maxim wouldn't care about that sort of thing. Now that he's out of the picture, maybe others will see things differently? -Ben From xeioex at nginx.com Thu May 9 19:59:56 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Thu, 09 May 2024 19:59:56 +0000 Subject: [njs] Configure: fixed QuickJS detection with --with-quickjs flag. Message-ID: details: https://hg.nginx.org/njs/rev/02369792b032 branches: changeset: 2326:02369792b032 user: Dmitry Volyntsev date: Thu May 09 12:58:57 2024 -0700 description: Configure: fixed QuickJS detection with --with-quickjs flag. diffstat: auto/quickjs | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r f146b5dc21cc -r 02369792b032 auto/quickjs --- a/auto/quickjs Wed May 01 17:31:01 2024 -0700 +++ b/auto/quickjs Thu May 09 12:58:57 2024 -0700 @@ -81,7 +81,7 @@ if [ $NJS_TRY_QUICKJS = YES ]; then NJS_LIB_AUX_LIBS="$NJS_LIB_AUX_LIBS $njs_feature_libs" fi - if [ $NJS_QUICKJS = YES -a $njs_found = no ]; then + if [ $NJS_QUICKJS = YES -a $NJS_HAVE_QUICKJS = NO ]; then echo echo $0: error: no QuickJS library found. echo From arut at nginx.com Mon May 13 07:18:18 2024 From: arut at nginx.com (Roman Arutyunyan) Date: Mon, 13 May 2024 11:18:18 +0400 Subject: [patch] reject http header without colon (:) in the header name In-Reply-To: References: Message-ID: <20240513071818.llekltkgqshxlgmg@N00W24XTQX> Hi, On Tue, May 07, 2024 at 05:58:34PM -0400, Ben Kallus wrote: > Nginx is the only widely-used HTTP server that ignores invalid > field-lines. This behavior makes it trivial to fingerprint. A simple test shows that google server gws does the same. > I never reported this in the past because I assumed Maxim wouldn't > care about that sort of thing. Now that he's out of the picture, maybe > others will see things differently? > > -Ben > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://mailman.nginx.org/mailman/listinfo/nginx-devel -- Roman Arutyunyan From benjamin.p.kallus.gr at dartmouth.edu Mon May 13 14:30:05 2024 From: benjamin.p.kallus.gr at dartmouth.edu (Ben Kallus) Date: Mon, 13 May 2024 14:30:05 +0000 Subject: [patch] reject http header without colon (:) in the header name In-Reply-To: <20240513071818.llekltkgqshxlgmg@N00W24XTQX> References: <20240513071818.llekltkgqshxlgmg@N00W24XTQX> Message-ID: Okay; I should have been more specific. I meant that nginx is unique among *general-purpose* web servers. GWS is something of an special case; it also accepts requests with no Host header, and doesn't validate the version string (e.g., HTTP/1.999999999 is accepted). Google has opted into these strange behaviors because it makes sense for them as the only users of GWS. These are, of course, bad defaults for a general-purpose HTTP/1.1 server. The "silently ignore invalid headers" behavior, imo, falls into the same category. -Ben From chipitsine at gmail.com Mon May 13 15:59:50 2024 From: chipitsine at gmail.com (=?UTF-8?B?0JjQu9GM0Y8g0KjQuNC/0LjRhtC40L0=?=) Date: Mon, 13 May 2024 17:59:50 +0200 Subject: [patch] reject http header without colon (:) in the header name In-Reply-To: References: <20240513071818.llekltkgqshxlgmg@N00W24XTQX> Message-ID: nginx is about as popular as GWS, same reasoning might be considered. btw, do you suggest to 1) introduce new behaviour by some setting (default is unchanged) 2) change default behaviour ? and I'm quite curious why do you want to change current behaviour пн, 13 мая 2024 г. в 16:30, Ben Kallus : > Okay; I should have been more specific. I meant that nginx is unique > among *general-purpose* web servers. > > GWS is something of an special case; it also accepts requests with no > Host header, and doesn't validate the version string (e.g., > HTTP/1.999999999 is accepted). > > Google has opted into these strange behaviors because it makes sense > for them as the only users of GWS. These are, of course, bad defaults > for a general-purpose HTTP/1.1 server. > > The "silently ignore invalid headers" behavior, imo, falls into the > same category. > > -Ben > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://mailman.nginx.org/mailman/listinfo/nginx-devel > -------------- next part -------------- An HTML attachment was scrubbed... URL: From benjamin.p.kallus.gr at dartmouth.edu Mon May 13 20:09:45 2024 From: benjamin.p.kallus.gr at dartmouth.edu (Ben Kallus) Date: Mon, 13 May 2024 20:09:45 +0000 Subject: [patch] reject http header without colon (:) in the header name In-Reply-To: References: <20240513071818.llekltkgqshxlgmg@N00W24XTQX> Message-ID: > nginx is about as popular as GWS, same reasoning might be considered. What I'm saying is exceptional about GWS is not its popularity. Of course, Nginx (and Apache) are similarly popular. I'm arguing that because GWS is by design a single-purpose web server that serves the interest of a single company, it is expected that it implements unorthodox decisions that benefit that company. Nginx is general-purpose software. It is therefore reasonable to expect that it would support a configuration that behaves in the way most users expect a web server to behave (i.e., reject invalid incoming messages). > btw, do you suggest to > 1) introduce new behaviour by some setting (default is unchanged) > 2) change default behaviour Changing defaults is messy for programs as relied-upon as Nginx. I offer no suggestions about how default behaviors should change. > and I'm quite curious why do you want to change current behaviour HTTP request smuggling attacks rely on inconsistent parsing behaviors across web servers. These same behaviors also form the basis for HTTP server fingerprinting techniques. It is not always obvious at first glance whether a discrepancy is useful for these purposes. For this reason, I am generally in favor of offering users the opportunity to opt out of behaviors that are not recommended by the RFCs. -Ben From liudongmiao at gmail.com Tue May 14 00:27:06 2024 From: liudongmiao at gmail.com (Liu Dongmiao) Date: Tue, 14 May 2024 08:27:06 +0800 Subject: Discussion: websocket over http2 / http3? Message-ID: Hi, websocket over http2 is defined in RFC8441, chrome and firefox support it. https://chromestatus.com/feature/6251293127475200 websocket over http3 is defined in RFC9220, neither of chrome nor firefox support it. https://chromestatus.com/feature/5080537855688704 Is there any plan to support them in nginx? I'm implementing them, and would nginx accept them? Regards, Liu Dongmiao From maksim.yevmenkin at gmail.com Thu May 16 00:28:07 2024 From: maksim.yevmenkin at gmail.com (Maksim Yevmenkin) Date: Wed, 15 May 2024 17:28:07 -0700 Subject: limiting number of HTTP request headers Message-ID: Hello! Could the community share their thoughts on introducing a directive to cap the number of HTTP request headers? While we currently have the ability to limit client HTTP request buffer size, having more specific control over the number of headers could be advantageous. Thanks, max From liudongmiao at gmail.com Thu May 16 07:36:43 2024 From: liudongmiao at gmail.com (Liu Dongmiao) Date: Thu, 16 May 2024 15:36:43 +0800 Subject: limiting number of HTTP request headers In-Reply-To: References: Message-ID: Hi max, If you use njs, then you can use `r.headersIn` or `r.rawHeadersIn` https://nginx.org/en/docs/njs/reference.html#r_headers_in https://nginx.org/en/docs/njs/reference.html#r_raw_headers_in Regards, Liu Maksim Yevmenkin 于2024年5月16日周四 08:28写道: > > Hello! > > Could the community share their thoughts on introducing a directive to > cap the number of HTTP request headers? While we currently have the > ability to limit client HTTP request buffer size, having more specific > control over the number of headers could be advantageous. > > Thanks, > max > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://mailman.nginx.org/mailman/listinfo/nginx-devel From bonet at grenoble.cnrs.fr Thu May 16 09:25:33 2024 From: bonet at grenoble.cnrs.fr (Edgar Bonet) Date: Thu, 16 May 2024 11:25:33 +0200 Subject: [PATCH] Fix compile error in configure script Message-ID: <39799336-de5d-4373-b95e-e05be1d2973b@grenoble.cnrs.fr> # HG changeset patch # User Edgar Bonet # Date 1715850910 -7200 # Thu May 16 11:15:10 2024 +0200 # Node ID c2c3b0d74b1a7d3f967421c72760b5c573afcd81 # Parent 89093b003fcb54c7f8dc66042f17bc4dea4e7709 Fix compile error in configure script Building with GCC 14 fails at the configure step with: ./configure: error: libatomic_ops library was not found. The error is not caused by a missing library, but by an unrelated "incompatible pointer type" error in the test program: ... checking for atomic_ops library objs/autotest.c: In function 'main': objs/autotest.c:9:48: error: passing argument 1 of 'AO_compare_and_swap' from incompatible pointer type [-Wincompatible-pointer-types] Fix the error by using the correct pointer types. Signed-off-by: Edgar Bonet diff -r 89093b003fcb -r c2c3b0d74b1a auto/lib/libatomic/conf --- a/auto/lib/libatomic/conf Fri May 03 20:26:05 2024 +0400 +++ b/auto/lib/libatomic/conf Thu May 16 11:15:10 2024 +0200 @@ -19,7 +19,7 @@ #include " ngx_feature_path= ngx_feature_libs="-latomic_ops" - ngx_feature_test="long n = 0; + ngx_feature_test="AO_t n = 0; if (!AO_compare_and_swap(&n, 0, 1)) return 1; if (AO_fetch_and_add(&n, 1) != 1) From pluknet at nginx.com Fri May 17 17:41:39 2024 From: pluknet at nginx.com (Sergey Kandaurov) Date: Fri, 17 May 2024 21:41:39 +0400 Subject: [PATCH] Fix compile error in configure script In-Reply-To: <39799336-de5d-4373-b95e-e05be1d2973b@grenoble.cnrs.fr> References: <39799336-de5d-4373-b95e-e05be1d2973b@grenoble.cnrs.fr> Message-ID: > On 16 May 2024, at 13:25, Edgar Bonet wrote: > > # HG changeset patch > # User Edgar Bonet > # Date 1715850910 -7200 > # Thu May 16 11:15:10 2024 +0200 > # Node ID c2c3b0d74b1a7d3f967421c72760b5c573afcd81 > # Parent 89093b003fcb54c7f8dc66042f17bc4dea4e7709 > Fix compile error in configure script > > Building with GCC 14 fails at the configure step with: > > ./configure: error: libatomic_ops library was not found. > > The error is not caused by a missing library, but by an unrelated > "incompatible pointer type" error in the test program: > > ... > checking for atomic_ops library > objs/autotest.c: In function 'main': > objs/autotest.c:9:48: error: passing argument 1 of 'AO_compare_and_swap' from incompatible pointer type [-Wincompatible-pointer-types] > Where did you try to build? Usually, long and size_t (a "common default" for AO_t) have the same underlying type, unless you build with something like MSVC. So far I only get signedness warnings with -Wpointer-sign on both Clang and GCC 14 prerelease, and it is disabled by default on GCC. The patch addresses them. This warning option is documented to enable warnings other than -Wincompatible-pointer-types. It might have been changed in the released version though. > Fix the error by using the correct pointer types. > > Signed-off-by: Edgar Bonet > > diff -r 89093b003fcb -r c2c3b0d74b1a auto/lib/libatomic/conf > --- a/auto/lib/libatomic/conf Fri May 03 20:26:05 2024 +0400 > +++ b/auto/lib/libatomic/conf Thu May 16 11:15:10 2024 +0200 > @@ -19,7 +19,7 @@ > #include " > ngx_feature_path= > ngx_feature_libs="-latomic_ops" > - ngx_feature_test="long n = 0; > + ngx_feature_test="AO_t n = 0; > if (!AO_compare_and_swap(&n, 0, 1)) > return 1; > if (AO_fetch_and_add(&n, 1) != 1) > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://mailman.nginx.org/mailman/listinfo/nginx-devel -- Sergey Kandaurov From bonet at grenoble.cnrs.fr Fri May 17 19:27:07 2024 From: bonet at grenoble.cnrs.fr (Edgar Bonet) Date: Fri, 17 May 2024 21:27:07 +0200 Subject: [PATCH] Fix compile error in configure script In-Reply-To: References: <39799336-de5d-4373-b95e-e05be1d2973b@grenoble.cnrs.fr> Message-ID: <14a3408e-6f08-48c6-96ca-021fa1406142@grenoble.cnrs.fr> Hello! Sergey Kandaurov wrote: > > objs/autotest.c:9:48: error: passing argument 1 > > of 'AO_compare_and_swap' from incompatible pointer type > > [-Wincompatible-pointer-types] > > Where did you try to build? I experienced this when building for arm and i686, both cross-compiled from x86_64. Building for x86_64 works fine. > Usually, long and size_t (a "common default" for AO_t) have the same > underlying type, unless you build with something like MSVC. AO_t is a 'volatile size_t'. The volatile qualifier may not matter though. The error message about incompatible types was followed by this note: expected 'volatile size_t *' {aka 'volatile unsigned int *'} but argument is of type 'long int *' My understanding is that the compiler considers 'int' and 'long' to be incompatible types, even though they have the same underlying representation on ILP32 environments. I'm not a language lawyer, so I cannot tell _why_ they are considered incompatible. But then, 'size_t' being an 'unsigned int', it is incompatible with 'long'. On LP64 (your typical 64-bit Linux/Mac), 'size_t' is a 'unsigned long', which is compatible with 'long' but for the signedness warning. Regards, Edgar. From xeioex at nginx.com Sat May 18 04:55:22 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Sat, 18 May 2024 04:55:22 +0000 Subject: [njs] Added string creation benchmark. Message-ID: details: https://hg.nginx.org/njs/rev/f474755a4dce branches: changeset: 2327:f474755a4dce user: Dmitry Volyntsev date: Fri May 17 18:36:12 2024 -0700 description: Added string creation benchmark. diffstat: src/test/njs_benchmark.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 158 insertions(+), 1 deletions(-) diffs (185 lines): diff -r 02369792b032 -r f474755a4dce src/test/njs_benchmark.c --- a/src/test/njs_benchmark.c Thu May 09 12:58:57 2024 -0700 +++ b/src/test/njs_benchmark.c Fri May 17 18:36:12 2024 -0700 @@ -29,12 +29,52 @@ typedef struct { } njs_opts_t; +static njs_int_t njs_benchmark_preinit(njs_vm_t *vm); +static njs_int_t njs_benchmark_init(njs_vm_t *vm); +static njs_int_t njs_benchmark_string(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused, njs_value_t *retval); + + +static njs_external_t njs_benchmark_external[] = { + + { + .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL, + .name.symbol = NJS_SYMBOL_TO_STRING_TAG, + .u.property = { + .value = "Benchmark", + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("string"), + .writable = 1, + .configurable = 1, + .enumerable = 1, + .u.method = { + .native = njs_benchmark_string, + } + }, +}; + + +njs_module_t njs_benchmark_module = { + .name = njs_str("benchmark"), + .preinit = njs_benchmark_preinit, + .init = njs_benchmark_init, +}; + + njs_module_t *njs_benchmark_addon_external_modules[] = { &njs_unit_test_external_module, - NULL, + &njs_benchmark_module, + NULL }; +static njs_int_t njs_benchmark_proto_id; + + static uint64_t njs_time(void) { @@ -225,6 +265,46 @@ static njs_benchmark_test_t njs_test[] njs_str("4"), 100000 }, + { "string set 'abcdefABCDEF'", + njs_str("benchmark.string('set', 'abcdef', 1000000)"), + njs_str("undefined"), + 1 }, + + { "string set 'АБВГДЕ'", + njs_str("benchmark.string('set', 'АБВГДЕ', 1000000)"), + njs_str("undefined"), + 1 }, + + { "string set 'x'.repeat(24)", + njs_str("benchmark.string('set', 'x'.repeat(32), 1000000)"), + njs_str("undefined"), + 1 }, + + { "string set 'Д'.repeat(12)", + njs_str("benchmark.string('set', 'А'.repeat(16), 1000000)"), + njs_str("undefined"), + 1 }, + + { "string create 'abcdefABCDEF'", + njs_str("benchmark.string('create', 'abcdef', 1000000)"), + njs_str("undefined"), + 1 }, + + { "string create 'АБВГДЕ'", + njs_str("benchmark.string('create', 'АБВГДЕ', 1000000)"), + njs_str("undefined"), + 1 }, + + { "string create 'x'.repeat(24)", + njs_str("benchmark.string('create', 'x'.repeat(32), 1000000)"), + njs_str("undefined"), + 1 }, + + { "string create 'Д'.repeat(12)", + njs_str("benchmark.string('create', 'А'.repeat(16), 1000000)"), + njs_str("undefined"), + 1 }, + { "JSON.parse", njs_str("JSON.parse('{\"a\":123, \"XXX\":[3,4,null]}').a"), njs_str("123"), @@ -570,3 +650,80 @@ invalid_options: return EXIT_FAILURE; } + + +static njs_int_t +njs_benchmark_preinit(njs_vm_t *vm) +{ + njs_benchmark_proto_id = njs_vm_external_prototype(vm, + njs_benchmark_external, + njs_nitems(njs_benchmark_external)); + if (njs_slow_path(njs_benchmark_proto_id < 0)) { + njs_printf("njs_vm_external_prototype() failed\n"); + return NJS_ERROR; + } + + return NJS_OK; +} + + +static njs_int_t +njs_benchmark_init(njs_vm_t *vm) +{ + njs_int_t ret; + njs_opaque_value_t value; + + static const njs_str_t benchmark = njs_str("benchmark"); + + ret = njs_vm_external_create(vm, njs_value_arg(&value), + njs_benchmark_proto_id, NULL, 1); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + ret = njs_vm_bind(vm, &benchmark, njs_value_arg(&value), 1); + if (njs_slow_path(ret != NJS_OK)) { + njs_printf("njs_vm_bind() failed\n"); + return NJS_ERROR; + } + + return NJS_OK; +} + + +static njs_int_t +njs_benchmark_string(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t unused, njs_value_t *retval) +{ + int64_t i, n; + njs_str_t s, mode; + njs_value_t value; + + njs_value_string_get(njs_arg(args, nargs, 1), &mode); + + njs_value_string_get(njs_arg(args, nargs, 2), &s); + + if (njs_value_to_integer(vm, njs_arg(args, nargs, 3), &n) != NJS_OK) { + return NJS_ERROR; + } + + if (memcmp(mode.start, "set", 3) == 0) { + for (i = 0; i < n; i++) { + njs_string_set(vm, &value, s.start, s.length); + } + + } else if (memcmp(mode.start, "create", 6) == 0) { + + for (i = 0; i < n; i++) { + njs_string_create(vm, &value, (char *) s.start, s.length); + } + + } else { + njs_type_error(vm, "unknown mode \"%V\"", &mode); + return NJS_ERROR; + } + + njs_value_undefined_set(retval); + + return NJS_OK; +} From xeioex at nginx.com Sat May 18 04:55:24 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Sat, 18 May 2024 04:55:24 +0000 Subject: [njs] Optimized string creation with ASCII input. Message-ID: details: https://hg.nginx.org/njs/rev/dec46ad52e9a branches: changeset: 2328:dec46ad52e9a user: Dmitry Volyntsev date: Fri May 17 21:54:49 2024 -0700 description: Optimized string creation with ASCII input. diffstat: src/njs_string.c | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-) diffs (24 lines): diff -r f474755a4dce -r dec46ad52e9a src/njs_string.c --- a/src/njs_string.c Fri May 17 18:36:12 2024 -0700 +++ b/src/njs_string.c Fri May 17 21:54:49 2024 -0700 @@ -130,8 +130,20 @@ njs_int_t njs_string_create(njs_vm_t *vm, njs_value_t *value, const char *src, size_t size) { + u_char *p, *p_end; njs_str_t str; + p = (u_char *) src; + p_end = p + size; + + while (p < p_end && *p < 0x80) { + p++; + } + + if (p == p_end) { + return njs_string_new(vm, value, (u_char *) src, size, size); + } + str.start = (u_char *) src; str.length = size; From xeioex at nginx.com Sat May 18 04:55:26 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Sat, 18 May 2024 04:55:26 +0000 Subject: [njs] Change: removed byte strings API. Message-ID: details: https://hg.nginx.org/njs/rev/4e0553f7ea68 branches: changeset: 2329:4e0553f7ea68 user: Dmitry Volyntsev date: Fri May 17 21:54:50 2024 -0700 description: Change: removed byte strings API. These functions are unsafe because they produce byte strings. Byte strings may not work as expected with the existing JS methods. The following functions were removed: - njs_vm_value_string_set() use njs_vm_value_string_create() as a drop-in replacement. - njs_vm_value_string_alloc() use njs_chb_t and njs_vm_value_string_create_chb() instead. This fixes #710 on Github. diffstat: external/njs_query_string_module.c | 2 +- external/njs_shell.c | 4 +- external/njs_webcrypto_module.c | 54 ++++++------ external/njs_xml_module.c | 20 ++-- nginx/ngx_http_js_module.c | 150 ++++++++++++++---------------------- nginx/ngx_js.c | 34 ++++---- nginx/ngx_js.h | 2 +- nginx/ngx_js_fetch.c | 32 +++--- nginx/ngx_js_shared_dict.c | 25 +++-- nginx/ngx_stream_js_module.c | 4 +- src/njs.h | 8 - src/njs_string.c | 2 +- src/njs_vm.c | 19 +---- src/test/njs_benchmark.c | 12 +- src/test/njs_externals_test.c | 38 ++++---- src/test/njs_unit_test.c | 32 +++--- 16 files changed, 193 insertions(+), 245 deletions(-) diffs (truncated from 1114 to 1000 lines): diff -r dec46ad52e9a -r 4e0553f7ea68 external/njs_query_string_module.c --- a/external/njs_query_string_module.c Fri May 17 21:54:49 2024 -0700 +++ b/external/njs_query_string_module.c Fri May 17 21:54:50 2024 -0700 @@ -694,7 +694,7 @@ njs_query_string_stringify(njs_vm_t *vm, object = njs_arg(args, nargs, 1); if (njs_slow_path(!njs_value_is_object(object))) { - njs_vm_value_string_set(vm, retval, (u_char *) "", 0); + njs_vm_value_string_create(vm, retval, (u_char *) "", 0); return NJS_OK; } diff -r dec46ad52e9a -r 4e0553f7ea68 external/njs_shell.c --- a/external/njs_shell.c Fri May 17 21:54:49 2024 -0700 +++ b/external/njs_shell.c Fri May 17 21:54:50 2024 -0700 @@ -1579,8 +1579,8 @@ njs_engine_njs_complete(njs_engine_t *en while (p < end && *p != '.') { p++; } - ret = njs_vm_value_string_set(vm, njs_value_arg(&key), start, - p - start); + ret = njs_vm_value_string_create(vm, njs_value_arg(&key), start, + p - start); if (njs_slow_path(ret != NJS_OK)) { return NULL; } diff -r dec46ad52e9a -r 4e0553f7ea68 external/njs_webcrypto_module.c --- a/external/njs_webcrypto_module.c Fri May 17 21:54:49 2024 -0700 +++ b/external/njs_webcrypto_module.c Fri May 17 21:54:50 2024 -0700 @@ -1855,7 +1855,7 @@ njs_export_jwk_rsa(njs_vm_t *vm, njs_web return NJS_ERROR; } - njs_vm_value_string_set(vm, njs_value_arg(&rsa_s), (u_char *) "RSA", 3); + njs_vm_value_string_create(vm, njs_value_arg(&rsa_s), (u_char *) "RSA", 3); ret = njs_vm_object_prop_set(vm, retval, &string_kty, &rsa_s); if (ret != NJS_OK) { @@ -1909,8 +1909,8 @@ njs_export_jwk_rsa(njs_vm_t *vm, njs_web nm = &njs_webcrypto_alg_name[key->alg->type][key->hash]; - (void) njs_vm_value_string_set(vm, njs_value_arg(&alg), nm->start, - nm->length); + (void) njs_vm_value_string_create(vm, njs_value_arg(&alg), nm->start, + nm->length); return njs_vm_object_prop_set(vm, retval, &string_alg, &alg); } @@ -1975,8 +1975,8 @@ njs_export_jwk_ec(njs_vm_t *vm, njs_webc nid = EC_GROUP_get_curve_name(group); cname = njs_algorithm_curve_name(nid); - (void) njs_vm_value_string_set(vm, njs_value_arg(&name), - cname->start, cname->length); + (void) njs_vm_value_string_create(vm, njs_value_arg(&name), + cname->start, cname->length); if (cname->length == 0) { njs_vm_type_error(vm, "Unsupported JWK EC curve: %s", OBJ_nid2sn(nid)); @@ -1988,7 +1988,7 @@ njs_export_jwk_ec(njs_vm_t *vm, njs_webc goto fail; } - njs_vm_value_string_set(vm, njs_value_arg(&ec_s), (u_char *) "EC", 2); + njs_vm_value_string_create(vm, njs_value_arg(&ec_s), (u_char *) "EC", 2); ret = njs_vm_object_prop_set(vm, retval, &string_kty, &ec_s); if (ret != NJS_OK) { @@ -2154,8 +2154,8 @@ njs_export_jwk_oct(njs_vm_t *vm, njs_web if (key->alg->type == NJS_ALGORITHM_HMAC) { nm = &njs_webcrypto_alg_name[type][key->hash]; - (void) njs_vm_value_string_set(vm, njs_value_arg(&alg), nm->start, - nm->length); + (void) njs_vm_value_string_create(vm, njs_value_arg(&alg), nm->start, + nm->length); } else { switch (key->u.s.raw.length) { @@ -2164,8 +2164,8 @@ njs_export_jwk_oct(njs_vm_t *vm, njs_web case 32: nm = &njs_webcrypto_alg_aes_name [type - NJS_ALGORITHM_AES_GCM][(key->u.s.raw.length - 16) / 8]; - (void) njs_vm_value_string_set(vm, njs_value_arg(&alg), nm->start, - nm->length); + (void) njs_vm_value_string_create(vm, njs_value_arg(&alg), + nm->start, nm->length); break; default: @@ -2186,7 +2186,7 @@ njs_export_jwk_oct(njs_vm_t *vm, njs_web return NJS_ERROR; } - njs_vm_value_string_set(vm, njs_value_arg(&oct_s), (u_char *) "oct", 3); + njs_vm_value_string_create(vm, njs_value_arg(&oct_s), (u_char *) "oct", 3); ret = njs_vm_object_prop_set(vm, retval, &string_kty, &oct_s); if (ret != NJS_OK) { @@ -4150,14 +4150,14 @@ njs_key_ext_algorithm(njs_vm_t *vm, njs_ } name = &njs_webcrypto_alg[key->alg->type].name; - ret = njs_vm_value_string_set(vm, njs_value_arg(&alg), name->start, - name->length); + ret = njs_vm_value_string_create(vm, njs_value_arg(&alg), name->start, + name->length); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } - (void) njs_vm_value_string_set(vm, njs_value_arg(&name_s), - (u_char *) "name", njs_length("name")); + (void) njs_vm_value_string_create(vm, njs_value_arg(&name_s), + (u_char *) "name", njs_length("name")); ret = njs_vm_object_alloc(vm, retval, &name_s, &alg, NULL); if (njs_slow_path(ret != NJS_OK)) { @@ -4203,8 +4203,8 @@ njs_key_ext_algorithm(njs_vm_t *vm, njs_ } name = njs_algorithm_hash_name(key->hash); - ret = njs_vm_value_string_set(vm, njs_value_arg(&hash), name->start, - name->length); + ret = njs_vm_value_string_create(vm, njs_value_arg(&hash), name->start, + name->length); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } @@ -4252,8 +4252,8 @@ njs_key_ext_algorithm(njs_vm_t *vm, njs_ name = njs_algorithm_curve_name(EC_GROUP_get_curve_name(group)); - ret = njs_vm_value_string_set(vm, njs_value_arg(&val), name->start, - name->length); + ret = njs_vm_value_string_create(vm, njs_value_arg(&val), name->start, + name->length); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } @@ -4270,8 +4270,8 @@ njs_key_ext_algorithm(njs_vm_t *vm, njs_ /* HmacKeyGenParams */ name = njs_algorithm_hash_name(key->hash); - ret = njs_vm_value_string_set(vm, njs_value_arg(&val), name->start, - name->length); + ret = njs_vm_value_string_create(vm, njs_value_arg(&val), name->start, + name->length); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } @@ -4320,12 +4320,12 @@ njs_key_ext_type(njs_vm_t *vm, njs_objec } if (key->alg->raw) { - (void) njs_vm_value_string_set(vm, retval, (u_char *) "secret", - njs_length("secret")); + (void) njs_vm_value_string_create(vm, retval, (u_char *) "secret", + njs_length("secret")); } else { type = key->u.a.privat ? "private": "public"; - (void) njs_vm_value_string_set(vm, retval, (u_char *) type, - key->u.a.privat ? 7 : 6); + (void) njs_vm_value_string_create(vm, retval, (u_char *) type, + key->u.a.privat ? 7 : 6); } return NJS_OK; @@ -4544,8 +4544,8 @@ njs_key_ops(njs_vm_t *vm, njs_value_t *r return NJS_ERROR; } - ret = njs_vm_value_string_set(vm, value, e->name.start, - e->name.length); + ret = njs_vm_value_string_create(vm, value, e->name.start, + e->name.length); if (ret != NJS_OK) { return NJS_ERROR; } diff -r dec46ad52e9a -r 4e0553f7ea68 external/njs_xml_module.c --- a/external/njs_xml_module.c Fri May 17 21:54:49 2024 -0700 +++ b/external/njs_xml_module.c Fri May 17 21:54:50 2024 -0700 @@ -584,8 +584,8 @@ njs_xml_node_ext_prop_keys(njs_vm_t *vm, return NJS_ERROR; } - ret = njs_vm_value_string_set(vm, push, (u_char *) "$name", - njs_length("$name")); + ret = njs_vm_value_string_create(vm, push, (u_char *) "$name", + njs_length("$name")); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } @@ -597,8 +597,8 @@ njs_xml_node_ext_prop_keys(njs_vm_t *vm, return NJS_ERROR; } - ret = njs_vm_value_string_set(vm, push, (u_char *) "$ns", - njs_length("$ns")); + ret = njs_vm_value_string_create(vm, push, (u_char *) "$ns", + njs_length("$ns")); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } @@ -610,8 +610,8 @@ njs_xml_node_ext_prop_keys(njs_vm_t *vm, return NJS_ERROR; } - ret = njs_vm_value_string_set(vm, push, (u_char *) "$attrs", - njs_length("$attrs")); + ret = njs_vm_value_string_create(vm, push, (u_char *) "$attrs", + njs_length("$attrs")); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } @@ -623,8 +623,8 @@ njs_xml_node_ext_prop_keys(njs_vm_t *vm, return NJS_ERROR; } - ret = njs_vm_value_string_set(vm, push, (u_char *) "$text", - njs_length("$text")); + ret = njs_vm_value_string_create(vm, push, (u_char *) "$text", + njs_length("$text")); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } @@ -640,8 +640,8 @@ njs_xml_node_ext_prop_keys(njs_vm_t *vm, return NJS_ERROR; } - ret = njs_vm_value_string_set(vm, push, (u_char *) "$tags", - njs_length("$tags")); + ret = njs_vm_value_string_create(vm, push, (u_char *) "$tags", + njs_length("$tags")); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } diff -r dec46ad52e9a -r 4e0553f7ea68 nginx/ngx_http_js_module.c --- a/nginx/ngx_http_js_module.c Fri May 17 21:54:49 2024 -0700 +++ b/nginx/ngx_http_js_module.c Fri May 17 21:54:50 2024 -0700 @@ -1144,8 +1144,8 @@ ngx_http_js_body_filter(ngx_http_request njs_value_assign(&arguments[0], &ctx->request); - njs_vm_value_string_set(ctx->vm, njs_value_arg(&last_key), - last_str.start, last_str.length); + njs_vm_value_string_create(ctx->vm, njs_value_arg(&last_key), + last_str.start, last_str.length); while (in != NULL) { ctx->buf = in->buf; @@ -1474,7 +1474,7 @@ ngx_http_js_ext_keys_header(njs_vm_t *vm return NJS_ERROR; } - rc = njs_vm_value_string_set(vm, value, h->key.data, h->key.len); + rc = njs_vm_value_string_create(vm, value, h->key.data, h->key.len); if (rc != NJS_OK) { return NJS_ERROR; } @@ -1586,7 +1586,7 @@ ngx_http_js_ext_raw_header(njs_vm_t *vm, return NJS_ERROR; } - rc = njs_vm_value_string_set(vm, elem, h->key.data, h->key.len); + rc = njs_vm_value_string_create(vm, elem, h->key.data, h->key.len); if (rc != NJS_OK) { return NJS_ERROR; } @@ -1596,7 +1596,7 @@ ngx_http_js_ext_raw_header(njs_vm_t *vm, return NJS_ERROR; } - rc = njs_vm_value_string_set(vm, elem, h->value.data, h->value.len); + rc = njs_vm_value_string_create(vm, elem, h->value.data, h->value.len); if (rc != NJS_OK) { return NJS_ERROR; } @@ -1703,7 +1703,8 @@ ngx_http_js_header_single(njs_vm_t *vm, return NJS_DECLINED; } - rc = njs_vm_value_string_set(vm, retval, h->value.data, h->value.len); + rc = njs_vm_value_string_create(vm, retval, h->value.data, + h->value.len); if (rc != NJS_OK) { return NJS_ERROR; } @@ -1845,8 +1846,8 @@ ngx_http_js_header_array(njs_vm_t *vm, n return NJS_ERROR; } - rc = njs_vm_value_string_set(vm, value, h->value.data, - h->value.len); + rc = njs_vm_value_string_create(vm, value, h->value.data, + h->value.len); if (rc != NJS_OK) { return NJS_ERROR; } @@ -1934,7 +1935,7 @@ ngx_http_js_header_generic(njs_vm_t *vm, return NJS_DECLINED; } - return njs_vm_value_string_set(vm, retval, start, p - start); + return njs_vm_value_string_create(vm, retval, start, p - start); } header = part->elts; @@ -2110,8 +2111,8 @@ ngx_http_js_ext_keys_header_out(njs_vm_t return NJS_ERROR; } - rc = njs_vm_value_string_set(vm, value, (u_char *) "Content-Type", - njs_length("Content-Type")); + rc = njs_vm_value_string_create(vm, value, (u_char *) "Content-Type", + njs_length("Content-Type")); if (rc != NJS_OK) { return NJS_ERROR; } @@ -2125,8 +2126,8 @@ ngx_http_js_ext_keys_header_out(njs_vm_t return NJS_ERROR; } - rc = njs_vm_value_string_set(vm, value, (u_char *) "Content-Length", - njs_length("Content-Length")); + rc = njs_vm_value_string_create(vm, value, (u_char *) "Content-Length", + njs_length("Content-Length")); if (rc != NJS_OK) { return NJS_ERROR; } @@ -2573,7 +2574,7 @@ ngx_http_js_ext_get_http_version(njs_vm_ break; } - return njs_vm_value_string_set(vm, retval, v.data, v.len); + return njs_vm_value_string_create(vm, retval, v.data, v.len); } @@ -2610,8 +2611,8 @@ ngx_http_js_ext_get_remote_address(njs_v c = r->connection; - return njs_vm_value_string_set(vm, retval, c->addr_text.data, - c->addr_text.len); + return njs_vm_value_string_create(vm, retval, c->addr_text.data, + c->addr_text.len); } @@ -2819,52 +2820,36 @@ static njs_int_t ngx_http_js_header_in_array(njs_vm_t *vm, ngx_http_request_t *r, ngx_array_t *array, u_char sep, njs_value_t *retval) { - u_char *p, *end; - size_t len; + njs_chb_t chain; + njs_int_t ret; ngx_uint_t i, n; ngx_table_elt_t **hh; n = array->nelts; hh = array->elts; - len = 0; - - for (i = 0; i < n; i++) { - len += hh[i]->value.len + 1; - } - - if (len == 0) { + if (n == 0) { njs_value_undefined_set(retval); return NJS_DECLINED; } - len -= 1; - if (n == 1) { - return njs_vm_value_string_set(vm, retval, (*hh)->value.data, - (*hh)->value.len); - } - - p = njs_vm_value_string_alloc(vm, retval, len); - if (p == NULL) { - return NJS_ERROR; - } - - end = p + len; - - - for (i = 0; /* void */ ; i++) { - - p = ngx_copy(p, hh[i]->value.data, hh[i]->value.len); - - if (p == end) { - break; - } - - *p++ = sep; - } - - return NJS_OK; + return njs_vm_value_string_create(vm, retval, (*hh)->value.data, + (*hh)->value.len); + } + + NJS_CHB_MP_INIT(&chain, vm); + + for (i = 0; i < n; i++) { + njs_chb_append(&chain, hh[i]->value.data, hh[i]->value.len); + njs_chb_append(&chain, &sep, 1); + } + + ret = njs_vm_value_string_create_chb(vm, retval, &chain); + + njs_chb_destroy(&chain); + + return ret; } #else static njs_int_t @@ -3889,9 +3874,9 @@ ngx_http_js_header_generic(njs_vm_t *vm, ngx_list_t *headers, ngx_table_elt_t **ph, unsigned flags, njs_str_t *name, njs_value_t *retval) { - u_char *p, sep; - ssize_t size; - njs_int_t rc; + u_char sep; + njs_chb_t chain; + njs_int_t rc, ret; ngx_uint_t i; njs_value_t *value; ngx_list_part_t *part; @@ -3949,8 +3934,8 @@ ngx_http_js_header_generic(njs_vm_t *vm, return NJS_ERROR; } - rc = njs_vm_value_string_set(vm, value, h->value.data, - h->value.len); + rc = njs_vm_value_string_create(vm, value, h->value.data, + h->value.len); if (rc != NJS_OK) { return NJS_ERROR; } @@ -3960,34 +3945,25 @@ ngx_http_js_header_generic(njs_vm_t *vm, } if ((*ph)->next == NULL || flags & NJS_HEADER_SINGLE) { - return njs_vm_value_string_set(vm, retval, (*ph)->value.data, - (*ph)->value.len); - } - - size = - (ssize_t) njs_length("; "); - - for (h = *ph; h; h = h->next) { - size += h->value.len + njs_length("; "); - } - - p = njs_vm_value_string_alloc(vm, retval, size); - if (p == NULL) { - return NJS_ERROR; - } + return njs_vm_value_string_create(vm, retval, (*ph)->value.data, + (*ph)->value.len); + } + + NJS_CHB_MP_INIT(&chain, vm); sep = flags & NJS_HEADER_SEMICOLON ? ';' : ','; for (h = *ph; h; h = h->next) { - p = ngx_copy(p, h->value.data, h->value.len); - - if (h->next == NULL) { - break; - } - - *p++ = sep; *p++ = ' '; - } - - return NJS_OK; + njs_chb_append(&chain, h->value.data, h->value.len); + njs_chb_append(&chain, &sep, 1); + njs_chb_append_literal(&chain, " "); + } + + ret = njs_vm_value_string_create_chb(vm, retval, &chain); + + njs_chb_destroy(&chain); + + return ret; } #endif @@ -4016,7 +3992,7 @@ static njs_int_t ngx_http_js_content_length(njs_vm_t *vm, ngx_http_request_t *r, unsigned flags, njs_str_t *v, njs_value_t *setval, njs_value_t *retval) { - u_char *p, *start; + u_char *p; njs_int_t rc; ngx_int_t n; ngx_table_elt_t *h; @@ -4028,14 +4004,8 @@ ngx_http_js_content_length(njs_vm_t *vm, { p = ngx_sprintf(content_len, "%O", r->headers_out.content_length_n); - start = njs_vm_value_string_alloc(vm, retval, p - content_len); - if (start == NULL) { - return NJS_ERROR; - } - - ngx_memcpy(start, content_len, p - content_len); - - return NJS_OK; + return njs_vm_value_string_create(vm, retval, content_len, + p - content_len); } } @@ -4084,7 +4054,7 @@ ngx_http_js_content_type(njs_vm_t *vm, n return NJS_OK; } - return njs_vm_value_string_set(vm, retval, hdr->data, hdr->len); + return njs_vm_value_string_create(vm, retval, hdr->data, hdr->len); } if (setval != NULL && njs_value_is_array(setval)) { diff -r dec46ad52e9a -r 4e0553f7ea68 nginx/ngx_js.c --- a/nginx/ngx_js.c Fri May 17 21:54:49 2024 -0700 +++ b/nginx/ngx_js.c Fri May 17 21:54:50 2024 -0700 @@ -668,7 +668,7 @@ ngx_js_ext_string(njs_vm_t *vm, njs_obje field = (ngx_str_t *) (p + njs_vm_prop_magic32(prop)); - return njs_vm_value_string_set(vm, retval, field->data, field->len); + return njs_vm_value_string_create(vm, retval, field->data, field->len); } @@ -745,15 +745,15 @@ njs_int_t ngx_js_ext_build(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - return njs_vm_value_string_set(vm, retval, + return njs_vm_value_string_create(vm, retval, #ifdef NGX_BUILD - (u_char *) NGX_BUILD, - njs_strlen(NGX_BUILD) + (u_char *) NGX_BUILD, + njs_strlen(NGX_BUILD) #else - (u_char *) "", - 0 + (u_char *) "", + 0 #endif - ); + ); } @@ -761,8 +761,8 @@ njs_int_t ngx_js_ext_conf_file_path(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - return njs_vm_value_string_set(vm, retval, ngx_cycle->conf_file.data, - ngx_cycle->conf_file.len); + return njs_vm_value_string_create(vm, retval, ngx_cycle->conf_file.data, + ngx_cycle->conf_file.len); } @@ -770,8 +770,8 @@ njs_int_t ngx_js_ext_conf_prefix(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - return njs_vm_value_string_set(vm, retval, ngx_cycle->conf_prefix.data, - ngx_cycle->conf_prefix.len); + return njs_vm_value_string_create(vm, retval, ngx_cycle->conf_prefix.data, + ngx_cycle->conf_prefix.len); } @@ -779,8 +779,8 @@ njs_int_t ngx_js_ext_error_log_path(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - return njs_vm_value_string_set(vm, retval, ngx_cycle->error_log.data, - ngx_cycle->error_log.len); + return njs_vm_value_string_create(vm, retval, ngx_cycle->error_log.data, + ngx_cycle->error_log.len); } @@ -788,8 +788,8 @@ njs_int_t ngx_js_ext_prefix(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - return njs_vm_value_string_set(vm, retval, ngx_cycle->prefix.data, - ngx_cycle->prefix.len); + return njs_vm_value_string_create(vm, retval, ngx_cycle->prefix.data, + ngx_cycle->prefix.len); } @@ -797,8 +797,8 @@ njs_int_t ngx_js_ext_version(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - return njs_vm_value_string_set(vm, retval, (u_char *) NGINX_VERSION, - njs_strlen(NGINX_VERSION)); + return njs_vm_value_string_create(vm, retval, (u_char *) NGINX_VERSION, + njs_strlen(NGINX_VERSION)); } diff -r dec46ad52e9a -r 4e0553f7ea68 nginx/ngx_js.h --- a/nginx/ngx_js.h Fri May 17 21:54:49 2024 -0700 +++ b/nginx/ngx_js.h Fri May 17 21:54:50 2024 -0700 @@ -175,7 +175,7 @@ struct ngx_js_ctx_s { #define ngx_js_prop(vm, type, value, start, len) \ - ((type == NGX_JS_STRING) ? njs_vm_value_string_set(vm, value, start, len) \ + ((type == NGX_JS_STRING) ? njs_vm_value_string_create(vm, value, start, len) \ : njs_vm_value_buffer_set(vm, value, start, len)) diff -r dec46ad52e9a -r 4e0553f7ea68 nginx/ngx_js_fetch.c --- a/nginx/ngx_js_fetch.c Fri May 17 21:54:49 2024 -0700 +++ b/nginx/ngx_js_fetch.c Fri May 17 21:54:50 2024 -0700 @@ -3237,8 +3237,8 @@ ngx_headers_js_get(njs_vm_t *vm, njs_val return NJS_ERROR; } - rc = njs_vm_value_string_set(vm, value, ph->value.data, - ph->value.len); + rc = njs_vm_value_string_create(vm, value, ph->value.data, + ph->value.len); if (rc != NJS_OK) { return NJS_ERROR; } @@ -3283,7 +3283,7 @@ ngx_headers_js_get(njs_vm_t *vm, njs_val h = h->next; } - return njs_vm_value_string_set(vm, retval, data, p - data); + return njs_vm_value_string_create(vm, retval, data, p - data); } @@ -3574,8 +3574,8 @@ ngx_headers_js_ext_keys(njs_vm_t *vm, nj return NJS_ERROR; } - rc = njs_vm_value_string_set(vm, value, h[i].key.data, - h[i].key.len); + rc = njs_vm_value_string_create(vm, value, h[i].key.data, + h[i].key.len); if (rc != NJS_OK) { return NJS_ERROR; } @@ -3709,9 +3709,9 @@ ngx_request_js_ext_body(njs_vm_t *vm, nj case NGX_JS_BODY_JSON: case NGX_JS_BODY_TEXT: default: - ret = njs_vm_value_string_set(vm, njs_value_arg(&result), - request->body.start, - request->body.length); + ret = njs_vm_value_string_create(vm, njs_value_arg(&result), + request->body.start, + request->body.length); if (ret != NJS_OK) { njs_vm_memory_error(vm); return NJS_ERROR; @@ -3869,8 +3869,8 @@ ngx_response_js_ext_body(njs_vm_t *vm, n case NGX_JS_BODY_JSON: case NGX_JS_BODY_TEXT: default: - ret = njs_vm_value_string_set(vm, njs_value_arg(&result), - string.start, string.length); + ret = njs_vm_value_string_create(vm, njs_value_arg(&result), + string.start, string.length); if (ret != NJS_OK) { njs_vm_memory_error(vm); return NJS_ERROR; @@ -3985,8 +3985,8 @@ ngx_response_js_ext_status_text(njs_vm_t return NJS_DECLINED; } - njs_vm_value_string_set(vm, retval, response->status_text.start, - response->status_text.length); + njs_vm_value_string_create(vm, retval, response->status_text.start, + response->status_text.length); return NJS_OK; } @@ -4004,8 +4004,8 @@ ngx_response_js_ext_type(njs_vm_t *vm, n return NJS_DECLINED; } - return njs_vm_value_string_set(vm, retval, (u_char *) "basic", - njs_length("basic")); + return njs_vm_value_string_create(vm, retval, (u_char *) "basic", + njs_length("basic")); } @@ -4017,8 +4017,8 @@ ngx_fetch_flag(njs_vm_t *vm, const ngx_j for (e = entries; e->name.length != 0; e++) { if (e->value == value) { - return njs_vm_value_string_set(vm, retval, e->name.start, - e->name.length); + return njs_vm_value_string_create(vm, retval, e->name.start, + e->name.length); } } diff -r dec46ad52e9a -r 4e0553f7ea68 nginx/ngx_js_shared_dict.c --- a/nginx/ngx_js_shared_dict.c Fri May 17 21:54:49 2024 -0700 +++ b/nginx/ngx_js_shared_dict.c Fri May 17 21:54:50 2024 -0700 @@ -423,8 +423,8 @@ njs_js_ext_global_shared_keys(njs_vm_t * return NJS_ERROR; } - rc = njs_vm_value_string_set(vm, value, shm_zone->shm.name.data, - shm_zone->shm.name.len); + rc = njs_vm_value_string_create(vm, value, shm_zone->shm.name.data, + shm_zone->shm.name.len); if (rc != NJS_OK) { return NJS_ERROR; } @@ -698,8 +698,8 @@ njs_js_ext_shared_dict_keys(njs_vm_t *vm goto fail; } - rc = njs_vm_value_string_set(vm, value, node->sn.str.data, - node->sn.str.len); + rc = njs_vm_value_string_create(vm, value, node->sn.str.data, + node->sn.str.len); if (rc != NJS_OK) { goto fail; } @@ -853,8 +853,8 @@ njs_js_ext_shared_dict_items(njs_vm_t *v goto fail; } - rc = njs_vm_value_string_set(vm, value, node->sn.str.data, - node->sn.str.len); + rc = njs_vm_value_string_create(vm, value, node->sn.str.data, + node->sn.str.len); if (rc != NJS_OK) { goto fail; } @@ -896,8 +896,8 @@ njs_js_ext_shared_dict_name(njs_vm_t *vm return NJS_DECLINED; } - return njs_vm_value_string_set(vm, retval, shm_zone->shm.name.data, - shm_zone->shm.name.len); + return njs_vm_value_string_create(vm, retval, shm_zone->shm.name.data, + shm_zone->shm.name.len); } @@ -1063,7 +1063,7 @@ njs_js_ext_shared_dict_type(njs_vm_t *vm break; } - return njs_vm_value_string_set(vm, retval, type.start, type.length); + return njs_vm_value_string_create(vm, retval, type.start, type.length); } @@ -1406,7 +1406,8 @@ ngx_js_dict_copy_value_locked(njs_vm_t * return NGX_ERROR; } - ret = njs_vm_value_string_set(vm, retval, string.start, string.length); + ret = njs_vm_value_string_create(vm, retval, string.start, + string.length); if (ret != NJS_OK) { return NGX_ERROR; } @@ -1493,8 +1494,8 @@ static njs_int_t ngx_js_dict_shared_error_name(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - return njs_vm_value_string_set(vm, retval, (u_char *) "SharedMemoryError", - 17); + return njs_vm_value_string_create(vm, retval, + (u_char *) "SharedMemoryError", 17); } diff -r dec46ad52e9a -r 4e0553f7ea68 nginx/ngx_stream_js_module.c --- a/nginx/ngx_stream_js_module.c Fri May 17 21:54:49 2024 -0700 +++ b/nginx/ngx_stream_js_module.c Fri May 17 21:54:50 2024 -0700 @@ -1241,8 +1241,8 @@ ngx_stream_js_ext_get_remote_address(njs c = s->connection; - return njs_vm_value_string_set(vm, retval, c->addr_text.data, - c->addr_text.len); + return njs_vm_value_string_create(vm, retval, c->addr_text.data, + c->addr_text.len); } diff -r dec46ad52e9a -r 4e0553f7ea68 src/njs.h --- a/src/njs.h Fri May 17 21:54:49 2024 -0700 +++ b/src/njs.h Fri May 17 21:54:50 2024 -0700 @@ -400,14 +400,6 @@ NJS_EXPORT njs_int_t njs_value_to_intege /* Gets string value, no copy. */ NJS_EXPORT void njs_value_string_get(njs_value_t *value, njs_str_t *dst); -/* - * Sets a byte string value. - * start data is not copied and should not be freed. - */ -NJS_EXPORT njs_int_t njs_vm_value_string_set(njs_vm_t *vm, njs_value_t *value, - const u_char *start, uint32_t size); -NJS_EXPORT u_char *njs_vm_value_string_alloc(njs_vm_t *vm, njs_value_t *value, - uint32_t size); NJS_EXPORT njs_int_t njs_vm_value_string_create(njs_vm_t *vm, njs_value_t *value, const u_char *start, uint32_t size); NJS_EXPORT njs_int_t njs_vm_value_string_create_chb(njs_vm_t *vm, diff -r dec46ad52e9a -r 4e0553f7ea68 src/njs_string.c --- a/src/njs_string.c Fri May 17 21:54:49 2024 -0700 +++ b/src/njs_string.c Fri May 17 21:54:50 2024 -0700 @@ -3152,7 +3152,7 @@ njs_string_get_substitution(njs_vm_t *vm p += 2; - ret = njs_vm_value_string_set(vm, &name, p, r - p); + ret = njs_string_create(vm, &name, (const char *) p, r - p); if (njs_slow_path(ret != NJS_OK)) { goto exception; } diff -r dec46ad52e9a -r 4e0553f7ea68 src/njs_vm.c --- a/src/njs_vm.c Fri May 17 21:54:49 2024 -0700 +++ b/src/njs_vm.c Fri May 17 21:54:50 2024 -0700 @@ -946,14 +946,6 @@ njs_value_string_get(njs_value_t *value, njs_int_t -njs_vm_value_string_set(njs_vm_t *vm, njs_value_t *value, const u_char *start, - uint32_t size) -{ - return njs_string_set(vm, value, start, size); -} - - -njs_int_t njs_vm_value_array_buffer_set(njs_vm_t *vm, njs_value_t *value, const u_char *start, uint32_t size) { @@ -981,13 +973,6 @@ njs_vm_value_buffer_set(njs_vm_t *vm, nj } -u_char * -njs_vm_value_string_alloc(njs_vm_t *vm, njs_value_t *value, uint32_t size) -{ - return njs_string_alloc(vm, value, size, 0); -} - - njs_int_t njs_vm_value_string_create(njs_vm_t *vm, njs_value_t *value, const u_char *start, uint32_t size) @@ -1342,7 +1327,7 @@ njs_vm_object_prop(njs_vm_t *vm, njs_val return NULL; } - ret = njs_vm_value_string_set(vm, &key, prop->start, prop->length); + ret = njs_vm_value_string_create(vm, &key, prop->start, prop->length); if (njs_slow_path(ret != NJS_OK)) { return NULL; } @@ -1368,7 +1353,7 @@ njs_vm_object_prop_set(njs_vm_t *vm, njs return NJS_ERROR; } - ret = njs_vm_value_string_set(vm, &key, prop->start, prop->length); + ret = njs_vm_value_string_create(vm, &key, prop->start, prop->length); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } diff -r dec46ad52e9a -r 4e0553f7ea68 src/test/njs_benchmark.c --- a/src/test/njs_benchmark.c Fri May 17 21:54:49 2024 -0700 +++ b/src/test/njs_benchmark.c Fri May 17 21:54:50 2024 -0700 @@ -188,10 +188,10 @@ njs_benchmark_test(njs_vm_t *parent, njs goto done; } - ret = njs_vm_value_string_set(parent, &name, (u_char *) test->name, - njs_strlen(test->name)); + ret = njs_vm_value_string_create(parent, &name, (u_char *) test->name, + njs_strlen(test->name)); if (ret != NJS_OK) { - njs_printf("njs_vm_value_string_set() failed\n"); + njs_printf("njs_vm_value_string_create() failed\n"); goto done; } @@ -595,10 +595,10 @@ main(int argc, char **argv) } if (opts.previous) { - ret = njs_vm_value_string_set(vm, &args[0], (u_char *) opts.previous, - njs_strlen(opts.previous)); + ret = njs_vm_value_string_create(vm, &args[0], (u_char *) opts.previous, + njs_strlen(opts.previous)); if (ret != NJS_OK) { - njs_printf("njs_vm_value_string_set() failed\n"); + njs_printf("njs_vm_value_string_create() failed\n"); goto done; } diff -r dec46ad52e9a -r 4e0553f7ea68 src/test/njs_externals_test.c --- a/src/test/njs_externals_test.c Fri May 17 21:54:49 2024 -0700 +++ b/src/test/njs_externals_test.c Fri May 17 21:54:50 2024 -0700 @@ -158,7 +158,7 @@ njs_unit_test_r_uri(njs_vm_t *vm, njs_ob return njs_vm_value_to_bytes(vm, field, setval); } - return njs_vm_value_string_set(vm, retval, field->start, field->length); + return njs_vm_value_string_create(vm, retval, field->start, field->length); } @@ -178,7 +178,7 @@ njs_unit_test_r_a(njs_vm_t *vm, njs_obje p = njs_sprintf(buf, buf + njs_length(buf), "%uD", r->a); - return njs_vm_value_string_set(vm, retval, buf, p - buf); + return njs_vm_value_string_create(vm, retval, buf, p - buf); } @@ -214,7 +214,7 @@ static njs_int_t njs_unit_test_r_host(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - return njs_vm_value_string_set(vm, retval, (u_char *) "АБВГДЕЁЖЗИЙ", 22); + return njs_vm_value_string_create(vm, retval, (u_char *) "АБВГДЕЁЖЗИЙ", 22); } @@ -264,7 +264,7 @@ njs_unit_test_r_vars(njs_vm_t *vm, njs_o if (setval != NULL) { /* Set. */ - njs_vm_value_string_set(vm, &name, lhq.key.start, lhq.key.length); + njs_vm_value_string_create(vm, &name, lhq.key.start, lhq.key.length); prop = lvlhsh_unit_test_alloc(vm->mem_pool, &name, setval); if (prop == NULL) { njs_memory_error(vm); @@ -313,24 +313,22 @@ static njs_int_t njs_unit_test_r_header(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *unused, njs_value_t *retval) { - u_char *p; - uint32_t size; njs_int_t ret; njs_str_t h; + njs_chb_t chain; ret = njs_vm_prop_name(vm, prop, &h); if (ret == NJS_OK) { - size = 7 + h.length; + NJS_CHB_MP_INIT(&chain, vm); + + njs_chb_append(&chain, h.start, h.length); + njs_chb_append(&chain, (u_char *) "|АБВ", njs_length("|АБВ")); - p = njs_vm_value_string_alloc(vm, retval, size); - if (p == NULL) { - return NJS_ERROR; - } + ret = njs_vm_value_string_create_chb(vm, retval, &chain); - p = njs_cpymem(p, h.start, h.length); - *p++ = '|'; - memcpy(p, "АБВ", njs_length("АБВ")); - return NJS_OK; + njs_chb_destroy(&chain); + + return ret; } njs_value_undefined_set(retval); @@ -360,7 +358,7 @@ njs_unit_test_r_header_keys(njs_vm_t *vm From xeioex at nginx.com Sat May 18 04:55:29 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Sat, 18 May 2024 04:55:29 +0000 Subject: [njs] Removing njs_string_set() from builtin functions. Message-ID: details: https://hg.nginx.org/njs/rev/8851a78723dc branches: changeset: 2330:8851a78723dc user: Dmitry Volyntsev date: Fri May 17 21:54:50 2024 -0700 description: Removing njs_string_set() from builtin functions. This is the last function that produced byte strings. diffstat: src/njs_builtin.c | 9 ++++----- src/njs_error.c | 2 +- src/njs_extern.c | 5 +++-- src/njs_parser.c | 2 +- src/njs_regexp.c | 4 ++-- src/njs_string.c | 4 ++-- src/njs_string.h | 3 ++- src/njs_vm.c | 4 ++-- src/test/njs_benchmark.c | 2 +- 9 files changed, 18 insertions(+), 17 deletions(-) diffs (159 lines): diff -r 4e0553f7ea68 -r 8851a78723dc src/njs_builtin.c --- a/src/njs_builtin.c Fri May 17 21:54:50 2024 -0700 +++ b/src/njs_builtin.c Fri May 17 21:54:50 2024 -0700 @@ -1201,8 +1201,8 @@ njs_process_object_argv(njs_vm_t *vm, nj i = 0; for (arg = vm->options.argv; i < vm->options.argc; arg++) { - njs_string_set(vm, &argv->start[i++], (u_char *) *arg, - njs_strlen(*arg)); + njs_string_create(vm, &argv->start[i++], (u_char *) *arg, + njs_strlen(*arg)); } prop = njs_object_prop_alloc(vm, &argv_string, &njs_value_undefined, 1); @@ -1265,7 +1265,7 @@ njs_env_hash_init(njs_vm_t *vm, njs_lvlh continue; } - ret = njs_string_create(vm, &prop->name, (char *) entry, val - entry); + ret = njs_string_create(vm, &prop->name, entry, val - entry); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } @@ -1285,8 +1285,7 @@ njs_env_hash_init(njs_vm_t *vm, njs_lvlh val++; - ret = njs_string_create(vm, njs_prop_value(prop), (char *) val, - njs_strlen(val)); + ret = njs_string_create(vm, njs_prop_value(prop), val, njs_strlen(val)); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } diff -r 4e0553f7ea68 -r 8851a78723dc src/njs_error.c --- a/src/njs_error.c Fri May 17 21:54:50 2024 -0700 +++ b/src/njs_error.c Fri May 17 21:54:50 2024 -0700 @@ -147,7 +147,7 @@ njs_error_stack_new(njs_vm_t *vm, njs_ob return ret; } - return njs_string_set(vm, retval, string.start, string.length); + return njs_string_create(vm, retval, string.start, string.length); } diff -r 4e0553f7ea68 -r 8851a78723dc src/njs_extern.c --- a/src/njs_extern.c Fri May 17 21:54:50 2024 -0700 +++ b/src/njs_extern.c Fri May 17 21:54:50 2024 -0700 @@ -74,8 +74,9 @@ njs_external_add(njs_vm_t *vm, njs_arr_t lhq.key_hash = external->name.symbol; } else { - ret = njs_string_set(vm, &prop->name, external->name.string.start, - external->name.string.length); + ret = njs_string_create(vm, &prop->name, + external->name.string.start, + external->name.string.length); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } diff -r 4e0553f7ea68 -r 8851a78723dc src/njs_parser.c --- a/src/njs_parser.c Fri May 17 21:54:50 2024 -0700 +++ b/src/njs_parser.c Fri May 17 21:54:50 2024 -0700 @@ -9242,7 +9242,7 @@ njs_parser_error(njs_vm_t *vm, njs_objec njs_value_property_set(vm, &error, njs_value_arg(&line_number), &value); if (file->length != 0) { - ret = njs_string_set(vm, &value, file->start, file->length); + ret = njs_string_create(vm, &value, file->start, file->length); if (ret == NJS_OK) { njs_value_property_set(vm, &error, njs_value_arg(&file_name), &value); diff -r 4e0553f7ea68 -r 8851a78723dc src/njs_regexp.c --- a/src/njs_regexp.c Fri May 17 21:54:50 2024 -0700 +++ b/src/njs_regexp.c Fri May 17 21:54:50 2024 -0700 @@ -1144,8 +1144,8 @@ njs_regexp_exec_result(njs_vm_t *vm, njs do { group = &pattern->groups[i]; - ret = njs_string_set(vm, &name, group->name.start, - group->name.length); + ret = njs_string_create(vm, &name, group->name.start, + group->name.length); if (njs_slow_path(ret != NJS_OK)) { goto fail; } diff -r 4e0553f7ea68 -r 8851a78723dc src/njs_string.c --- a/src/njs_string.c Fri May 17 21:54:50 2024 -0700 +++ b/src/njs_string.c Fri May 17 21:54:50 2024 -0700 @@ -127,7 +127,7 @@ njs_string_set(njs_vm_t *vm, njs_value_t njs_int_t -njs_string_create(njs_vm_t *vm, njs_value_t *value, const char *src, +njs_string_create(njs_vm_t *vm, njs_value_t *value, const u_char *src, size_t size) { u_char *p, *p_end; @@ -3152,7 +3152,7 @@ njs_string_get_substitution(njs_vm_t *vm p += 2; - ret = njs_string_create(vm, &name, (const char *) p, r - p); + ret = njs_string_create(vm, &name, p, r - p); if (njs_slow_path(ret != NJS_OK)) { goto exception; } diff -r 4e0553f7ea68 -r 8851a78723dc src/njs_string.h --- a/src/njs_string.h Fri May 17 21:54:50 2024 -0700 +++ b/src/njs_string.h Fri May 17 21:54:50 2024 -0700 @@ -103,13 +103,14 @@ typedef enum { } njs_trim_t; +/* njs_string_set() Is deprecated. */ njs_int_t njs_string_set(njs_vm_t *vm, njs_value_t *value, const u_char *start, uint32_t size); u_char *njs_string_alloc(njs_vm_t *vm, njs_value_t *value, uint64_t size, uint64_t length); njs_int_t njs_string_new(njs_vm_t *vm, njs_value_t *value, const u_char *start, uint32_t size, uint32_t length); -njs_int_t njs_string_create(njs_vm_t *vm, njs_value_t *value, const char *src, +njs_int_t njs_string_create(njs_vm_t *vm, njs_value_t *value, const u_char *src, size_t size); njs_int_t njs_string_create_chb(njs_vm_t *vm, njs_value_t *value, njs_chb_t *chain); diff -r 4e0553f7ea68 -r 8851a78723dc src/njs_vm.c --- a/src/njs_vm.c Fri May 17 21:54:50 2024 -0700 +++ b/src/njs_vm.c Fri May 17 21:54:50 2024 -0700 @@ -843,7 +843,7 @@ njs_vm_value(njs_vm_t *vm, const njs_str return NJS_ERROR; } - ret = njs_string_set(vm, &key, start, size); + ret = njs_string_create(vm, &key, start, size); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } @@ -977,7 +977,7 @@ njs_int_t njs_vm_value_string_create(njs_vm_t *vm, njs_value_t *value, const u_char *start, uint32_t size) { - return njs_string_create(vm, value, (const char *) start, size); + return njs_string_create(vm, value, start, size); } diff -r 4e0553f7ea68 -r 8851a78723dc src/test/njs_benchmark.c --- a/src/test/njs_benchmark.c Fri May 17 21:54:50 2024 -0700 +++ b/src/test/njs_benchmark.c Fri May 17 21:54:50 2024 -0700 @@ -715,7 +715,7 @@ njs_benchmark_string(njs_vm_t *vm, njs_v } else if (memcmp(mode.start, "create", 6) == 0) { for (i = 0; i < n; i++) { - njs_string_create(vm, &value, (char *) s.start, s.length); + njs_string_create(vm, &value, s.start, s.length); } } else { From bonet at grenoble.cnrs.fr Sat May 18 12:43:52 2024 From: bonet at grenoble.cnrs.fr (Edgar Bonet) Date: Sat, 18 May 2024 14:43:52 +0200 Subject: [PATCH] Fix compile error in configure script In-Reply-To: <14a3408e-6f08-48c6-96ca-021fa1406142@grenoble.cnrs.fr> References: <39799336-de5d-4373-b95e-e05be1d2973b@grenoble.cnrs.fr> <14a3408e-6f08-48c6-96ca-021fa1406142@grenoble.cnrs.fr> Message-ID: Hello! Yesterday, I wrote: > My understanding is that the compiler considers 'int' and 'long' to be > incompatible types [... On ILP32,] 'size_t' being an 'unsigned int', > it is incompatible with 'long'. > > On LP64 (your typical 64-bit Linux/Mac), 'size_t' is a 'unsigned > long', which is compatible with 'long' but for the signedness warning. I just did a small experiment to confirm all this. It shows that this “incompatible pointer type” error is specific to GCC 14 compiling for 32-bit targets. I natively compiled the following C file: #include void callee(size_t *); void caller(void) { long n; callee(&n); } on three different systems: 1. gcc 11.4 / Ubuntu 22.04 / x86_64 (desktop PC, 64 bits) 2. gcc 12.2 / Debian 12 / i686 (Acer Aspire One A110L, 32 bits) 3. gcc 10.2 / Raspbian 11 / armv6l (Raspberry Pi model B, 32 bits) On the 64-bit PC, the compiler issues no warnings unless I explicitly request them (e.g., with -Wall). If I do so, I get the signedness warning: warning: pointer targets in passing argument 1 of ‘callee’ differ in signedness [-Wpointer-sign] note: expected ‘size_t *’ {aka ‘long unsigned int *’} but argument is of type ‘long int *’ On both 32-bit systems, I get the following warning even with no -W* option: warning: passing argument 1 of ‘callee’ from incompatible pointer type [-Wincompatible-pointer-types] note: expected ‘size_t *’ {aka ‘unsigned int *’} but argument is of type ‘long int *’ This shows that: * ‘size_t’ is ‘unsigned int’ on ILP32 and ‘long unsigned int’ on LP64 * ‘int’ and ’long int’ are considered incompatible even on ILP32, where they have the same size. What changes with GCC 14 is that the “incompatible pointer type” warning has been changed to an error. The GCC 14 porting guide states:[1] Type checking on pointer types (-Werror=incompatible-pointer-types) GCC no longer allows implicitly casting all pointer types to all other pointer types. This is confirmed by the documentation of the option -Wno-incompatible-pointer-types, which contains this sentence:[2] By default, in C99 and later dialects of C, GCC treats this issue as an error. The sentence is absent from the GCC 13 documentation of the same option.[3] Regards, Edgar. [1] https://gcc.gnu.org/gcc-14/porting_to.html#incompatible-pointer-types [2] https://gcc.gnu.org/onlinedocs/gcc-14.1.0/gcc/Warning-Options.html#index-Wno-incompatible-pointer-types [3] https://gcc.gnu.org/onlinedocs/gcc-13.2.0/gcc/Warning-Options.html#index-Wno-incompatible-pointer-types From pluknet at nginx.com Mon May 20 20:20:23 2024 From: pluknet at nginx.com (Sergey Kandaurov) Date: Tue, 21 May 2024 00:20:23 +0400 Subject: [PATCH] Fix compile error in configure script In-Reply-To: <39799336-de5d-4373-b95e-e05be1d2973b@grenoble.cnrs.fr> Message-ID: On Sat, May 18, 2024 at 02:43:52PM +0200, Edgar Bonet wrote: > Hello! > > Yesterday, I wrote: > > My understanding is that the compiler considers 'int' and 'long' to be > > incompatible types [... On ILP32,] 'size_t' being an 'unsigned int', > > it is incompatible with 'long'. > > > > On LP64 (your typical 64-bit Linux/Mac), 'size_t' is a 'unsigned > > long', which is compatible with 'long' but for the signedness warning. > > I just did a small experiment to confirm all this. It shows that this > “incompatible pointer type” error is specific to GCC 14 compiling for > 32-bit targets. I natively compiled the following C file: > > #include > > void callee(size_t *); > > void caller(void) > { > long n; > callee(&n); > } > > on three different systems: > > 1. gcc 11.4 / Ubuntu 22.04 / x86_64 (desktop PC, 64 bits) > 2. gcc 12.2 / Debian 12 / i686 (Acer Aspire One A110L, 32 bits) > 3. gcc 10.2 / Raspbian 11 / armv6l (Raspberry Pi model B, 32 bits) > > On the 64-bit PC, the compiler issues no warnings unless I explicitly > request them (e.g., with -Wall). If I do so, I get the signedness > warning: > > warning: pointer targets in passing argument 1 of ‘callee’ > differ in signedness [-Wpointer-sign] > note: expected ‘size_t *’ {aka ‘long unsigned int *’} > but argument is of type ‘long int *’ > > On both 32-bit systems, I get the following warning even with no -W* > option: > > warning: passing argument 1 of ‘callee’ > from incompatible pointer type [-Wincompatible-pointer-types] > note: expected ‘size_t *’ {aka ‘unsigned int *’} > but argument is of type ‘long int *’ > > This shows that: > > * ‘size_t’ is ‘unsigned int’ on ILP32 and ‘long unsigned int’ on LP64 > > * ‘int’ and ’long int’ are considered incompatible even on ILP32, > where they have the same size. > > What changes with GCC 14 is that the “incompatible pointer type” warning > has been changed to an error. The GCC 14 porting guide states:[1] Thanks for clarification and testing, this matches my observation. Concerning type compatibility, C11 gives a definition on what types are compatible. From the n1548 draft, §6.2.7: : Two types have compatible type if their types are the same. Following "§6.2.5 Types", int and long belong to different types (regardless of signedness). An §6.7.8 example further clarifies compatible type definitions: : typedef struct s1 { int x; } t1, *tp1; : typedef struct s2 { int x; } t2, *tp2; : : type t1 and the type pointed to by tp1 are compatible. Type t1 is : also compatible with type struct s1, but not compatible with the : types struct s2, t2, the type pointed to by tp2, or int. On Thu, May 16, 2024 at 11:25:33AM +0200, Edgar Bonet wrote: > # HG changeset patch > # User Edgar Bonet > # Date 1715850910 -7200 > # Thu May 16 11:15:10 2024 +0200 > # Node ID c2c3b0d74b1a7d3f967421c72760b5c573afcd81 > # Parent 89093b003fcb54c7f8dc66042f17bc4dea4e7709 > Fix compile error in configure script > > Building with GCC 14 fails at the configure step with: > > ./configure: error: libatomic_ops library was not found. > > The error is not caused by a missing library, but by an unrelated > "incompatible pointer type" error in the test program: > > ... > checking for atomic_ops library > objs/autotest.c: In function 'main': > objs/autotest.c:9:48: error: passing argument 1 of 'AO_compare_and_swap' from incompatible pointer type [-Wincompatible-pointer-types] > > Fix the error by using the correct pointer types. > > Signed-off-by: Edgar Bonet > > diff -r 89093b003fcb -r c2c3b0d74b1a auto/lib/libatomic/conf > --- a/auto/lib/libatomic/conf Fri May 03 20:26:05 2024 +0400 > +++ b/auto/lib/libatomic/conf Thu May 16 11:15:10 2024 +0200 > @@ -19,7 +19,7 @@ > #include " > ngx_feature_path= > ngx_feature_libs="-latomic_ops" > - ngx_feature_test="long n = 0; > + ngx_feature_test="AO_t n = 0; > if (!AO_compare_and_swap(&n, 0, 1)) > return 1; > if (AO_fetch_and_add(&n, 1) != 1) I like the patch, but would like to adjust the commit log: there some styles issues and over-quoting. Also, there is no mention of Clang behaviour. Please see below. # HG changeset patch # User Edgar Bonet # Date 1715850910 -7200 # Thu May 16 11:15:10 2024 +0200 # Node ID 8d35d9cfef17f350f750049940e22d1d61d55a6a # Parent 5a5c01ec6f58d413e9867ace5d0065bb43484a11 Configure: fixed building libatomic test. Using "long *" instead of "AO_t *" leads either to -Wincompatible-pointer-types or -Wpointer-sign warnings, depending on whether long and size_t are compatible types (e.g., ILP32 versus LP64 data models). Notably, -Wpointer-sign warnings are enabled by default in Clang only, and -Wincompatible-pointer-types is an error starting from GCC 14. Signed-off-by: Edgar Bonet From bonet at grenoble.cnrs.fr Mon May 20 20:50:41 2024 From: bonet at grenoble.cnrs.fr (Edgar Bonet) Date: Mon, 20 May 2024 22:50:41 +0200 Subject: [PATCH] Fix compile error in configure script In-Reply-To: References: Message-ID: <17728919-9610-410e-bf34-e1123f3e3d2b@grenoble.cnrs.fr> Hello! On 2024-05-20, Sergey Kandaurov wrote: > Concerning type compatibility, C11 gives a definition on what types > are compatible. [...] Thank-you for sharing these findings! > I like the patch, but would like to adjust the commit log: > there some styles issues and over-quoting. Also, there is > no mention of Clang behaviour. Please see below. > > # HG changeset patch > # User Edgar Bonet > # Date 1715850910 -7200 > # Thu May 16 11:15:10 2024 +0200 > # Node ID 8d35d9cfef17f350f750049940e22d1d61d55a6a > # Parent 5a5c01ec6f58d413e9867ace5d0065bb43484a11 > Configure: fixed building libatomic test. > > Using "long *" instead of "AO_t *" leads either to -Wincompatible-pointer-types > or -Wpointer-sign warnings, depending on whether long and size_t are compatible > types (e.g., ILP32 versus LP64 data models). Notably, -Wpointer-sign warnings > are enabled by default in Clang only, and -Wincompatible-pointer-types is an > error starting from GCC 14. > > Signed-off-by: Edgar Bonet This all looks good to me. Regards, Edgar. From xeioex at nginx.com Mon May 20 23:46:18 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Mon, 20 May 2024 23:46:18 +0000 Subject: [njs] HTTP: fixed handling of 0 length request body. Message-ID: details: https://hg.nginx.org/njs/rev/286dbef3c0b2 branches: changeset: 2331:286dbef3c0b2 user: Dmitry Volyntsev date: Mon May 20 16:44:10 2024 -0700 description: HTTP: fixed handling of 0 length request body. Previously, when r.requestBuffer was passed as a body argument to ngx.fetch() or r.subrequest() then exception was thrown "Error: invalid Request body" when the request body had 0 length. diffstat: src/njs_vm.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diffs (16 lines): diff -r 8851a78723dc -r 286dbef3c0b2 src/njs_vm.c --- a/src/njs_vm.c Fri May 17 21:54:50 2024 -0700 +++ b/src/njs_vm.c Mon May 20 16:44:10 2024 -0700 @@ -1602,6 +1602,12 @@ njs_vm_value_to_bytes(njs_vm_t *vm, njs_ } if (njs_slow_path(njs_is_detached_buffer(buffer))) { + if (length == 0) { + dst->length = 0; + dst->start = NULL; + return NJS_OK; + } + njs_type_error(vm, "detached buffer"); return NJS_ERROR; } From pluknet at nginx.com Tue May 21 11:43:20 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Tue, 21 May 2024 11:43:20 +0000 Subject: [nginx] Configure: fixed building libatomic test. Message-ID: details: https://hg.nginx.org/nginx/rev/f58b6f636238 branches: changeset: 9247:f58b6f636238 user: Edgar Bonet date: Thu May 16 11:15:10 2024 +0200 description: Configure: fixed building libatomic test. Using "long *" instead of "AO_t *" leads either to -Wincompatible-pointer-types or -Wpointer-sign warnings, depending on whether long and size_t are compatible types (e.g., ILP32 versus LP64 data models). Notably, -Wpointer-sign warnings are enabled by default in Clang only, and -Wincompatible-pointer-types is an error starting from GCC 14. Signed-off-by: Edgar Bonet diffstat: auto/lib/libatomic/conf | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 89093b003fcb -r f58b6f636238 auto/lib/libatomic/conf --- a/auto/lib/libatomic/conf Fri May 03 20:26:05 2024 +0400 +++ b/auto/lib/libatomic/conf Thu May 16 11:15:10 2024 +0200 @@ -19,7 +19,7 @@ else #include " ngx_feature_path= ngx_feature_libs="-latomic_ops" - ngx_feature_test="long n = 0; + ngx_feature_test="AO_t n = 0; if (!AO_compare_and_swap(&n, 0, 1)) return 1; if (AO_fetch_and_add(&n, 1) != 1) From arut at nginx.com Wed May 22 14:14:26 2024 From: arut at nginx.com (Roman Arutyunyan) Date: Wed, 22 May 2024 18:14:26 +0400 Subject: I think I found a fix for the memory leak issue on gRPC module In-Reply-To: References: Message-ID: <20240522141426.ahzeenwq2qom3m4f@N00W24XTQX> Hi, Indeed there's a problem there. We have similar problems in other places as well. Attached is a patch that fixes all I could find. I did some testing for the sub_filter with the following config. Small buffers exaggerate the problem. http { server { listen 8000; location / { root html; output_buffers 2 128; sub_filter 1 2; sub_filter_types *; sub_filter_once off; } } } Retrieving a 10m file resulted in 7304 (patched) vs 1317704 (unpatched) bytes allocated from the request pool. With the default output_buffers (2 32768), it's 79880 vs 84040. On Thu, May 02, 2024 at 07:59:44AM +0000, Pavel Pautov via nginx-devel wrote: > Hi Sangmin, > > Your analysis looks correct. Client streaming RPCs can lead to unbound accumulation of ngx_chain_t objects (although, at very slow rate). Gzip module had a similar issue (https://trac.nginx.org/nginx/ticket/1046). > Attaching somewhat simplified patch based on yours. I was able to reproduce the issue locally and the patch fixes it. > > From: nginx-devel On Behalf Of Sangmin Lee > Sent: Thursday, April 4, 2024 19:29 > To: nginx-devel at nginx.org > Subject: I think I found a fix for the memory leak issue on gRPC module > > CAUTION: This email has been sent from an external source. Do not click links, open attachments, or provide sensitive business information unless you can verify the sender's legitimacy. > > I am sending this mail again because I did a mistake while I was writing a mail. I didn't know, in gmail, "Ctrl - Enter" would send a mail immediately even without a title! > I am sorry for that, so I am sending again. > > Hello, > > I think I found the main cause of the memory leak issue when using gRPC stream so I made a patch for it. > Please find the test scenario and details here -- This is what I wrote.: > https://trac.nginx.org/nginx/ticket/2614 > After I changed the memory pool totally on nginx and tested our workload -- long-lived gRPC streams with many connections -- using Valgrind and massif, I was able to find what brought up the memory leak issue. > like the picture below. > > [cid:image001.png at 01DA9C29.C792CD90] > ( I am not sure whether this picture will be sent properly ) > > After I patched one part, it seems okay now I have tested it for 1 week with out workload. > > [cid:image002.png at 01DA9C29.C792CD90] > ( I am not sure whether this picture will be sent properly ) > > But because I am not familiar with Mercurial, I couldn't find a way to create PR like on github. I guess this mailing list is for this patch. > From my point of view, it is more like a workaround and I think the way of using ngx_chain_add_copy() or itself needs to be changed because it allocates a ngx_chain_t structure using ngx_alloc_chain_link() but inside of that, it just copies pointer, like cl->buf = in->buf; > so this ngx_chain_t instance should be dealt with differently unlike other ngx_chain_t instances. > But I am quite new to nginx codes so my view might be wrong. > Anyhow, please go over this patch and I would like to further talk here. > > -------------------------------------------------------------------------------------------------------------------------------------------- > > diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c > index dfe49c586..1db67bd0a 100644 > --- a/src/http/modules/ngx_http_grpc_module.c > +++ b/src/http/modules/ngx_http_grpc_module.c > @@ -1462,6 +1462,12 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) > in = in->next; > } > > + ngx_chain_t *nl; > + for (ngx_chain_t *dl = ctx->in; dl != in; dl = nl ) { > + nl = dl->next; > + ngx_free_chain(r->pool, dl); > + } > + > ctx->in = in; > > if (last) { > > -------------------------------------------------------------------------------------------------------------------------------------------- > > Best regards, > Sangmin > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://mailman.nginx.org/mailman/listinfo/nginx-devel -- Roman Arutyunyan -------------- next part -------------- # HG changeset patch # User Roman Arutyunyan # Date 1716386385 -14400 # Wed May 22 17:59:45 2024 +0400 # Node ID 95af5fe4921294b48e634defc03b6b0f0201d6f7 # Parent e60377bdee3d0f8dbd237b5ae8a5deab2af785ef Optimized chain link usage (ticket #2614). Previously chain links could sometimes be dropped instead of being reused, which could result in increased memory consumption during long requests. A similar chain link issue in ngx_http_gzip_filter_module was fixed in da46bfc484ef (1.11.10). Based on a patch by Sangmin Lee. diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -117,7 +117,10 @@ ngx_output_chain(ngx_output_chain_ctx_t ngx_debug_point(); - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in = cl->next; + + ngx_free_chain(ctx->pool, cl); continue; } @@ -203,7 +206,10 @@ ngx_output_chain(ngx_output_chain_ctx_t /* delete the completed buf from the ctx->in chain */ if (ngx_buf_size(ctx->in->buf) == 0) { - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in = cl->next; + + ngx_free_chain(ctx->pool, cl); } cl = ngx_alloc_chain_link(ctx->pool); diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -1459,7 +1459,10 @@ ngx_http_grpc_body_output_filter(void *d last = 1; } + cl = in; in = in->next; + + ngx_free_chain(r->pool, cl); } ctx->in = in; diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c --- a/src/http/modules/ngx_http_gunzip_filter_module.c +++ b/src/http/modules/ngx_http_gunzip_filter_module.c @@ -333,6 +333,8 @@ static ngx_int_t ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, ngx_http_gunzip_ctx_t *ctx) { + ngx_chain_t *cl; + if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { return NGX_OK; } @@ -344,8 +346,11 @@ ngx_http_gunzip_filter_add_data(ngx_http return NGX_DECLINED; } - ctx->in_buf = ctx->in->buf; - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in_buf = cl->buf; + ctx->in = cl->next; + + ngx_free_chain(r->pool, cl); ctx->zstream.next_in = ctx->in_buf->pos; ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; @@ -383,8 +388,12 @@ ngx_http_gunzip_filter_get_buf(ngx_http_ conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); if (ctx->free) { - ctx->out_buf = ctx->free->buf; - ctx->free = ctx->free->next; + + cl = ctx->free; + ctx->out_buf = cl->buf; + ctx->free = cl->next; + + ngx_free_chain(r->pool, cl); ctx->out_buf->flush = 0; diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -985,10 +985,12 @@ static void ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { - ngx_chain_t *cl; + ngx_chain_t *cl, *next; - for (cl = ctx->copied; cl; cl = cl->next) { + for (cl = ctx->copied; cl; cl = next) { ngx_pfree(r->pool, cl->buf->start); + next = cl->next; + ngx_free_chain(r->pool, cl); } ctx->copied = NULL; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -482,9 +482,13 @@ ngx_http_ssi_body_filter(ngx_http_reques while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { - ctx->buf = ctx->in->buf; - ctx->in = ctx->in->next; + + cl = ctx->in; + ctx->buf = cl->buf; + ctx->in = cl->next; ctx->pos = ctx->buf->pos; + + ngx_free_chain(r->pool, cl); } if (ctx->state == ssi_start_state) { diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -335,9 +335,13 @@ ngx_http_sub_body_filter(ngx_http_reques while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { - ctx->buf = ctx->in->buf; - ctx->in = ctx->in->next; + + cl = ctx->in; + ctx->buf = cl->buf; + ctx->in = cl->next; ctx->pos = ctx->buf->pos; + + ngx_free_chain(r->pool, cl); } if (ctx->buf->flush || ctx->buf->recycled) { From xeioex at nginx.com Wed May 22 16:40:53 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Wed, 22 May 2024 16:40:53 +0000 Subject: [njs] Avoid creating byte strings explicitly. Message-ID: details: https://hg.nginx.org/njs/rev/27da19960b72 branches: changeset: 2332:27da19960b72 user: Dmitry Volyntsev date: Tue May 21 23:38:19 2024 -0700 description: Avoid creating byte strings explicitly. Previously, calls like njs_string_new(,,,0) produced byte strings by explicitly providing zero length argument. diffstat: src/njs_builtin.c | 4 ++-- src/njs_json.c | 8 +------- src/njs_vm.c | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diffs (58 lines): diff -r 286dbef3c0b2 -r 27da19960b72 src/njs_builtin.c --- a/src/njs_builtin.c Mon May 20 16:44:10 2024 -0700 +++ b/src/njs_builtin.c Tue May 21 23:38:19 2024 -0700 @@ -388,7 +388,7 @@ njs_builtin_traverse(njs_vm_t *vm, njs_t return NJS_ERROR; } - ret = njs_string_new(vm, &prop->name, buf, p - buf, 0); + ret = njs_string_create(vm, &prop->name, buf, p - buf); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -590,7 +590,7 @@ njs_ext_dump(njs_vm_t *vm, njs_value_t * return NJS_ERROR; } - return njs_string_new(vm, retval, str.start, str.length, 0); + return njs_string_create(vm, retval, str.start, str.length); } diff -r 286dbef3c0b2 -r 27da19960b72 src/njs_json.c --- a/src/njs_json.c Mon May 20 16:44:10 2024 -0700 +++ b/src/njs_json.c Tue May 21 23:38:19 2024 -0700 @@ -548,7 +548,6 @@ njs_json_parse_string(njs_json_parse_ctx { u_char ch, *s, *dst; size_t size, surplus; - ssize_t length; uint32_t utf, utf_low; njs_int_t ret; const u_char *start, *last; @@ -742,12 +741,7 @@ njs_json_parse_string(njs_json_parse_ctx start = dst; } - length = njs_utf8_length(start, size); - if (njs_slow_path(length < 0)) { - length = 0; - } - - ret = njs_string_new(ctx->vm, value, (u_char *) start, size, length); + ret = njs_string_create(ctx->vm, value, (u_char *) start, size); if (njs_slow_path(ret != NJS_OK)) { return NULL; } diff -r 286dbef3c0b2 -r 27da19960b72 src/njs_vm.c --- a/src/njs_vm.c Mon May 20 16:44:10 2024 -0700 +++ b/src/njs_vm.c Tue May 21 23:38:19 2024 -0700 @@ -874,7 +874,7 @@ njs_vm_bind2(njs_vm_t *vm, const njs_str njs_lvlhsh_t *hash; njs_lvlhsh_query_t lhq; - ret = njs_string_new(vm, &prop->name, var_name->start, var_name->length, 0); + ret = njs_string_create(vm, &prop->name, var_name->start, var_name->length); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } From xeioex at nginx.com Wed May 22 16:40:55 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Wed, 22 May 2024 16:40:55 +0000 Subject: [njs] Removed code for byte strings in built-in functions. Message-ID: details: https://hg.nginx.org/njs/rev/2d098d2a1c85 branches: changeset: 2333:2d098d2a1c85 user: Dmitry Volyntsev date: Tue May 21 23:41:10 2024 -0700 description: Removed code for byte strings in built-in functions. diffstat: src/njs_array.c | 52 ++++++++------------------------------ src/njs_iterator.c | 2 +- src/njs_json.c | 9 +----- src/njs_object.c | 4 +- src/njs_regexp.c | 16 +++-------- src/njs_string.c | 65 +++++++++++++++++------------------------------ src/njs_string.h | 20 ++----------- src/njs_vmcode.c | 9 ------ src/test/njs_unit_test.c | 30 +--------------------- 9 files changed, 49 insertions(+), 158 deletions(-) diffs (596 lines): diff -r 27da19960b72 -r 2d098d2a1c85 src/njs_array.c --- a/src/njs_array.c Tue May 21 23:38:19 2024 -0700 +++ b/src/njs_array.c Tue May 21 23:41:10 2024 -0700 @@ -826,29 +826,15 @@ njs_array_prototype_slice_copy(njs_vm_t src = string.start; end = src + string.size; - if (string.length == 0) { - /* Byte string. */ - do { - value = &array->start[n++]; - dst = njs_string_short_start(value); - *dst = *src++; - njs_string_short_set(value, 1, 0); - - length--; - } while (length != 0); - - } else { - /* UTF-8 or ASCII string. */ - do { - value = &array->start[n++]; - dst = njs_string_short_start(value); - dst = njs_utf8_copy(dst, &src, end); - size = dst - njs_string_short_start(value); - njs_string_short_set(value, size, 1); - - length--; - } while (length != 0); - } + do { + value = &array->start[n++]; + dst = njs_string_short_start(value); + dst = njs_utf8_copy(dst, &src, end); + size = dst - njs_string_short_start(value); + njs_string_short_set(value, size, 1); + + length--; + } while (length != 0); } else if (njs_is_object(this)) { @@ -1647,11 +1633,10 @@ static njs_int_t njs_array_prototype_join(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { - u_char *p, *last; + u_char *p; int64_t i, size, len, length; njs_int_t ret; njs_chb_t chain; - njs_utf8_t utf8; njs_value_t *value, *this, entry; njs_string_prop_t separator, string; @@ -1684,7 +1669,6 @@ njs_array_prototype_join(njs_vm_t *vm, n } length = 0; - utf8 = njs_is_byte_string(&separator) ? NJS_STRING_BYTE : NJS_STRING_UTF8; ret = njs_object_length(vm, this, &len); if (njs_slow_path(ret == NJS_ERROR)) { @@ -1708,29 +1692,15 @@ njs_array_prototype_join(njs_vm_t *vm, n if (!njs_is_null_or_undefined(value)) { if (!njs_is_string(value)) { - last = njs_chb_current(&chain); - ret = njs_value_to_chain(vm, &chain, value); if (njs_slow_path(ret < NJS_OK)) { return ret; } - if (last != njs_chb_current(&chain) && ret == 0) { - /* - * Appended values was a byte string. - */ - utf8 = NJS_STRING_BYTE; - } - length += ret; } else { (void) njs_string_prop(&string, value); - - if (njs_is_byte_string(&string)) { - utf8 = NJS_STRING_BYTE; - } - length += string.length; njs_chb_append(&chain, string.start, string.size); } @@ -1755,7 +1725,7 @@ njs_array_prototype_join(njs_vm_t *vm, n length -= separator.length; - p = njs_string_alloc(vm, retval, size, utf8 ? length : 0); + p = njs_string_alloc(vm, retval, size, length); if (njs_slow_path(p == NULL)) { return NJS_ERROR; } diff -r 27da19960b72 -r 2d098d2a1c85 src/njs_iterator.c --- a/src/njs_iterator.c Tue May 21 23:38:19 2024 -0700 +++ b/src/njs_iterator.c Tue May 21 23:41:10 2024 -0700 @@ -355,7 +355,7 @@ njs_object_iterate(njs_vm_t *vm, njs_ite end = p + string_prop.size; if ((size_t) length == string_prop.size) { - /* Byte or ASCII string. */ + /* ASCII string. */ for (i = from; i < to; i++) { /* This cannot fail. */ diff -r 27da19960b72 -r 2d098d2a1c85 src/njs_json.c --- a/src/njs_json.c Tue May 21 23:38:19 2024 -0700 +++ b/src/njs_json.c Tue May 21 23:41:10 2024 -0700 @@ -226,13 +226,6 @@ njs_json_stringify(njs_vm_t *vm, njs_val switch (space->type) { case NJS_STRING: length = njs_string_prop(&prop, space); - - if (njs_is_byte_string(&prop)) { - njs_internal_error(vm, "space argument cannot be" - " a byte string"); - return NJS_ERROR; - } - p = njs_string_offset(&prop, njs_min(length, 10)); stringify->space.start = prop.start; @@ -1552,7 +1545,7 @@ njs_json_append_string(njs_chb_t *chain, dst = njs_utf8_copy(dst, &p, end); } else { - /* Byte or ASCII string. */ + /* ASCII string. */ *dst++ = *p++; } diff -r 27da19960b72 -r 2d098d2a1c85 src/njs_object.c --- a/src/njs_object.c Tue May 21 23:38:19 2024 -0700 +++ b/src/njs_object.c Tue May 21 23:41:10 2024 -0700 @@ -741,7 +741,7 @@ njs_object_enumerate_string(njs_vm_t *vm case NJS_ENUM_VALUES: if (str_prop.size == (size_t) len) { - /* Byte or ASCII string. */ + /* ASCII string. */ for (i = 0; i < len; i++) { begin = njs_string_short_start(item); @@ -774,7 +774,7 @@ njs_object_enumerate_string(njs_vm_t *vm case NJS_ENUM_BOTH: if (str_prop.size == (size_t) len) { - /* Byte or ASCII string. */ + /* ASCII string. */ for (i = 0; i < len; i++) { diff -r 27da19960b72 -r 2d098d2a1c85 src/njs_regexp.c --- a/src/njs_regexp.c Tue May 21 23:38:19 2024 -0700 +++ b/src/njs_regexp.c Tue May 21 23:41:10 2024 -0700 @@ -748,12 +748,6 @@ njs_regexp_prototype_to_string(njs_vm_t size = source_string.size + flags_string.size + njs_length("//"); length = source_string.length + flags_string.length + njs_length("//"); - if (njs_is_byte_string(&source_string) - || njs_is_byte_string(&flags_string)) - { - length = 0; - } - p = njs_string_alloc(vm, retval, size, length); if (njs_slow_path(p == NULL)) { return NJS_ERROR; @@ -908,13 +902,13 @@ njs_regexp_builtin_exec(njs_vm_t *vm, nj goto not_found; } - utf8 = NJS_STRING_BYTE; + utf8 = NJS_STRING_ASCII; type = NJS_REGEXP_BYTE; if (string.length != 0) { type = NJS_REGEXP_UTF8; - if (string.length != string.size) { + if (!njs_is_ascii_string(&string)) { utf8 = NJS_STRING_UTF8; } } @@ -1693,7 +1687,7 @@ njs_regexp_prototype_symbol_split(njs_vm arguments[0] = *rx; if (!sticky) { - length = njs_is_byte_string(&s) ? 0 : s.length + 1; + length = s.length + 1; dst = njs_string_alloc(vm, &arguments[1], s.size + 1, length); if (njs_slow_path(dst == NULL)) { @@ -1749,9 +1743,9 @@ njs_regexp_prototype_symbol_split(njs_vm goto single; } - utf8 = NJS_STRING_BYTE; + utf8 = NJS_STRING_ASCII; - if (!njs_is_byte_or_ascii_string(&s)) { + if (!njs_is_ascii_string(&s)) { utf8 = NJS_STRING_UTF8; } diff -r 27da19960b72 -r 2d098d2a1c85 src/njs_string.c --- a/src/njs_string.c Tue May 21 23:38:19 2024 -0700 +++ b/src/njs_string.c Tue May 21 23:41:10 2024 -0700 @@ -186,6 +186,8 @@ njs_string_new(njs_vm_t *vm, njs_value_t { u_char *p; + njs_assert((size == 0 && length == 0) || (size != 0 && length != 0)); + p = njs_string_alloc(vm, value, size, length); if (njs_fast_path(p != NULL)) { @@ -880,10 +882,6 @@ njs_string_prototype_concat(njs_vm_t *vm size += string.size; length += string.length; - - if (njs_is_byte_string(&string)) { - mask = 0; - } } length &= mask; @@ -1238,15 +1236,10 @@ njs_string_slice_string_prop(njs_string_ start = string->start; if (string->size == slice->string_length) { - /* Byte or ASCII string. */ + /* ASCII string. */ start += slice->start; size = slice->length; - if (string->length == 0) { - /* Byte string. */ - length = 0; - } - } else { /* UTF-8 string. */ end = start + string->size; @@ -1327,7 +1320,7 @@ njs_string_prototype_char_code_at(njs_vm } if (length == string.size) { - /* Byte or ASCII string. */ + /* ASCII string. */ code = string.start[index]; } else { @@ -1715,20 +1708,20 @@ njs_string_index_of(njs_string_prop_t *s size_t index, length, search_length; const u_char *p, *end; - length = (string->length == 0) ? string->size : string->length; - - if (njs_slow_path(search->size == 0)) { + length = string->length; + + if (njs_slow_path(search->length == 0)) { return (from < length) ? from : length; } index = from; - search_length = (search->length == 0) ? search->size : search->length; + search_length = search->length; if (length - index >= search_length) { end = string->start + string->size; if (string->size == length) { - /* Byte or ASCII string. */ + /* ASCII string. */ end -= (search->size - 1); @@ -1863,7 +1856,7 @@ njs_string_prototype_last_index_of(njs_v end = string.start + string.size; if (string.size == (size_t) length) { - /* Byte or ASCII string. */ + /* ASCII string. */ p = &string.start[index]; @@ -2209,7 +2202,7 @@ njs_string_prototype_to_lower_case(njs_v (void) njs_string_prop(&string, njs_argument(args, 0)); - if (njs_is_byte_or_ascii_string(&string)) { + if (njs_is_ascii_string(&string)) { p = njs_string_alloc(vm, retval, string.size, string.length); if (njs_slow_path(p == NULL)) { @@ -2280,7 +2273,7 @@ njs_string_prototype_to_upper_case(njs_v (void) njs_string_prop(&string, njs_argument(args, 0)); - if (njs_is_byte_or_ascii_string(&string)) { + if (njs_is_ascii_string(&string)) { p = njs_string_alloc(vm, retval, string.size, string.length); if (njs_slow_path(p == NULL)) { @@ -2343,7 +2336,7 @@ njs_string_trim(const njs_value_t *value start = string->start; end = string->start + string->size; - if (njs_is_byte_or_ascii_string(string)) { + if (njs_is_ascii_string(string)) { if (mode & NJS_TRIM_START) { for ( ;; ) { @@ -2831,14 +2824,13 @@ njs_string_match_multiple(njs_vm_t *vm, (void) njs_string_prop(&string, &args[0]); - utf8 = NJS_STRING_BYTE; + utf8 = NJS_STRING_ASCII; type = NJS_REGEXP_BYTE; if (string.length != 0) { - utf8 = NJS_STRING_ASCII; type = NJS_REGEXP_UTF8; - if (string.length != string.size) { + if (!njs_is_ascii_string(&string)) { utf8 = NJS_STRING_UTF8; } } @@ -2877,7 +2869,7 @@ njs_string_match_multiple(njs_vm_t *vm, if (c1 == 0) { if (start < end) { - p = (utf8 != NJS_STRING_BYTE) ? njs_utf8_next(start, end) + p = (utf8 == NJS_STRING_UTF8) ? njs_utf8_next(start, end) : start + 1; string.size = end - p; @@ -3006,12 +2998,10 @@ njs_string_prototype_split(njs_vm_t *vm, goto done; } - utf8 = NJS_STRING_BYTE; + utf8 = NJS_STRING_ASCII; if (string.length != 0) { - utf8 = NJS_STRING_ASCII; - - if (string.length != string.size) { + if (!njs_is_ascii_string(&string)) { utf8 = NJS_STRING_UTF8; } } @@ -3037,7 +3027,7 @@ found: /* Empty split string. */ if (p == next) { - p = (utf8 != NJS_STRING_BYTE) ? njs_utf8_next(p, end) + p = (utf8 == NJS_STRING_UTF8) ? njs_utf8_next(p, end) : p + 1; next = p; } @@ -3241,7 +3231,7 @@ njs_string_prototype_replace(njs_vm_t *v njs_int_t ret; njs_str_t str; njs_chb_t chain; - njs_bool_t is_byte_or_ascii_string; + njs_bool_t is_ascii_string; njs_value_t *this, *search, *replace; njs_value_t search_lvalue, replace_lvalue, replacer, value, arguments[3]; @@ -3372,13 +3362,6 @@ njs_string_prototype_replace(njs_vm_t *v size = string.size + ret_string.size - s.size; length = string.length + ret_string.length - s.length; - if (njs_is_byte_string(&string) - || njs_is_byte_string(&s) - || njs_is_byte_string(&ret_string)) - { - length = 0; - } - r = njs_string_alloc(vm, retval, size, length); if (njs_slow_path(r == NULL)) { return NJS_ERROR; @@ -3395,7 +3378,7 @@ njs_string_prototype_replace(njs_vm_t *v p_start = string.start; increment = s.length != 0 ? s.length : 1; - is_byte_or_ascii_string = njs_is_byte_or_ascii_string(&string); + is_ascii_string = njs_is_ascii_string(&string); do { if (func_replace == NULL) { @@ -3422,7 +3405,7 @@ njs_string_prototype_replace(njs_vm_t *v } } - if (is_byte_or_ascii_string) { + if (is_ascii_string) { p = string.start + pos; } else { @@ -3815,7 +3798,7 @@ njs_string_encode_uri(njs_vm_t *vm, njs_ src = string.start; end = src + string.size; - if (njs_is_byte_or_ascii_string(&string)) { + if (njs_is_ascii_string(&string)) { while (src < end) { byte = *src++; @@ -3871,7 +3854,7 @@ njs_string_encode_uri(njs_vm_t *vm, njs_ src = string.start; - if (njs_is_byte_or_ascii_string(&string)) { + if (njs_is_ascii_string(&string)) { (void) njs_string_encode(escape, string.size, src, dst); return NJS_OK; } diff -r 27da19960b72 -r 2d098d2a1c85 src/njs_string.h --- a/src/njs_string.h Tue May 21 23:38:19 2024 -0700 +++ b/src/njs_string.h Tue May 21 23:41:10 2024 -0700 @@ -91,8 +91,7 @@ typedef struct { typedef enum { - NJS_STRING_BYTE = 0, - NJS_STRING_ASCII, + NJS_STRING_ASCII = 0, NJS_STRING_UTF8, } njs_utf8_t; @@ -179,16 +178,9 @@ njs_int_t njs_string_get_substitution(nj njs_inline njs_bool_t -njs_is_byte_string(njs_string_prop_t *string) +njs_is_ascii_string(njs_string_prop_t *string) { - return (string->length == 0 && string->size != 0); -} - - -njs_inline njs_bool_t -njs_is_byte_or_ascii_string(njs_string_prop_t *string) -{ - return (string->length == 0 || string->length == string->size); + return string->length == string->size; } @@ -198,10 +190,6 @@ njs_string_calc_length(njs_utf8_t utf8, ssize_t length; switch (utf8) { - - case NJS_STRING_BYTE: - return 0; - case NJS_STRING_ASCII: return size; @@ -251,7 +239,7 @@ njs_string_encode(const uint32_t *escape njs_inline const u_char * njs_string_offset(njs_string_prop_t *string, int64_t index) { - if (njs_is_byte_or_ascii_string(string)) { + if (njs_is_ascii_string(string)) { return string->start + index; } diff -r 27da19960b72 -r 2d098d2a1c85 src/njs_vmcode.c --- a/src/njs_vmcode.c Tue May 21 23:38:19 2024 -0700 +++ b/src/njs_vmcode.c Tue May 21 23:41:10 2024 -0700 @@ -2318,15 +2318,6 @@ njs_string_concat(njs_vm_t *vm, njs_valu (void) njs_string_prop(&string2, val2); length = string1.length + string2.length; - - /* - * A result of concatenation of Byte and ASCII or UTF-8 strings - * is a Byte string. - */ - if (njs_is_byte_string(&string1) || njs_is_byte_string(&string2)) { - length = 0; - } - size = string1.size + string2.size; start = njs_string_alloc(vm, retval, size, length); diff -r 27da19960b72 -r 2d098d2a1c85 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue May 21 23:38:19 2024 -0700 +++ b/src/test/njs_unit_test.c Tue May 21 23:41:10 2024 -0700 @@ -4372,10 +4372,9 @@ static njs_unit_test_t njs_test[] = { njs_str("[" " 'α'.repeat(33)," - " $262.byteString(Array(16).fill(0x9d))," "]" ".map(v=>{var out = ['β', 'γ'].join(v); return out.length})"), - njs_str("35,20") }, + njs_str("35") }, { njs_str("[" " []," @@ -4393,9 +4392,6 @@ static njs_unit_test_t njs_test[] = { njs_str("var a = ['β','γ']; a.join('').length"), njs_str("2") }, - { njs_str("var a = ['β', $262.byteString([0x9d]),'γ']; a.join('').length"), - njs_str("5") }, - { njs_str("var a = []; a[5] = 5; a.join()"), njs_str(",,,,,5") }, @@ -4764,9 +4760,6 @@ static njs_unit_test_t njs_test[] = { njs_str("Array.prototype.slice.call('αβZγ')"), njs_str("α,β,Z,γ") }, - { njs_str("Array.prototype.slice.call($262.byteString(Array(16).fill(0x9d)))[0].charCodeAt(0)"), - njs_str("157") }, - { njs_str("Array.prototype.slice.call('αβZγ', 1)"), njs_str("β,Z,γ") }, @@ -9941,10 +9934,6 @@ static njs_unit_test_t njs_test[] = { njs_str("'abc'.padEnd(10, Symbol())"), njs_str("TypeError: Cannot convert a Symbol value to a string") }, - { njs_str("[undefined, null, Symbol()]" - ".every(v=> { try {$262.byteString(v);} catch(e) {return e.name == 'TypeError'} })"), - njs_str("true") }, - { njs_str("encodeURI.name"), njs_str("encodeURI")}, @@ -11796,10 +11785,6 @@ static njs_unit_test_t njs_test[] = njs_str("3 БВ бв 2 /бв/gi") }, #endif - { njs_str("var r = /_/g; var index = r.exec($262.byteString([255,149,15,97,95])).index;" - "[index, r.lastIndex]"), - njs_str("4,5") }, - { njs_str("var descs = Object.getOwnPropertyDescriptors(RegExp('a'));" "Object.keys(descs)"), njs_str("lastIndex") }, @@ -12103,13 +12088,6 @@ static njs_unit_test_t njs_test[] = { njs_str("Error('e').name + ': ' + Error('e').message"), njs_str("Error: e") }, - { njs_str("Error($262.byteString(Array(1).fill(0x9d))).toString().length"), - njs_str("8") }, - - { njs_str("var e = Error('α'); e.name = $262.byteString(Array(1).fill(0x9d)); " - "e.toString().length"), - njs_str("5") }, - { njs_str("Error(1)"), njs_str("Error: 1") }, @@ -18565,9 +18543,6 @@ static njs_unit_test_t njs_test[] = { njs_str("JSON.stringify('абв'.repeat(100)).length"), njs_str("302") }, - { njs_str("JSON.stringify($262.byteString([0xCE, 0xB1, 0xC2, 0xB6]))"), - njs_str("\"α¶\"") }, - /* Optional arguments. */ { njs_str("JSON.stringify(undefined, undefined, 1)"), @@ -18601,9 +18576,6 @@ static njs_unit_test_t njs_test[] = { njs_str("JSON.stringify([1], null, '!!βββββββββββββββββ').length"), njs_str("15") }, - { njs_str("JSON.stringify([1], null, $262.byteString([0x9d])).length"), - njs_str("InternalError: space argument cannot be a byte string") }, - { njs_str("JSON.stringify([1], null, 11)"), njs_str("[\n 1\n]") }, From xeioex at nginx.com Wed May 22 16:40:57 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Wed, 22 May 2024 16:40:57 +0000 Subject: [njs] Aligned StringIndexOf() implementation with the spec. Message-ID: details: https://hg.nginx.org/njs/rev/bc09b884022d branches: changeset: 2334:bc09b884022d user: Dmitry Volyntsev date: Tue May 21 23:41:10 2024 -0700 description: Aligned StringIndexOf() implementation with the spec. When searchValue is empty the function should return early when fromIndex <= len is also true. diffstat: src/njs_string.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff -r 2d098d2a1c85 -r bc09b884022d src/njs_string.c --- a/src/njs_string.c Tue May 21 23:41:10 2024 -0700 +++ b/src/njs_string.c Tue May 21 23:41:10 2024 -0700 @@ -1710,8 +1710,8 @@ njs_string_index_of(njs_string_prop_t *s length = string->length; - if (njs_slow_path(search->length == 0)) { - return (from < length) ? from : length; + if (search->length == 0 && from <= length) { + return from; } index = from; From xeioex at nginx.com Thu May 23 00:27:02 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Thu, 23 May 2024 00:27:02 +0000 Subject: [njs] Fixed String.prototype.replaceAll() with zero length argument. Message-ID: details: https://hg.nginx.org/njs/rev/e496851c0fe7 branches: changeset: 2335:e496851c0fe7 user: Dmitry Volyntsev date: Wed May 22 17:26:08 2024 -0700 description: Fixed String.prototype.replaceAll() with zero length argument. This fixes #712 issue on Github. diffstat: src/njs_string.c | 15 ++++----------- src/njs_string.h | 4 ++++ src/test/njs_unit_test.c | 6 ++++++ 3 files changed, 14 insertions(+), 11 deletions(-) diffs (76 lines): diff -r bc09b884022d -r e496851c0fe7 src/njs_string.c --- a/src/njs_string.c Tue May 21 23:41:10 2024 -0700 +++ b/src/njs_string.c Wed May 22 17:26:08 2024 -0700 @@ -1736,7 +1736,9 @@ njs_string_index_of(njs_string_prop_t *s } else { /* UTF-8 string. */ - p = njs_string_utf8_offset(string->start, end, index); + p = (index < string->length) + ? njs_string_utf8_offset(string->start, end, index) + : end; end -= search->size - 1; while (p < end) { @@ -3231,7 +3233,6 @@ njs_string_prototype_replace(njs_vm_t *v njs_int_t ret; njs_str_t str; njs_chb_t chain; - njs_bool_t is_ascii_string; njs_value_t *this, *search, *replace; njs_value_t search_lvalue, replace_lvalue, replacer, value, arguments[3]; @@ -3378,7 +3379,6 @@ njs_string_prototype_replace(njs_vm_t *v p_start = string.start; increment = s.length != 0 ? s.length : 1; - is_ascii_string = njs_is_ascii_string(&string); do { if (func_replace == NULL) { @@ -3405,14 +3405,7 @@ njs_string_prototype_replace(njs_vm_t *v } } - if (is_ascii_string) { - p = string.start + pos; - - } else { - p = njs_string_utf8_offset(string.start, string.start + string.size, - pos); - } - + p = njs_string_offset(&string, pos); (void) njs_string_prop(&ret_string, &value); njs_chb_append(&chain, p_start, p - p_start); diff -r bc09b884022d -r e496851c0fe7 src/njs_string.h --- a/src/njs_string.h Tue May 21 23:41:10 2024 -0700 +++ b/src/njs_string.h Wed May 22 17:26:08 2024 -0700 @@ -245,6 +245,10 @@ njs_string_offset(njs_string_prop_t *str /* UTF-8 string. */ + if (index == (int64_t) string->length) { + return string->start + string->size; + } + return njs_string_utf8_offset(string->start, string->start + string->size, index); } diff -r bc09b884022d -r e496851c0fe7 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue May 21 23:41:10 2024 -0700 +++ b/src/test/njs_unit_test.c Wed May 22 17:26:08 2024 -0700 @@ -8888,6 +8888,12 @@ static njs_unit_test_t njs_test[] = { njs_str("var r = 'αβγ'.replaceAll('', 'X'); [r, r.length]"), njs_str("XαXβXγX,7") }, + { njs_str("var r = ''.replaceAll('', 'z'); [r, r.length]"), + njs_str("z,1") }, + + { njs_str("var r = 'α'.padStart(32).replaceAll('', 'z'); [r, r.length]"), + njs_str("z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z zαz,65") }, + { njs_str("'abc'.replace('b', (m, o, s) => `|${s}|${o}|${m}|`)"), njs_str("a|abc|1|b|c") }, From xeioex at nginx.com Thu May 23 00:27:04 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Thu, 23 May 2024 00:27:04 +0000 Subject: [njs] Improved String.prototype.replaceAll() for readability. Message-ID: details: https://hg.nginx.org/njs/rev/077a5b2f30d8 branches: changeset: 2336:077a5b2f30d8 user: Dmitry Volyntsev date: Wed May 22 17:26:16 2024 -0700 description: Improved String.prototype.replaceAll() for readability. diffstat: src/njs_string.c | 44 ++++++++++++++++++++++++++------------------ 1 files changed, 26 insertions(+), 18 deletions(-) diffs (100 lines): diff -r e496851c0fe7 -r 077a5b2f30d8 src/njs_string.c --- a/src/njs_string.c Wed May 22 17:26:08 2024 -0700 +++ b/src/njs_string.c Wed May 22 17:26:16 2024 -0700 @@ -3228,7 +3228,7 @@ njs_string_prototype_replace(njs_vm_t *v njs_index_t replaceAll, njs_value_t *retval) { u_char *r; - size_t length, size, increment, end_of_last_match; + size_t length, size, end_of_last_match; int64_t pos; njs_int_t ret; njs_str_t str; @@ -3236,7 +3236,7 @@ njs_string_prototype_replace(njs_vm_t *v njs_value_t *this, *search, *replace; njs_value_t search_lvalue, replace_lvalue, replacer, value, arguments[3]; - const u_char *p, *p_start; + const u_char *start, *end; njs_function_t *func_replace; njs_string_prop_t string, s, ret_string; @@ -3331,7 +3331,6 @@ njs_string_prototype_replace(njs_vm_t *v } if (!replaceAll) { - if (func_replace == NULL) { ret = njs_string_get_substitution(vm, search, this, pos, NULL, 0, NULL, replace, &value); @@ -3356,7 +3355,7 @@ njs_string_prototype_replace(njs_vm_t *v } } - p = njs_string_offset(&string, pos); + end = njs_string_offset(&string, pos); (void) njs_string_prop(&ret_string, &value); @@ -3368,17 +3367,16 @@ njs_string_prototype_replace(njs_vm_t *v return NJS_ERROR; } - r = njs_cpymem(r, string.start, p - string.start); + r = njs_cpymem(r, string.start, end - string.start); r = njs_cpymem(r, ret_string.start, ret_string.size); - memcpy(r, p + s.size, string.size - s.size - (p - string.start)); + memcpy(r, end + s.size, string.size - s.size - (end - string.start)); return NJS_OK; } NJS_CHB_MP_INIT(&chain, vm); - p_start = string.start; - increment = s.length != 0 ? s.length : 1; + start = string.start; do { if (func_replace == NULL) { @@ -3405,20 +3403,30 @@ njs_string_prototype_replace(njs_vm_t *v } } - p = njs_string_offset(&string, pos); + end = njs_string_offset(&string, pos); (void) njs_string_prop(&ret_string, &value); - njs_chb_append(&chain, p_start, p - p_start); + njs_chb_append(&chain, start, end - start); njs_chb_append(&chain, ret_string.start, ret_string.size); - p_start = p + s.size; - end_of_last_match = pos + increment; - - pos = njs_string_index_of(&string, &s, end_of_last_match); - - } while (pos >= 0 && end_of_last_match <= string.length); - - njs_chb_append(&chain, p_start, string.start + string.size - p_start); + start = end + s.size; + end_of_last_match = pos + s.length; + + if (njs_slow_path(s.length == 0)) { + if (end_of_last_match >= string.length) { + pos = -1; + + } else { + pos = end_of_last_match + 1; + } + + } else { + pos = njs_string_index_of(&string, &s, end_of_last_match); + } + + } while (pos >= 0); + + njs_chb_append(&chain, start, string.start + string.size - start); ret = njs_string_create_chb(vm, retval, &chain); if (njs_slow_path(ret != NJS_OK)) { From arut at nginx.com Thu May 23 09:42:24 2024 From: arut at nginx.com (Roman Arutyunyan) Date: Thu, 23 May 2024 13:42:24 +0400 Subject: I think I found a fix for the memory leak issue on gRPC module In-Reply-To: <20240522141426.ahzeenwq2qom3m4f@N00W24XTQX> References: <20240522141426.ahzeenwq2qom3m4f@N00W24XTQX> Message-ID: <20240523094224.6n4ihcqrgsl54nxk@N00W24XTQX> Hi, On Wed, May 22, 2024 at 06:14:26PM +0400, Roman Arutyunyan wrote: > Hi, > > Indeed there's a problem there. We have similar problems in other places as > well. Attached is a patch that fixes all I could find. > > I did some testing for the sub_filter with the following config. Small buffers > exaggerate the problem. > > http { > server { > listen 8000; > > location / { > root html; > > output_buffers 2 128; > > sub_filter 1 2; > sub_filter_types *; > sub_filter_once off; > } > } > } > > Retrieving a 10m file resulted in 7304 (patched) vs 1317704 (unpatched) bytes > allocated from the request pool. With the default output_buffers (2 32768), > it's 79880 vs 84040. I tested ssi with the following config. server { listen 8000; location / { root html; output_buffers 2 128; ssi on; ssi_types *; } } The result is similar: 6224 vs 1316912 with small buffers 38864 vs 43952 with the default buffers > On Thu, May 02, 2024 at 07:59:44AM +0000, Pavel Pautov via nginx-devel wrote: > > Hi Sangmin, > > > > Your analysis looks correct. Client streaming RPCs can lead to unbound accumulation of ngx_chain_t objects (although, at very slow rate). Gzip module had a similar issue (https://trac.nginx.org/nginx/ticket/1046). > > Attaching somewhat simplified patch based on yours. I was able to reproduce the issue locally and the patch fixes it. > > > > From: nginx-devel On Behalf Of Sangmin Lee > > Sent: Thursday, April 4, 2024 19:29 > > To: nginx-devel at nginx.org > > Subject: I think I found a fix for the memory leak issue on gRPC module > > > > CAUTION: This email has been sent from an external source. Do not click links, open attachments, or provide sensitive business information unless you can verify the sender's legitimacy. > > > > I am sending this mail again because I did a mistake while I was writing a mail. I didn't know, in gmail, "Ctrl - Enter" would send a mail immediately even without a title! > > I am sorry for that, so I am sending again. > > > > Hello, > > > > I think I found the main cause of the memory leak issue when using gRPC stream so I made a patch for it. > > Please find the test scenario and details here -- This is what I wrote.: > > https://trac.nginx.org/nginx/ticket/2614 > > After I changed the memory pool totally on nginx and tested our workload -- long-lived gRPC streams with many connections -- using Valgrind and massif, I was able to find what brought up the memory leak issue. > > like the picture below. > > > > [cid:image001.png at 01DA9C29.C792CD90] > > ( I am not sure whether this picture will be sent properly ) > > > > After I patched one part, it seems okay now I have tested it for 1 week with out workload. > > > > [cid:image002.png at 01DA9C29.C792CD90] > > ( I am not sure whether this picture will be sent properly ) > > > > But because I am not familiar with Mercurial, I couldn't find a way to create PR like on github. I guess this mailing list is for this patch. > > From my point of view, it is more like a workaround and I think the way of using ngx_chain_add_copy() or itself needs to be changed because it allocates a ngx_chain_t structure using ngx_alloc_chain_link() but inside of that, it just copies pointer, like cl->buf = in->buf; > > so this ngx_chain_t instance should be dealt with differently unlike other ngx_chain_t instances. > > But I am quite new to nginx codes so my view might be wrong. > > Anyhow, please go over this patch and I would like to further talk here. > > > > -------------------------------------------------------------------------------------------------------------------------------------------- > > > > diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c > > index dfe49c586..1db67bd0a 100644 > > --- a/src/http/modules/ngx_http_grpc_module.c > > +++ b/src/http/modules/ngx_http_grpc_module.c > > @@ -1462,6 +1462,12 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) > > in = in->next; > > } > > > > + ngx_chain_t *nl; > > + for (ngx_chain_t *dl = ctx->in; dl != in; dl = nl ) { > > + nl = dl->next; > > + ngx_free_chain(r->pool, dl); > > + } > > + > > ctx->in = in; > > > > if (last) { > > > > -------------------------------------------------------------------------------------------------------------------------------------------- > > > > Best regards, > > Sangmin > > > > > > > _______________________________________________ > > nginx-devel mailing list > > nginx-devel at nginx.org > > https://mailman.nginx.org/mailman/listinfo/nginx-devel > > > -- > Roman Arutyunyan > # HG changeset patch > # User Roman Arutyunyan > # Date 1716386385 -14400 > # Wed May 22 17:59:45 2024 +0400 > # Node ID 95af5fe4921294b48e634defc03b6b0f0201d6f7 > # Parent e60377bdee3d0f8dbd237b5ae8a5deab2af785ef > Optimized chain link usage (ticket #2614). > > Previously chain links could sometimes be dropped instead of being reused, > which could result in increased memory consumption during long requests. > > A similar chain link issue in ngx_http_gzip_filter_module was fixed in > da46bfc484ef (1.11.10). > > Based on a patch by Sangmin Lee. > > diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c > --- a/src/core/ngx_output_chain.c > +++ b/src/core/ngx_output_chain.c > @@ -117,7 +117,10 @@ ngx_output_chain(ngx_output_chain_ctx_t > > ngx_debug_point(); > > - ctx->in = ctx->in->next; > + cl = ctx->in; > + ctx->in = cl->next; > + > + ngx_free_chain(ctx->pool, cl); > > continue; > } > @@ -203,7 +206,10 @@ ngx_output_chain(ngx_output_chain_ctx_t > /* delete the completed buf from the ctx->in chain */ > > if (ngx_buf_size(ctx->in->buf) == 0) { > - ctx->in = ctx->in->next; > + cl = ctx->in; > + ctx->in = cl->next; > + > + ngx_free_chain(ctx->pool, cl); > } > > cl = ngx_alloc_chain_link(ctx->pool); > diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c > --- a/src/http/modules/ngx_http_grpc_module.c > +++ b/src/http/modules/ngx_http_grpc_module.c > @@ -1459,7 +1459,10 @@ ngx_http_grpc_body_output_filter(void *d > last = 1; > } > > + cl = in; > in = in->next; > + > + ngx_free_chain(r->pool, cl); > } > > ctx->in = in; > diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c > --- a/src/http/modules/ngx_http_gunzip_filter_module.c > +++ b/src/http/modules/ngx_http_gunzip_filter_module.c > @@ -333,6 +333,8 @@ static ngx_int_t > ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, > ngx_http_gunzip_ctx_t *ctx) > { > + ngx_chain_t *cl; > + > if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { > return NGX_OK; > } > @@ -344,8 +346,11 @@ ngx_http_gunzip_filter_add_data(ngx_http > return NGX_DECLINED; > } > > - ctx->in_buf = ctx->in->buf; > - ctx->in = ctx->in->next; > + cl = ctx->in; > + ctx->in_buf = cl->buf; > + ctx->in = cl->next; > + > + ngx_free_chain(r->pool, cl); > > ctx->zstream.next_in = ctx->in_buf->pos; > ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; > @@ -383,8 +388,12 @@ ngx_http_gunzip_filter_get_buf(ngx_http_ > conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); > > if (ctx->free) { > - ctx->out_buf = ctx->free->buf; > - ctx->free = ctx->free->next; > + > + cl = ctx->free; > + ctx->out_buf = cl->buf; > + ctx->free = cl->next; > + > + ngx_free_chain(r->pool, cl); > > ctx->out_buf->flush = 0; > > diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c > --- a/src/http/modules/ngx_http_gzip_filter_module.c > +++ b/src/http/modules/ngx_http_gzip_filter_module.c > @@ -985,10 +985,12 @@ static void > ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, > ngx_http_gzip_ctx_t *ctx) > { > - ngx_chain_t *cl; > + ngx_chain_t *cl, *next; > > - for (cl = ctx->copied; cl; cl = cl->next) { > + for (cl = ctx->copied; cl; cl = next) { > ngx_pfree(r->pool, cl->buf->start); > + next = cl->next; > + ngx_free_chain(r->pool, cl); > } > > ctx->copied = NULL; > diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c > --- a/src/http/modules/ngx_http_ssi_filter_module.c > +++ b/src/http/modules/ngx_http_ssi_filter_module.c > @@ -482,9 +482,13 @@ ngx_http_ssi_body_filter(ngx_http_reques > while (ctx->in || ctx->buf) { > > if (ctx->buf == NULL) { > - ctx->buf = ctx->in->buf; > - ctx->in = ctx->in->next; > + > + cl = ctx->in; > + ctx->buf = cl->buf; > + ctx->in = cl->next; > ctx->pos = ctx->buf->pos; > + > + ngx_free_chain(r->pool, cl); > } > > if (ctx->state == ssi_start_state) { > diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c > --- a/src/http/modules/ngx_http_sub_filter_module.c > +++ b/src/http/modules/ngx_http_sub_filter_module.c > @@ -335,9 +335,13 @@ ngx_http_sub_body_filter(ngx_http_reques > while (ctx->in || ctx->buf) { > > if (ctx->buf == NULL) { > - ctx->buf = ctx->in->buf; > - ctx->in = ctx->in->next; > + > + cl = ctx->in; > + ctx->buf = cl->buf; > + ctx->in = cl->next; > ctx->pos = ctx->buf->pos; > + > + ngx_free_chain(r->pool, cl); > } > > if (ctx->buf->flush || ctx->buf->recycled) { > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://mailman.nginx.org/mailman/listinfo/nginx-devel -- Roman Arutyunyan From xeioex at nginx.com Thu May 23 16:59:59 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Thu, 23 May 2024 16:59:59 +0000 Subject: [njs] Fixed retval handling after an exception. Message-ID: details: https://hg.nginx.org/njs/rev/585756e8cafe branches: changeset: 2337:585756e8cafe user: Dmitry Volyntsev date: Wed May 22 23:08:15 2024 -0700 description: Fixed retval handling after an exception. Previously, some functions set a retval too early. If this happened before an exception a partially created object in inconsistent state may be visible outside the affected functions. The following functions were fixed: Object.prototype.valueOf() Array.prototype.toSpliced() Array.prototype.toReversed() Array.prototype.toSorted() This fixes #713 issue on Github. diffstat: src/njs_array.c | 39 ++++++++++++++++++++++----------------- src/njs_object.c | 14 ++++++++++---- src/test/njs_unit_test.c | 12 ++++++++++++ 3 files changed, 44 insertions(+), 21 deletions(-) diffs (203 lines): diff -r 077a5b2f30d8 -r 585756e8cafe src/njs_array.c --- a/src/njs_array.c Wed May 22 17:26:16 2024 -0700 +++ b/src/njs_array.c Wed May 22 23:08:15 2024 -0700 @@ -591,14 +591,14 @@ njs_array_of(njs_vm_t *vm, njs_value_t * return NJS_ERROR; } - njs_set_array(retval, array); - if (array->object.fast_array) { for (i = 0; i < length; i++) { array->start[i] = args[i + 1]; } } + njs_set_array(retval, array); + return NJS_OK; } @@ -1388,7 +1388,7 @@ njs_array_prototype_to_spliced(njs_vm_t { int64_t i, n, r, start, length, to_insert, to_skip, new_length; njs_int_t ret; - njs_value_t *this, value; + njs_value_t *this, a, value; njs_array_t *array; this = njs_argument(args, 0); @@ -1439,7 +1439,7 @@ njs_array_prototype_to_spliced(njs_vm_t return NJS_ERROR; } - njs_set_array(retval, array); + njs_set_array(&a, array); for (i = 0; i < start; i++) { ret = njs_value_property_i64(vm, this, i, &value); @@ -1447,14 +1447,14 @@ njs_array_prototype_to_spliced(njs_vm_t return NJS_ERROR; } - ret = njs_value_create_data_prop_i64(vm, retval, i, &value, 0); + ret = njs_value_create_data_prop_i64(vm, &a, i, &value, 0); if (njs_slow_path(ret != NJS_OK)) { return ret; } } for (n = 3; to_insert-- > 0; i++, n++) { - ret = njs_value_create_data_prop_i64(vm, retval, i, &args[n], 0); + ret = njs_value_create_data_prop_i64(vm, &a, i, &args[n], 0); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -1468,7 +1468,7 @@ njs_array_prototype_to_spliced(njs_vm_t return NJS_ERROR; } - ret = njs_value_create_data_prop_i64(vm, retval, i, &value, 0); + ret = njs_value_create_data_prop_i64(vm, &a, i, &value, 0); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -1477,6 +1477,8 @@ njs_array_prototype_to_spliced(njs_vm_t i++; } + njs_set_array(retval, array); + return NJS_OK; } @@ -1562,7 +1564,7 @@ njs_array_prototype_to_reversed(njs_vm_t int64_t length, i; njs_int_t ret; njs_array_t *array; - njs_value_t *this, value; + njs_value_t *this, a, value; this = njs_argument(args, 0); @@ -1581,7 +1583,7 @@ njs_array_prototype_to_reversed(njs_vm_t return NJS_ERROR; } - njs_set_array(retval, array); + njs_set_array(&a, array); for (i = 0; i < length; i++) { ret = njs_value_property_i64(vm, this, length - i - 1, &value); @@ -1589,12 +1591,14 @@ njs_array_prototype_to_reversed(njs_vm_t return NJS_ERROR; } - ret = njs_value_create_data_prop_i64(vm, retval, i, &value, 0); + ret = njs_value_create_data_prop_i64(vm, &a, i, &value, 0); if (njs_slow_path(ret != NJS_OK)) { return ret; } } + njs_set_array(retval, array); + return NJS_OK; } @@ -3018,7 +3022,7 @@ njs_array_prototype_to_sorted(njs_vm_t * int64_t i, nslots, nunds, length; njs_int_t ret; njs_array_t *array; - njs_value_t *this, *comparefn; + njs_value_t *this, *comparefn, a; njs_function_t *compare; njs_array_sort_slot_t *slots; @@ -3070,24 +3074,25 @@ njs_array_prototype_to_sorted(njs_vm_t * njs_assert(length == (nslots + nunds)); - njs_set_array(retval, array); + njs_set_array(&a, array); for (i = 0; i < nslots; i++) { - ret = njs_value_property_i64_set(vm, retval, i, &slots[i].value); - if (njs_slow_path(ret == NJS_ERROR)) { + ret = njs_value_create_data_prop_i64(vm, &a, i, &slots[i].value, 0); + if (njs_slow_path(ret != NJS_OK)) { goto exception; } } for (; i < length; i++) { - ret = njs_value_property_i64_set(vm, retval, i, - njs_value_arg(&njs_value_undefined)); - if (njs_slow_path(ret == NJS_ERROR)) { + ret = njs_value_create_data_prop_i64(vm, &a, i, + njs_value_arg(&njs_value_undefined), 0); + if (njs_slow_path(ret != NJS_OK)) { goto exception; } } ret = NJS_OK; + njs_set_array(retval, array); exception: diff -r 077a5b2f30d8 -r 585756e8cafe src/njs_object.c --- a/src/njs_object.c Wed May 22 17:26:16 2024 -0700 +++ b/src/njs_object.c Wed May 22 23:08:15 2024 -0700 @@ -2285,12 +2285,18 @@ static njs_int_t njs_object_prototype_value_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { - njs_value_assign(retval, njs_argument(args, 0)); - - if (!njs_is_object(retval)) { - return njs_value_to_object(vm, retval); + njs_value_t *value; + + value = njs_argument(args, 0); + + if (!njs_is_object(value)) { + if (njs_value_to_object(vm, value) != NJS_OK) { + return NJS_ERROR; + } } + njs_value_assign(retval, value); + return NJS_OK; } diff -r 077a5b2f30d8 -r 585756e8cafe src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed May 22 17:26:16 2024 -0700 +++ b/src/test/njs_unit_test.c Wed May 22 23:08:15 2024 -0700 @@ -5181,6 +5181,12 @@ static njs_unit_test_t njs_test[] = { njs_str("'/A/B/C/D/'.split('/').toSpliced(1,1).join('/')"), njs_str("/B/C/D/") }, + { njs_str("let r, arr = new Array(4);" + "Object.defineProperty(arr, 0, { get: () => { throw 'Oops'; } });" + "try { r = arr.toSpliced(0, 0); } catch (e) { }" + "r.toString()"), + njs_str("TypeError: cannot get property \"toString\" of undefined") }, + { njs_str("var a = []; a.reverse()"), njs_str("") }, @@ -5237,6 +5243,12 @@ static njs_unit_test_t njs_test[] = { njs_str("Array.prototype[0] = 0; var x = [,1]; x.reverse(); x"), njs_str("1,0") }, + { njs_str("let r, arr = new Array(4);" + "Object.defineProperty(arr, 0, { get: () => { throw 'Oops'; } });" + "try { r = arr.toReversed(0, 0); } catch (e) { }" + "r.toString()"), + njs_str("TypeError: cannot get property \"toString\" of undefined") }, + { njs_str("var a = [,3,2,1]; njs.dump([a.toReversed(),a])"), njs_str("[[1,2,3,undefined],[,3,2,1]]") }, From xeioex at nginx.com Fri May 24 23:01:24 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Fri, 24 May 2024 23:01:24 +0000 Subject: [njs] Added fast path in njs_chb_utf8_length() for ASCII input. Message-ID: details: https://hg.nginx.org/njs/rev/437fc09db765 branches: changeset: 2338:437fc09db765 user: Dmitry Volyntsev date: Thu May 23 22:50:19 2024 -0700 description: Added fast path in njs_chb_utf8_length() for ASCII input. diffstat: src/njs_chb.h | 19 +++++++++++++++++++ src/test/njs_benchmark.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 0 deletions(-) diffs (93 lines): diff -r 585756e8cafe -r 437fc09db765 src/njs_chb.h --- a/src/njs_chb.h Wed May 22 23:08:15 2024 -0700 +++ b/src/njs_chb.h Thu May 23 22:50:19 2024 -0700 @@ -96,6 +96,8 @@ njs_chb_size(njs_chb_t *chain) njs_inline int64_t njs_chb_utf8_length(njs_chb_t *chain) { + u_char *p, *p_end; + size_t size; int64_t len, length; njs_chb_node_t *n; @@ -108,6 +110,23 @@ njs_chb_utf8_length(njs_chb_t *chain) length = 0; while (n != NULL) { + p = n->start; + size = njs_chb_node_size(n); + p_end = p + size; + + while (p < p_end && *p < 0x80) { + p++; + } + + if (p != p_end) { + break; + } + + length += size; + n = n->next; + } + + while (n != NULL) { len = njs_utf8_length(n->start, njs_chb_node_size(n)); if (njs_slow_path(len < 0)) { return -1; diff -r 585756e8cafe -r 437fc09db765 src/test/njs_benchmark.c --- a/src/test/njs_benchmark.c Wed May 22 23:08:15 2024 -0700 +++ b/src/test/njs_benchmark.c Thu May 23 22:50:19 2024 -0700 @@ -305,6 +305,21 @@ static njs_benchmark_test_t njs_test[] njs_str("undefined"), 1 }, + { "string create chb 'x'.repeat(256)", + njs_str("benchmark.string('chb', 'x'.repeat(256), 10000)"), + njs_str("undefined"), + 1 }, + + { "string create chb 'Д'.repeat(128)", + njs_str("benchmark.string('chb', 'Д'.repeat(128), 10000)"), + njs_str("undefined"), + 1 }, + + { "string create chb 'x'.repeat(128) + 'Д'.repeat(64)", + njs_str("benchmark.string('chb', 'x'.repeat(128) + 'Д'.repeat(64), 10000)"), + njs_str("undefined"), + 1 }, + { "JSON.parse", njs_str("JSON.parse('{\"a\":123, \"XXX\":[3,4,null]}').a"), njs_str("123"), @@ -696,6 +711,7 @@ njs_benchmark_string(njs_vm_t *vm, njs_v njs_index_t unused, njs_value_t *retval) { int64_t i, n; + njs_chb_t chain; njs_str_t s, mode; njs_value_t value; @@ -718,6 +734,23 @@ njs_benchmark_string(njs_vm_t *vm, njs_v njs_string_create(vm, &value, s.start, s.length); } + } else if (memcmp(mode.start, "chb", 3) == 0) { + + NJS_CHB_MP_INIT(&chain, vm); + + njs_chb_append_literal(&chain, "abc"); + njs_chb_append(&chain, s.start, s.length); + njs_chb_append_literal(&chain, "abc"); + njs_chb_append(&chain, s.start, s.length); + njs_chb_append_literal(&chain, "abc"); + njs_chb_append(&chain, s.start, s.length); + + for (i = 0; i < n; i++) { + njs_string_create_chb(vm, &value, &chain); + } + + njs_chb_destroy(&chain); + } else { njs_type_error(vm, "unknown mode \"%V\"", &mode); return NJS_ERROR; From xeioex at nginx.com Fri May 24 23:01:26 2024 From: xeioex at nginx.com (=?utf-8?q?Dmitry_Volyntsev?=) Date: Fri, 24 May 2024 23:01:26 +0000 Subject: [njs] Fetch: fixed heap-buffer-overflow in Headers.get(). Message-ID: details: https://hg.nginx.org/njs/rev/f75f670905f0 branches: changeset: 2339:f75f670905f0 user: Dmitry Volyntsev date: Thu May 23 22:50:34 2024 -0700 description: Fetch: fixed heap-buffer-overflow in Headers.get(). Previously, when more than one header with the same name added to a Headers object and Headers.get() was used to get the the duplicate header heap-buffer-overflow occured. The overflow occurred due to an incorrect calculation of the combined header value's length. The issue was introduced in c43261bad627 (0.7.10). diffstat: nginx/ngx_js_fetch.c | 31 ++++++++++--------------------- 1 files changed, 10 insertions(+), 21 deletions(-) diffs (60 lines): diff -r 437fc09db765 -r f75f670905f0 nginx/ngx_js_fetch.c --- a/nginx/ngx_js_fetch.c Thu May 23 22:50:19 2024 -0700 +++ b/nginx/ngx_js_fetch.c Thu May 23 22:50:34 2024 -0700 @@ -3181,9 +3181,8 @@ static njs_int_t ngx_headers_js_get(njs_vm_t *vm, njs_value_t *value, njs_str_t *name, njs_value_t *retval, njs_bool_t as_array) { - u_char *data, *p; - size_t len; njs_int_t rc; + njs_chb_t chain; ngx_uint_t i; ngx_js_tb_elt_t *h, *ph; ngx_list_part_t *part; @@ -3254,36 +3253,26 @@ ngx_headers_js_get(njs_vm_t *vm, njs_val return NJS_DECLINED; } - len = 0; + NJS_CHB_MP_INIT(&chain, vm); + h = ph; - while (ph != NULL) { - len = ph->value.len + njs_length(", "); - ph = ph->next; - } - - len -= njs_length(", "); - - data = njs_mp_alloc(njs_vm_memory_pool(vm), len); - if (data == NULL) { - njs_vm_memory_error(vm); - return NJS_ERROR; - } - - p = data; - for ( ;; ) { - p = ngx_cpymem(p, h->value.data, h->value.len); + njs_chb_append(&chain, h->value.data, h->value.len); if (h->next == NULL) { break; } - *p++ = ','; *p++ = ' '; + njs_chb_append_literal(&chain, ", "); h = h->next; } - return njs_vm_value_string_create(vm, retval, data, p - data); + rc = njs_vm_value_string_create_chb(vm, retval, &chain); + + njs_chb_destroy(&chain); + + return rc; } From zjli at cnic.cn Sun May 26 12:56:25 2024 From: zjli at cnic.cn (=?UTF-8?B?5p2O54Sv5Z2a?=) Date: Sun, 26 May 2024 20:56:25 +0800 (GMT+08:00) Subject: Inquiry about QUIC Congestion Control Algorithms Development Message-ID: <130469f7.2e352.18fb4f942a0.Coremail.zjli@cnic.cn> Hi, I've been following the development of the QUIC protocol within Nginx, and I am particularly interested in the implementation of advanced congestion control algorithms such as BBR and CUBIC. Considering the impact that these algorithms can have on network performance, especially in scenarios where QUIC is being utilized, I was hoping to get some insights into the current or planned support for these within the Nginx ecosystem. Are there any ongoing efforts or discussions regarding the adoption of BBR, CUBIC, or similar congestion control algorithms for QUIC in Nginx? If so, could you please share some details or point me towards the relevant discussions or documentation? Thank you for your continued work on Nginx and for any information you can provide on this topic. Best regards, Zhuojian Li -------------- next part -------------- An HTML attachment was scrubbed... URL: From pluknet at nginx.com Sun May 26 21:13:58 2024 From: pluknet at nginx.com (Sergey Kandaurov) Date: Mon, 27 May 2024 01:13:58 +0400 Subject: [PATCH] Tests: ssl_engine_keys.t improved In-Reply-To: References: Message-ID: [ extraneous "Cc: PATCH, ssl_engine_keys.t" removed ] On Tue, May 07, 2024 at 11:32:45PM +0300, o.deeva at wbsrv.ru wrote: > # HG changeset patch > # User Oksana Deeva > # Date 1715111756 -10800 > # Tue May 07 22:55:56 2024 +0300 > # Node ID e5014b423e1391dd1078d064361a0b28d1a488d0 > # Parent 2a607a31f583add7adfa1ac434a3f793d327ca6b Hello, thanks for the patch. > Tests: ssl_engine_keys.t improved style: missing period For generic commit log style, see example in http://nginx.org/en/docs/contributing_changes.html > > diff -r 2a607a31f583 -r e5014b423e13 ssl_engine_keys.t > --- a/ssl_engine_keys.t Tue Apr 23 17:59:53 2024 +0400 > +++ b/ssl_engine_keys.t Tue May 07 22:55:56 2024 +0300 > @@ -28,7 +28,7 @@ > unless $ENV{TEST_NGINX_UNSAFE}; > > my $t = Test::Nginx->new()->has(qw/http proxy http_ssl/)->has_daemon('openssl') > - ->has_daemon('softhsm2-util')->has_daemon('pkcs11-tool')->plan(2); > + ->has_daemon('softhsm2-util')->has_daemon('pkcs11-tool'); > > $t->write_file_expand('nginx.conf', <<'EOF'); > > @@ -86,9 +86,29 @@ > # > # http://mailman.nginx.org/pipermail/nginx-devel/2014-October/006151.html > # > -# Note that library paths may differ on different systems, > +# Note that library paths vary on different systems, > # and may need to be adjusted. > > +my $libsofthsm2_path; > +my @so_paths = ( > + '/usr/lib/softhsm/', # alpine, astrase, debian, ubuntu > + '/usr/lib64/softhsm/', # rosachrome, rosafresh I couldn't test on rosa* variants and cannot claim the path is valid. The most closest I was able to find is a spec file on repology. From there, the library seems to be installed at various compat locations, including compatibility with Fedora. So, likely it should be fine to run the test with rhel-based path. On the other hand, the list is open-ended, and it makes sense to allow appending it in some handy way. > + '/usr/local/lib/softhsm/', # freebsd > + '/lib64/', # redos, almalinux, centos, oracle, rocky > +); > +for my $so_path (@so_paths) { > + my $path = $so_path . 'libsofthsm2.so'; > + if (-e $path) { > + $libsofthsm2_path = $path; > + last; > + } > +}; > + > +die 'Can\'t determine libsofthsm2.so path' > + unless $libsofthsm2_path; I don't like terminating the test in unclean fasion just because we are not aware of a path the library was installed on. Note that the "softhsm2-util" availability was checked prior to this. > + > +note("libsofthsm2_path: $libsofthsm2_path"); > + > $t->write_file('openssl.conf', < openssl_conf = openssl_def > > @@ -100,8 +120,8 @@ > > [pkcs11_section] > engine_id = pkcs11 > -dynamic_path = /usr/local/lib/engines/pkcs11.so > -MODULE_PATH = /usr/local/lib/softhsm/libsofthsm2.so > +#dynamic_path = /usr/local/lib/engines/pkcs11.so Commenting out "dynamic_path" will break running on FreeBSD. Note that both base and ports' openssl seeks for pkcs11.so on paths different from the installed one by package libp11. > +MODULE_PATH = $libsofthsm2_path > init = 1 > PIN = 1234 > > @@ -125,21 +145,37 @@ > $ENV{OPENSSL_CONF} = "$d/openssl.conf"; > > foreach my $name ('localhost') { > - system('softhsm2-util --init-token --slot 0 --label NginxZero ' > + my $cmd = 'softhsm2-util --init-token --slot 0 --label NginxZero ' > . '--pin 1234 --so-pin 1234 ' > - . ">>$d/openssl.out 2>&1"); > + . ">>$d/openssl.out 2>&1"; > + > + note("SOFTHSM2_CONF=$d/softhsm2.conf OPENSSL_CONF=$d/openssl.conf $cmd"); note() is a direct call to Test::More and may not be suppressed by out test suite, please avoid using it. Instead, log_core() and variants should be used, if at all. Here it makes little use. > + > + system($cmd); > > - system('pkcs11-tool --module=/usr/local/lib/softhsm/libsofthsm2.so ' > + $cmd = "pkcs11-tool --module=$libsofthsm2_path " > . '-p 1234 -l -k -d 0 -a nx_key_0 --key-type rsa:2048 ' > - . ">>$d/openssl.out 2>&1"); > + . ">>$d/openssl.out 2>&1"; > + > + note("SOFTHSM2_CONF=$d/softhsm2.conf OPENSSL_CONF=$d/openssl.conf $cmd"); > > - system('openssl req -x509 -new ' > + system($cmd); > + > + $cmd = 'openssl req -x509 -new ' > . "-subj /CN=$name/ -out $d/$name.crt -text " > . "-engine pkcs11 -keyform engine -key id_00 " > - . ">>$d/openssl.out 2>&1") == 0 > - or die "Can't create certificate for $name: $!\n"; > + . ">>$d/openssl.out 2>&1"; > + > + note("SOFTHSM2_CONF=$d/softhsm2.conf OPENSSL_CONF=$d/openssl.conf $cmd"); > + > + my $openssl_call_result = system($cmd); > + > + plan(skip_all => "Can't create certificate for $name: $!\n") > + unless $openssl_call_result == 0; Such wording is badly suitable for skip_all reason. You may want to examine existing cases and mimic it. > } > > +$t->plan(2); > + > $t->run(); > > $t->write_file('index.html', ''); Below is the patch I tested on FreeBSD, RHEL- and Debian-based. It should also work on exhotic platforms without modifications. Please test if it works for you. # HG changeset patch # User Sergey Kandaurov # Date 1716757790 -14400 # Mon May 27 01:09:50 2024 +0400 # Node ID 6b0ad2d8bda5eaf9b69ad211f9bf28a85fe42cee # Parent 5068d45ea46515e3437ba978ad012f05ce137374 Tests: adjusted ssl_engine_keys.t to run on Linux. Previously, library paths were hardcoded for FreeBSD. The TEST_NGINX_SOFTHSM environment variable is used to append the list of tested directories to look for the softhsm library. Further, testing demostrated that the "dynamic_path" command is needed for FreeBSD only, where openssl is badly packaged. Based on a patch by Oksana Deeva. diff --git a/ssl_engine_keys.t b/ssl_engine_keys.t --- a/ssl_engine_keys.t +++ b/ssl_engine_keys.t @@ -28,7 +28,7 @@ plan(skip_all => 'may not work, leaves c unless $ENV{TEST_NGINX_UNSAFE}; my $t = Test::Nginx->new()->has(qw/http proxy http_ssl/)->has_daemon('openssl') - ->has_daemon('softhsm2-util')->has_daemon('pkcs11-tool')->plan(2); + ->has_daemon('softhsm2-util')->has_daemon('pkcs11-tool'); $t->write_file_expand('nginx.conf', <<'EOF'); @@ -86,10 +86,28 @@ EOF # # http://mailman.nginx.org/pipermail/nginx-devel/2014-October/006151.html # -# Note that library paths may differ on different systems, +# Note that library paths vary on different systems, # and may need to be adjusted. -$t->write_file('openssl.conf', < "libsofthsm2.so not found") unless $libsofthsm2_path; + +my $openssl_conf = <write_file('openssl.conf', $openssl_conf); + my $d = $t->testdir(); $t->write_file('softhsm2.conf', <>$d/openssl.out 2>&1"); - system('pkcs11-tool --module=/usr/local/lib/softhsm/libsofthsm2.so ' + system("pkcs11-tool --module=$libsofthsm2_path " . '-p 1234 -l -k -d 0 -a nx_key_0 --key-type rsa:2048 ' . ">>$d/openssl.out 2>&1"); @@ -137,10 +158,10 @@ foreach my $name ('localhost') { . "-subj /CN=$name/ -out $d/$name.crt -text " . "-engine pkcs11 -keyform engine -key id_00 " . ">>$d/openssl.out 2>&1") == 0 - or die "Can't create certificate for $name: $!\n"; + or plan(skip_all => "missing engine"); } -$t->run(); +$t->run()->plan(2); $t->write_file('index.html', ''); From jordanc.carter at outlook.com Mon May 27 03:30:53 2024 From: jordanc.carter at outlook.com (=?iso-8859-1?q?J_Carter?=) Date: Mon, 27 May 2024 04:30:53 +0100 Subject: [PATCH] Memcached: memcached_flags_set directive Message-ID: # HG changeset patch # User J Carter # Date 1716779649 -3600 # Mon May 27 04:14:09 2024 +0100 # Node ID e90301dd1516b6dfa5b2b0beec05cfe2b567ea1e # Parent f58b6f6362387eeace46043a6fc0bceb56a6786a Memcached: memcached_flags_set directive. This directive creates a variable that returns the masked value of memcached response flags, by bitwise ANDing flags with specified mask. The optional 'shift' parameter may be used right bit-shift extracted value, for unpacking values. memcached_flags_set This directive may be specified in http context only. The purpose of this directive is to provide a more generalized form of the memcached_gzip_flag directive, to provide the means of conditionally adding other headers to response, such as cache control headers, and of setting their value dynamically using packed values in flags. Example #1: memcached_flags_set $flags_expire 1; map $flags_expire $expires_value { 0 off; 1 epoch; } server { location / { expires $expires_value; memcached_pass ...; } } Example #2: memcached_flags_set $flags_expire 1 0; memcached_flags_set $flags_expire 62 1; map $flags_expire $expires_value { 0 off; 1 ${flags_expire_hour}h; #0-24h } server { location / { expires $expires_value; memcached_pass ...; } } diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -21,9 +21,16 @@ size_t rest; ngx_http_request_t *request; ngx_str_t key; + ngx_uint_t flags; } ngx_http_memcached_ctx_t; +typedef struct { + ngx_uint_t mask; + ngx_uint_t shift; +} ngx_http_memcached_set_t; + + static ngx_int_t ngx_http_memcached_create_request(ngx_http_request_t *r); static ngx_int_t ngx_http_memcached_reinit_request(ngx_http_request_t *r); static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r); @@ -33,12 +40,16 @@ static void ngx_http_memcached_finalize_request(ngx_http_request_t *r, ngx_int_t rc); +static ngx_int_t ngx_http_memcached_variable_set(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static void *ngx_http_memcached_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_memcached_set(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_conf_bitmask_t ngx_http_memcached_next_upstream_masks[] = { @@ -130,6 +141,13 @@ offsetof(ngx_http_memcached_loc_conf_t, gzip_flag), NULL }, + { ngx_string("memcached_flags_set"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE23, + ngx_http_memcached_set, + 0, + 0, + NULL }, + ngx_null_command }; @@ -219,6 +237,7 @@ } ctx->request = r; + ctx->flags = 0; ngx_http_set_ctx(r, ctx, ngx_http_memcached_module); @@ -370,20 +389,12 @@ start = p; - while (*p) { - if (*p++ == ' ') { - if (mlcf->gzip_flag) { - goto flags; - } else { - goto length; - } + while (*p++ != ' ') { + if (*p == '\0') { + goto no_valid; } } - goto no_valid; - - flags: - flags = ngx_atoi(start, p - start - 1); if (flags == (ngx_uint_t) NGX_ERROR) { @@ -407,7 +418,9 @@ r->headers_out.content_encoding = h; } - length: + ctx->flags = flags; + + /* length */ start = p; p = line.data + line.len; @@ -587,6 +600,38 @@ } +static ngx_int_t +ngx_http_memcached_variable_set(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_memcached_ctx_t *ctx; + ngx_http_memcached_set_t *set; + + set = (ngx_http_memcached_set_t *) data; + + ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module); + if (ctx == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->data = ngx_pnalloc(r->pool, sizeof("4294967295") - 1); + if (v->data == NULL) { + return NGX_ERROR; + } + + v->len = 0; + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + v->len = ngx_sprintf(v->data, "%ui", + (ctx->flags & set->mask) >> set->shift) - v->data; + + return NGX_OK; +} + + static void * ngx_http_memcached_create_loc_conf(ngx_conf_t *cf) { @@ -734,3 +779,59 @@ return NGX_CONF_OK; } + + +static char * +ngx_http_memcached_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ngx_http_variable_t *v; + ngx_http_memcached_set_t *set; + + value = cf->args->elts; + + if (value[1].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + value[1].len--; + value[1].data++; + + v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_NOCACHEABLE); + if (v == NULL) { + return NGX_CONF_ERROR; + } + + set = ngx_palloc(cf->pool, sizeof(ngx_http_memcached_set_t)); + if (set == NULL) { + return NGX_CONF_ERROR; + } + + set->mask = ngx_atoi(value[2].data, value[2].len); + + if (set->mask == (ngx_uint_t) NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid mask \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + set->shift = 0; + + if (cf->args->nelts > 3) { + + set->shift = ngx_atoi(value[3].data, value[3].len); + + if (set->shift == (ngx_uint_t) NGX_ERROR || set->shift > 31) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid shift \"%V\"", &value[3]); + return NGX_CONF_ERROR; + } + } + + v->data = (uintptr_t) set; + v->get_handler = ngx_http_memcached_variable_set; + + return NGX_CONF_OK; +} From jordanc.carter at outlook.com Mon May 27 05:58:50 2024 From: jordanc.carter at outlook.com (J Carter) Date: Mon, 27 May 2024 06:58:50 +0100 Subject: [PATCH] Memcached: memcached_flags_set directive In-Reply-To: References: Message-ID: Fixed a typo in patch description, and overlooked buffer overflow... # HG changeset patch # User J Carter # Date 1716779649 -3600 # Mon May 27 04:14:09 2024 +0100 # Node ID e2ebeb2b05062369626e2de1ba753f318f821d9c # Parent f58b6f6362387eeace46043a6fc0bceb56a6786a Memcached: memcached_flags_set directive. This directive creates a variable that returns the masked value of memcached response flags, by bitwise ANDing flags with specified mask. The optional 'shift' parameter may be used right bit-shift extracted value, for unpacking values. memcached_flags_set This directive may be specified in http context only. The purpose of this directive is to provide a more generalized form of the memcached_gzip_flag directive, to provide the means of conditionally adding other headers to response, such as cache control headers, and of setting their value dynamically using packed values in flags. Example #1: memcached_flags_set $flags_expire 1; map $flags_expire $expires_value { 0 off; 1 epoch; } server { location / { expires $expires_value; memcached_pass ...; } } Example #2: memcached_flags_set $flags_expire 1 0; memcached_flags_set $flags_expire_hour 62 1; map $flags_expire $expires_value { 0 off; 1 ${flags_expire_hour}h; #0-24h } server { location / { expires $expires_value; memcached_pass ...; } } diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -21,9 +21,16 @@ size_t rest; ngx_http_request_t *request; ngx_str_t key; + ngx_uint_t flags; } ngx_http_memcached_ctx_t; +typedef struct { + ngx_uint_t mask; + ngx_uint_t shift; +} ngx_http_memcached_set_t; + + static ngx_int_t ngx_http_memcached_create_request(ngx_http_request_t *r); static ngx_int_t ngx_http_memcached_reinit_request(ngx_http_request_t *r); static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r); @@ -33,12 +40,16 @@ static void ngx_http_memcached_finalize_request(ngx_http_request_t *r, ngx_int_t rc); +static ngx_int_t ngx_http_memcached_variable_set(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static void *ngx_http_memcached_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_memcached_set(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_conf_bitmask_t ngx_http_memcached_next_upstream_masks[] = { @@ -130,6 +141,13 @@ offsetof(ngx_http_memcached_loc_conf_t, gzip_flag), NULL }, + { ngx_string("memcached_flags_set"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE23, + ngx_http_memcached_set, + 0, + 0, + NULL }, + ngx_null_command }; @@ -219,6 +237,7 @@ } ctx->request = r; + ctx->flags = 0; ngx_http_set_ctx(r, ctx, ngx_http_memcached_module); @@ -370,20 +389,12 @@ start = p; - while (*p) { - if (*p++ == ' ') { - if (mlcf->gzip_flag) { - goto flags; - } else { - goto length; - } + while (*p++ != ' ') { + if (*p == '\0') { + goto no_valid; } } - goto no_valid; - - flags: - flags = ngx_atoi(start, p - start - 1); if (flags == (ngx_uint_t) NGX_ERROR) { @@ -407,7 +418,9 @@ r->headers_out.content_encoding = h; } - length: + ctx->flags = flags; + + /* length */ start = p; p = line.data + line.len; @@ -587,6 +600,42 @@ } +static ngx_int_t +ngx_http_memcached_variable_set(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_memcached_ctx_t *ctx; + ngx_http_memcached_set_t *set; + ngx_uint_t value; + + set = (ngx_http_memcached_set_t *) data; + + ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module); + if (ctx == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->data = ngx_pnalloc(r->pool, sizeof("4294967295") - 1); + if (v->data == NULL) { + return NGX_ERROR; + } + + v->len = 0; + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + value = (ctx->flags & set->mask) >> set->shift; + + if (value <= 4294967295) { + v->len = ngx_sprintf(v->data, "%ui", value) - v->data; + } + + return NGX_OK; +} + + static void * ngx_http_memcached_create_loc_conf(ngx_conf_t *cf) { @@ -734,3 +783,61 @@ return NGX_CONF_OK; } + + +static char * +ngx_http_memcached_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ngx_http_variable_t *v; + ngx_http_memcached_set_t *set; + + value = cf->args->elts; + + if (value[1].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + value[1].len--; + value[1].data++; + + v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_NOCACHEABLE); + if (v == NULL) { + return NGX_CONF_ERROR; + } + + set = ngx_palloc(cf->pool, sizeof(ngx_http_memcached_set_t)); + if (set == NULL) { + return NGX_CONF_ERROR; + } + + set->mask = ngx_atoi(value[2].data, value[2].len); + + if (set->mask == (ngx_uint_t) NGX_ERROR + || set->mask > NGX_MAX_UINT32_VALUE) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid mask \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + set->shift = 0; + + if (cf->args->nelts > 3) { + + set->shift = ngx_atoi(value[3].data, value[3].len); + + if (set->shift == (ngx_uint_t) NGX_ERROR || set->shift > 31) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid shift \"%V\"", &value[3]); + return NGX_CONF_ERROR; + } + } + + v->data = (uintptr_t) set; + v->get_handler = ngx_http_memcached_variable_set; + + return NGX_CONF_OK; +} From arut at nginx.com Mon May 27 10:06:58 2024 From: arut at nginx.com (Roman Arutyunyan) Date: Mon, 27 May 2024 14:06:58 +0400 Subject: I think I found a fix for the memory leak issue on gRPC module In-Reply-To: <20240523094224.6n4ihcqrgsl54nxk@N00W24XTQX> References: <20240522141426.ahzeenwq2qom3m4f@N00W24XTQX> <20240523094224.6n4ihcqrgsl54nxk@N00W24XTQX> Message-ID: <20240527100658.nvgq5ebpk4xnvutd@N00W24XTQX> Hi, Following an internal discussion with Sergey, here's an updated version of the patch. On Thu, May 23, 2024 at 01:42:24PM +0400, Roman Arutyunyan wrote: > Hi, > > On Wed, May 22, 2024 at 06:14:26PM +0400, Roman Arutyunyan wrote: > > Hi, > > > > Indeed there's a problem there. We have similar problems in other places as > > well. Attached is a patch that fixes all I could find. > > > > I did some testing for the sub_filter with the following config. Small buffers > > exaggerate the problem. > > > > http { > > server { > > listen 8000; > > > > location / { > > root html; > > > > output_buffers 2 128; > > > > sub_filter 1 2; > > sub_filter_types *; > > sub_filter_once off; > > } > > } > > } > > > > Retrieving a 10m file resulted in 7304 (patched) vs 1317704 (unpatched) bytes > > allocated from the request pool. With the default output_buffers (2 32768), > > it's 79880 vs 84040. > > I tested ssi with the following config. > > server { > listen 8000; > > location / { > root html; > > output_buffers 2 128; > > ssi on; > ssi_types *; > } > } > > The result is similar: > > 6224 vs 1316912 with small buffers > 38864 vs 43952 with the default buffers > > > On Thu, May 02, 2024 at 07:59:44AM +0000, Pavel Pautov via nginx-devel wrote: > > > Hi Sangmin, > > > > > > Your analysis looks correct. Client streaming RPCs can lead to unbound accumulation of ngx_chain_t objects (although, at very slow rate). Gzip module had a similar issue (https://trac.nginx.org/nginx/ticket/1046). > > > Attaching somewhat simplified patch based on yours. I was able to reproduce the issue locally and the patch fixes it. > > > > > > From: nginx-devel On Behalf Of Sangmin Lee > > > Sent: Thursday, April 4, 2024 19:29 > > > To: nginx-devel at nginx.org > > > Subject: I think I found a fix for the memory leak issue on gRPC module > > > > > > CAUTION: This email has been sent from an external source. Do not click links, open attachments, or provide sensitive business information unless you can verify the sender's legitimacy. > > > > > > I am sending this mail again because I did a mistake while I was writing a mail. I didn't know, in gmail, "Ctrl - Enter" would send a mail immediately even without a title! > > > I am sorry for that, so I am sending again. > > > > > > Hello, > > > > > > I think I found the main cause of the memory leak issue when using gRPC stream so I made a patch for it. > > > Please find the test scenario and details here -- This is what I wrote.: > > > https://trac.nginx.org/nginx/ticket/2614 > > > After I changed the memory pool totally on nginx and tested our workload -- long-lived gRPC streams with many connections -- using Valgrind and massif, I was able to find what brought up the memory leak issue. > > > like the picture below. > > > > > > [cid:image001.png at 01DA9C29.C792CD90] > > > ( I am not sure whether this picture will be sent properly ) > > > > > > After I patched one part, it seems okay now I have tested it for 1 week with out workload. > > > > > > [cid:image002.png at 01DA9C29.C792CD90] > > > ( I am not sure whether this picture will be sent properly ) > > > > > > But because I am not familiar with Mercurial, I couldn't find a way to create PR like on github. I guess this mailing list is for this patch. > > > From my point of view, it is more like a workaround and I think the way of using ngx_chain_add_copy() or itself needs to be changed because it allocates a ngx_chain_t structure using ngx_alloc_chain_link() but inside of that, it just copies pointer, like cl->buf = in->buf; > > > so this ngx_chain_t instance should be dealt with differently unlike other ngx_chain_t instances. > > > But I am quite new to nginx codes so my view might be wrong. > > > Anyhow, please go over this patch and I would like to further talk here. > > > > > > -------------------------------------------------------------------------------------------------------------------------------------------- > > > > > > diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c > > > index dfe49c586..1db67bd0a 100644 > > > --- a/src/http/modules/ngx_http_grpc_module.c > > > +++ b/src/http/modules/ngx_http_grpc_module.c > > > @@ -1462,6 +1462,12 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) > > > in = in->next; > > > } > > > > > > + ngx_chain_t *nl; > > > + for (ngx_chain_t *dl = ctx->in; dl != in; dl = nl ) { > > > + nl = dl->next; > > > + ngx_free_chain(r->pool, dl); > > > + } > > > + > > > ctx->in = in; > > > > > > if (last) { > > > > > > -------------------------------------------------------------------------------------------------------------------------------------------- > > > > > > Best regards, > > > Sangmin > > > > > > > > > > > > > _______________________________________________ > > > nginx-devel mailing list > > > nginx-devel at nginx.org > > > https://mailman.nginx.org/mailman/listinfo/nginx-devel > > > > > > -- > > Roman Arutyunyan > > > # HG changeset patch > > # User Roman Arutyunyan > > # Date 1716386385 -14400 > > # Wed May 22 17:59:45 2024 +0400 > > # Node ID 95af5fe4921294b48e634defc03b6b0f0201d6f7 > > # Parent e60377bdee3d0f8dbd237b5ae8a5deab2af785ef > > Optimized chain link usage (ticket #2614). > > > > Previously chain links could sometimes be dropped instead of being reused, > > which could result in increased memory consumption during long requests. > > > > A similar chain link issue in ngx_http_gzip_filter_module was fixed in > > da46bfc484ef (1.11.10). > > > > Based on a patch by Sangmin Lee. > > > > diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c > > --- a/src/core/ngx_output_chain.c > > +++ b/src/core/ngx_output_chain.c > > @@ -117,7 +117,10 @@ ngx_output_chain(ngx_output_chain_ctx_t > > > > ngx_debug_point(); > > > > - ctx->in = ctx->in->next; > > + cl = ctx->in; > > + ctx->in = cl->next; > > + > > + ngx_free_chain(ctx->pool, cl); > > > > continue; > > } > > @@ -203,7 +206,10 @@ ngx_output_chain(ngx_output_chain_ctx_t > > /* delete the completed buf from the ctx->in chain */ > > > > if (ngx_buf_size(ctx->in->buf) == 0) { > > - ctx->in = ctx->in->next; > > + cl = ctx->in; > > + ctx->in = cl->next; > > + > > + ngx_free_chain(ctx->pool, cl); > > } > > > > cl = ngx_alloc_chain_link(ctx->pool); > > diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c > > --- a/src/http/modules/ngx_http_grpc_module.c > > +++ b/src/http/modules/ngx_http_grpc_module.c > > @@ -1459,7 +1459,10 @@ ngx_http_grpc_body_output_filter(void *d > > last = 1; > > } > > > > + cl = in; > > in = in->next; > > + > > + ngx_free_chain(r->pool, cl); > > } > > > > ctx->in = in; > > diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c > > --- a/src/http/modules/ngx_http_gunzip_filter_module.c > > +++ b/src/http/modules/ngx_http_gunzip_filter_module.c > > @@ -333,6 +333,8 @@ static ngx_int_t > > ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, > > ngx_http_gunzip_ctx_t *ctx) > > { > > + ngx_chain_t *cl; > > + > > if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { > > return NGX_OK; > > } > > @@ -344,8 +346,11 @@ ngx_http_gunzip_filter_add_data(ngx_http > > return NGX_DECLINED; > > } > > > > - ctx->in_buf = ctx->in->buf; > > - ctx->in = ctx->in->next; > > + cl = ctx->in; > > + ctx->in_buf = cl->buf; > > + ctx->in = cl->next; > > + > > + ngx_free_chain(r->pool, cl); > > > > ctx->zstream.next_in = ctx->in_buf->pos; > > ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; > > @@ -383,8 +388,12 @@ ngx_http_gunzip_filter_get_buf(ngx_http_ > > conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); > > > > if (ctx->free) { > > - ctx->out_buf = ctx->free->buf; > > - ctx->free = ctx->free->next; > > + > > + cl = ctx->free; > > + ctx->out_buf = cl->buf; > > + ctx->free = cl->next; > > + > > + ngx_free_chain(r->pool, cl); > > > > ctx->out_buf->flush = 0; > > > > diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c > > --- a/src/http/modules/ngx_http_gzip_filter_module.c > > +++ b/src/http/modules/ngx_http_gzip_filter_module.c > > @@ -985,10 +985,12 @@ static void > > ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, > > ngx_http_gzip_ctx_t *ctx) > > { > > - ngx_chain_t *cl; > > + ngx_chain_t *cl, *next; > > > > - for (cl = ctx->copied; cl; cl = cl->next) { > > + for (cl = ctx->copied; cl; cl = next) { > > ngx_pfree(r->pool, cl->buf->start); > > + next = cl->next; > > + ngx_free_chain(r->pool, cl); > > } > > > > ctx->copied = NULL; > > diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c > > --- a/src/http/modules/ngx_http_ssi_filter_module.c > > +++ b/src/http/modules/ngx_http_ssi_filter_module.c > > @@ -482,9 +482,13 @@ ngx_http_ssi_body_filter(ngx_http_reques > > while (ctx->in || ctx->buf) { > > > > if (ctx->buf == NULL) { > > - ctx->buf = ctx->in->buf; > > - ctx->in = ctx->in->next; > > + > > + cl = ctx->in; > > + ctx->buf = cl->buf; > > + ctx->in = cl->next; > > ctx->pos = ctx->buf->pos; > > + > > + ngx_free_chain(r->pool, cl); > > } > > > > if (ctx->state == ssi_start_state) { > > diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c > > --- a/src/http/modules/ngx_http_sub_filter_module.c > > +++ b/src/http/modules/ngx_http_sub_filter_module.c > > @@ -335,9 +335,13 @@ ngx_http_sub_body_filter(ngx_http_reques > > while (ctx->in || ctx->buf) { > > > > if (ctx->buf == NULL) { > > - ctx->buf = ctx->in->buf; > > - ctx->in = ctx->in->next; > > + > > + cl = ctx->in; > > + ctx->buf = cl->buf; > > + ctx->in = cl->next; > > ctx->pos = ctx->buf->pos; > > + > > + ngx_free_chain(r->pool, cl); > > } > > > > if (ctx->buf->flush || ctx->buf->recycled) { > > > _______________________________________________ > > nginx-devel mailing list > > nginx-devel at nginx.org > > https://mailman.nginx.org/mailman/listinfo/nginx-devel > > -- > Roman Arutyunyan > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://mailman.nginx.org/mailman/listinfo/nginx-devel -- Roman Arutyunyan -------------- next part -------------- # HG changeset patch # User Roman Arutyunyan # Date 1716477338 -14400 # Thu May 23 19:15:38 2024 +0400 # Node ID f7d53c7f70140b1cd1eaf51ce4346a873692f879 # Parent f58b6f6362387eeace46043a6fc0bceb56a6786a Optimized chain link usage (ticket #2614). Previously chain links could sometimes be dropped instead of being reused, which could result in increased memory consumption during long requests. A similar chain link issue in ngx_http_gzip_filter_module was fixed in da46bfc484ef (1.11.10). Based on a patch by Sangmin Lee. diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -117,7 +117,10 @@ ngx_output_chain(ngx_output_chain_ctx_t ngx_debug_point(); - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in = cl->next; + + ngx_free_chain(ctx->pool, cl); continue; } @@ -203,7 +206,10 @@ ngx_output_chain(ngx_output_chain_ctx_t /* delete the completed buf from the ctx->in chain */ if (ngx_buf_size(ctx->in->buf) == 0) { - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in = cl->next; + + ngx_free_chain(ctx->pool, cl); } cl = ngx_alloc_chain_link(ctx->pool); diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -1231,7 +1231,7 @@ ngx_http_grpc_body_output_filter(void *d ngx_buf_t *b; ngx_int_t rc; ngx_uint_t next, last; - ngx_chain_t *cl, *out, **ll; + ngx_chain_t *cl, *out, *ln, **ll; ngx_http_upstream_t *u; ngx_http_grpc_ctx_t *ctx; ngx_http_grpc_frame_t *f; @@ -1459,7 +1459,10 @@ ngx_http_grpc_body_output_filter(void *d last = 1; } + ln = in; in = in->next; + + ngx_free_chain(r->pool, ln); } ctx->in = in; diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c --- a/src/http/modules/ngx_http_gunzip_filter_module.c +++ b/src/http/modules/ngx_http_gunzip_filter_module.c @@ -333,6 +333,8 @@ static ngx_int_t ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, ngx_http_gunzip_ctx_t *ctx) { + ngx_chain_t *cl; + if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { return NGX_OK; } @@ -344,8 +346,11 @@ ngx_http_gunzip_filter_add_data(ngx_http return NGX_DECLINED; } - ctx->in_buf = ctx->in->buf; - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in_buf = cl->buf; + ctx->in = cl->next; + + ngx_free_chain(r->pool, cl); ctx->zstream.next_in = ctx->in_buf->pos; ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; @@ -374,6 +379,7 @@ static ngx_int_t ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, ngx_http_gunzip_ctx_t *ctx) { + ngx_chain_t *cl; ngx_http_gunzip_conf_t *conf; if (ctx->zstream.avail_out) { @@ -383,8 +389,12 @@ ngx_http_gunzip_filter_get_buf(ngx_http_ conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); if (ctx->free) { - ctx->out_buf = ctx->free->buf; - ctx->free = ctx->free->next; + + cl = ctx->free; + ctx->out_buf = cl->buf; + ctx->free = cl->next; + + ngx_free_chain(r->pool, cl); ctx->out_buf->flush = 0; diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -985,10 +985,14 @@ static void ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { - ngx_chain_t *cl; + ngx_chain_t *cl, *ln; - for (cl = ctx->copied; cl; cl = cl->next) { - ngx_pfree(r->pool, cl->buf->start); + for (cl = ctx->copied; cl; /* void */) { + ln = cl; + cl = cl->next; + + ngx_pfree(r->pool, ln->buf->start); + ngx_free_chain(r->pool, ln); } ctx->copied = NULL; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -482,9 +482,13 @@ ngx_http_ssi_body_filter(ngx_http_reques while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { - ctx->buf = ctx->in->buf; - ctx->in = ctx->in->next; + + cl = ctx->in; + ctx->buf = cl->buf; + ctx->in = cl->next; ctx->pos = ctx->buf->pos; + + ngx_free_chain(r->pool, cl); } if (ctx->state == ssi_start_state) { diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -335,9 +335,13 @@ ngx_http_sub_body_filter(ngx_http_reques while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { - ctx->buf = ctx->in->buf; - ctx->in = ctx->in->next; + + cl = ctx->in; + ctx->buf = cl->buf; + ctx->in = cl->next; ctx->pos = ctx->buf->pos; + + ngx_free_chain(r->pool, cl); } if (ctx->buf->flush || ctx->buf->recycled) { From pluknet at nginx.com Mon May 27 10:08:29 2024 From: pluknet at nginx.com (Sergey Kandaurov) Date: Mon, 27 May 2024 14:08:29 +0400 Subject: I think I found a fix for the memory leak issue on gRPC module In-Reply-To: <20240522141426.ahzeenwq2qom3m4f@N00W24XTQX> References: <20240522141426.ahzeenwq2qom3m4f@N00W24XTQX> Message-ID: On Wed, May 22, 2024 at 06:14:26PM +0400, Roman Arutyunyan wrote: > Hi, > > Indeed there's a problem there. We have similar problems in other places as > well. Attached is a patch that fixes all I could find. > > I did some testing for the sub_filter with the following config. Small buffers > exaggerate the problem. > > http { > server { > listen 8000; > > location / { > root html; > > output_buffers 2 128; > > sub_filter 1 2; > sub_filter_types *; > sub_filter_once off; > } > } > } > > Retrieving a 10m file resulted in 7304 (patched) vs 1317704 (unpatched) bytes > allocated from the request pool. With the default output_buffers (2 32768), > it's 79880 vs 84040. Note that unlike in sub_filter and gzip modules, gRPC logic is more flawed as the buffer size in user controlled. > > > On Thu, May 02, 2024 at 07:59:44AM +0000, Pavel Pautov via nginx-devel wrote: > > Hi Sangmin, > > > > Your analysis looks correct. Client streaming RPCs can lead to unbound accumulation of ngx_chain_t objects (although, at very slow rate). Gzip module had a similar issue (https://trac.nginx.org/nginx/ticket/1046). > > Attaching somewhat simplified patch based on yours. I was able to reproduce the issue locally and the patch fixes it. > > > > From: nginx-devel On Behalf Of Sangmin Lee > > Sent: Thursday, April 4, 2024 19:29 > > To: nginx-devel at nginx.org > > Subject: I think I found a fix for the memory leak issue on gRPC module > > > > CAUTION: This email has been sent from an external source. Do not click links, open attachments, or provide sensitive business information unless you can verify the sender's legitimacy. > > > > I am sending this mail again because I did a mistake while I was writing a mail. I didn't know, in gmail, "Ctrl - Enter" would send a mail immediately even without a title! > > I am sorry for that, so I am sending again. > > > > Hello, > > > > I think I found the main cause of the memory leak issue when using gRPC stream so I made a patch for it. > > Please find the test scenario and details here -- This is what I wrote.: > > https://trac.nginx.org/nginx/ticket/2614 > > After I changed the memory pool totally on nginx and tested our workload -- long-lived gRPC streams with many connections -- using Valgrind and massif, I was able to find what brought up the memory leak issue. > > like the picture below. > > > > [cid:image001.png at 01DA9C29.C792CD90] > > ( I am not sure whether this picture will be sent properly ) > > > > After I patched one part, it seems okay now I have tested it for 1 week with out workload. > > > > [cid:image002.png at 01DA9C29.C792CD90] > > ( I am not sure whether this picture will be sent properly ) > > > > But because I am not familiar with Mercurial, I couldn't find a way to create PR like on github. I guess this mailing list is for this patch. > > From my point of view, it is more like a workaround and I think the way of using ngx_chain_add_copy() or itself needs to be changed because it allocates a ngx_chain_t structure using ngx_alloc_chain_link() but inside of that, it just copies pointer, like cl->buf = in->buf; > > so this ngx_chain_t instance should be dealt with differently unlike other ngx_chain_t instances. > > But I am quite new to nginx codes so my view might be wrong. > > Anyhow, please go over this patch and I would like to further talk here. > > > > -------------------------------------------------------------------------------------------------------------------------------------------- > > > > diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c > > index dfe49c586..1db67bd0a 100644 > > --- a/src/http/modules/ngx_http_grpc_module.c > > +++ b/src/http/modules/ngx_http_grpc_module.c > > @@ -1462,6 +1462,12 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) > > in = in->next; > > } > > > > + ngx_chain_t *nl; > > + for (ngx_chain_t *dl = ctx->in; dl != in; dl = nl ) { > > + nl = dl->next; > > + ngx_free_chain(r->pool, dl); > > + } > > + > > ctx->in = in; > > > > if (last) { > > > > -------------------------------------------------------------------------------------------------------------------------------------------- > > > > Best regards, > > Sangmin > > > > > > > _______________________________________________ > > nginx-devel mailing list > > nginx-devel at nginx.org > > https://mailman.nginx.org/mailman/listinfo/nginx-devel > > > -- > Roman Arutyunyan > # HG changeset patch > # User Roman Arutyunyan > # Date 1716386385 -14400 > # Wed May 22 17:59:45 2024 +0400 > # Node ID 95af5fe4921294b48e634defc03b6b0f0201d6f7 > # Parent e60377bdee3d0f8dbd237b5ae8a5deab2af785ef > Optimized chain link usage (ticket #2614). > > Previously chain links could sometimes be dropped instead of being reused, > which could result in increased memory consumption during long requests. > > A similar chain link issue in ngx_http_gzip_filter_module was fixed in > da46bfc484ef (1.11.10). > > Based on a patch by Sangmin Lee. > > diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c > --- a/src/core/ngx_output_chain.c > +++ b/src/core/ngx_output_chain.c > @@ -117,7 +117,10 @@ ngx_output_chain(ngx_output_chain_ctx_t > > ngx_debug_point(); > > - ctx->in = ctx->in->next; > + cl = ctx->in; > + ctx->in = cl->next; > + > + ngx_free_chain(ctx->pool, cl); > > continue; > } > @@ -203,7 +206,10 @@ ngx_output_chain(ngx_output_chain_ctx_t > /* delete the completed buf from the ctx->in chain */ > > if (ngx_buf_size(ctx->in->buf) == 0) { > - ctx->in = ctx->in->next; > + cl = ctx->in; > + ctx->in = cl->next; > + > + ngx_free_chain(ctx->pool, cl); > } > > cl = ngx_alloc_chain_link(ctx->pool); > diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c > --- a/src/http/modules/ngx_http_grpc_module.c > +++ b/src/http/modules/ngx_http_grpc_module.c > @@ -1459,7 +1459,10 @@ ngx_http_grpc_body_output_filter(void *d > last = 1; > } > > + cl = in; > in = in->next; > + > + ngx_free_chain(r->pool, cl); cl is used later in this function, this change makes it clobbered > } > > ctx->in = in; > diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c > --- a/src/http/modules/ngx_http_gunzip_filter_module.c > +++ b/src/http/modules/ngx_http_gunzip_filter_module.c > @@ -333,6 +333,8 @@ static ngx_int_t > ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, > ngx_http_gunzip_ctx_t *ctx) > { > + ngx_chain_t *cl; > + > if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { > return NGX_OK; > } > @@ -344,8 +346,11 @@ ngx_http_gunzip_filter_add_data(ngx_http > return NGX_DECLINED; > } > > - ctx->in_buf = ctx->in->buf; > - ctx->in = ctx->in->next; > + cl = ctx->in; > + ctx->in_buf = cl->buf; > + ctx->in = cl->next; > + > + ngx_free_chain(r->pool, cl); > > ctx->zstream.next_in = ctx->in_buf->pos; > ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; > @@ -383,8 +388,12 @@ ngx_http_gunzip_filter_get_buf(ngx_http_ > conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); > > if (ctx->free) { > - ctx->out_buf = ctx->free->buf; > - ctx->free = ctx->free->next; > + > + cl = ctx->free; > + ctx->out_buf = cl->buf; > + ctx->free = cl->next; > + > + ngx_free_chain(r->pool, cl); > > ctx->out_buf->flush = 0; > > diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c > --- a/src/http/modules/ngx_http_gzip_filter_module.c > +++ b/src/http/modules/ngx_http_gzip_filter_module.c > @@ -985,10 +985,12 @@ static void > ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, > ngx_http_gzip_ctx_t *ctx) > { > - ngx_chain_t *cl; > + ngx_chain_t *cl, *next; > > - for (cl = ctx->copied; cl; cl = cl->next) { > + for (cl = ctx->copied; cl; cl = next) { > ngx_pfree(r->pool, cl->buf->start); > + next = cl->next; > + ngx_free_chain(r->pool, cl); > } > > ctx->copied = NULL; > diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c > --- a/src/http/modules/ngx_http_ssi_filter_module.c > +++ b/src/http/modules/ngx_http_ssi_filter_module.c > @@ -482,9 +482,13 @@ ngx_http_ssi_body_filter(ngx_http_reques > while (ctx->in || ctx->buf) { > > if (ctx->buf == NULL) { > - ctx->buf = ctx->in->buf; > - ctx->in = ctx->in->next; > + > + cl = ctx->in; > + ctx->buf = cl->buf; > + ctx->in = cl->next; > ctx->pos = ctx->buf->pos; > + > + ngx_free_chain(r->pool, cl); > } > > if (ctx->state == ssi_start_state) { > diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c > --- a/src/http/modules/ngx_http_sub_filter_module.c > +++ b/src/http/modules/ngx_http_sub_filter_module.c > @@ -335,9 +335,13 @@ ngx_http_sub_body_filter(ngx_http_reques > while (ctx->in || ctx->buf) { > > if (ctx->buf == NULL) { > - ctx->buf = ctx->in->buf; > - ctx->in = ctx->in->next; > + > + cl = ctx->in; > + ctx->buf = cl->buf; > + ctx->in = cl->next; > ctx->pos = ctx->buf->pos; > + > + ngx_free_chain(r->pool, cl); > } > > if (ctx->buf->flush || ctx->buf->recycled) { From arut at nginx.com Mon May 27 10:13:37 2024 From: arut at nginx.com (Roman Arutyunyan) Date: Mon, 27 May 2024 14:13:37 +0400 Subject: Inquiry about QUIC Congestion Control Algorithms Development In-Reply-To: <130469f7.2e352.18fb4f942a0.Coremail.zjli@cnic.cn> References: <130469f7.2e352.18fb4f942a0.Coremail.zjli@cnic.cn> Message-ID: <20240527101337.w5o5w6azf24f23qq@N00W24XTQX> Hi, > Hi, > > I've been following the development of the QUIC protocol within Nginx, and I am particularly interested in the implementation of advanced congestion control algorithms such as BBR and CUBIC. > > Considering the impact that these algorithms can have on network performance, especially in scenarios where QUIC is being utilized, I was hoping to get some insights into the current or planned support for these within the Nginx ecosystem. > > Are there any ongoing efforts or discussions regarding the adoption of BBR, CUBIC, or similar congestion control algorithms for QUIC in Nginx? If so, could you please share some details or point me towards the relevant discussions or documentation? > > Thank you for your continued work on Nginx and for any information you can provide on this topic. We have CUBIC in our roadmap. BBR will be our next step after it, but no particular plans about it so far. -- Roman Arutyunyan From pluknet at nginx.com Mon May 27 10:21:43 2024 From: pluknet at nginx.com (=?iso-8859-1?q?Sergey_Kandaurov?=) Date: Mon, 27 May 2024 14:21:43 +0400 Subject: [PATCH 1 of 2] Rewritten host header validation to follow generic parsing rules Message-ID: # HG changeset patch # User Sergey Kandaurov # Date 1716805272 -14400 # Mon May 27 14:21:12 2024 +0400 # Node ID e82a7318ed48fdbc1273771bc96357e9dc232975 # Parent f58b6f6362387eeace46043a6fc0bceb56a6786a Rewritten host header validation to follow generic parsing rules. It now uses a generic model of state-based machine, with more strict parsing rules borrowed from ngx_http_validate_host(), with additional checks for double dots and stripping a port subcomponent. Notably, now a port subcomponent of the Host header is restricted to digits, using underscores in domain name labels is prohibited. diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2148,9 +2148,11 @@ ngx_http_validate_host(ngx_str_t *host, size_t i, dot_pos, host_len; enum { - sw_usual = 0, - sw_literal, - sw_rest + sw_host_start = 0, + sw_host, + sw_host_end, + sw_host_ip_literal, + sw_port, } state; dot_pos = host->len; @@ -2158,55 +2160,122 @@ ngx_http_validate_host(ngx_str_t *host, h = host->data; - state = sw_usual; + state = sw_host_start; for (i = 0; i < host->len; i++) { ch = h[i]; - switch (ch) { - - case '.': - if (dot_pos == i - 1) { - return NGX_DECLINED; + switch (state) { + + case sw_host_start: + + if (ch == '[') { + state = sw_host_ip_literal; + break; + } + + state = sw_host; + + /* fall through */ + + case sw_host: + + if (ch >= 'A' && ch <= 'Z') { + alloc = 1; + break; + } + + if (ch >= 'a' && ch <= 'z') { + break; } - dot_pos = i; - break; - - case ':': - if (state == sw_usual) { + + if ((ch >= '0' && ch <= '9') || ch == '-') { + break; + } + + if (ch == '.') { + if (dot_pos == i - 1) { + return NGX_DECLINED; + } + + dot_pos = i; + break; + } + + /* fall through */ + + case sw_host_end: + + switch (ch) { + case ':': host_len = i; - state = sw_rest; + state = sw_port; + break; + default: + return NGX_DECLINED; } break; - case '[': - if (i == 0) { - state = sw_literal; - } - break; - - case ']': - if (state == sw_literal) { - host_len = i + 1; - state = sw_rest; - } - break; - - default: - - if (ngx_path_separator(ch)) { - return NGX_DECLINED; - } - - if (ch <= 0x20 || ch == 0x7f) { - return NGX_DECLINED; - } + case sw_host_ip_literal: if (ch >= 'A' && ch <= 'Z') { alloc = 1; + break; } + if (ch >= 'a' && ch <= 'z') { + break; + } + + if (ch >= '0' && ch <= '9') { + break; + } + + if (ch == '.') { + if (dot_pos == i - 1) { + return NGX_DECLINED; + } + + dot_pos = i; + break; + } + + switch (ch) { + case ':': + break; + case ']': + host_len = i + 1; + state = sw_host_end; + break; + case '-': + case '_': + case '~': + /* unreserved */ + break; + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + /* sub-delims */ + break; + default: + return NGX_DECLINED; + } break; + + case sw_port: + if (ch >= '0' && ch <= '9') { + break; + } + + return NGX_DECLINED; } } diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -471,9 +471,11 @@ ngx_stream_validate_host(ngx_str_t *host size_t i, dot_pos, host_len; enum { - sw_usual = 0, - sw_literal, - sw_rest + sw_host_start = 0, + sw_host, + sw_host_end, + sw_host_ip_literal, + sw_port, } state; dot_pos = host->len; @@ -481,55 +483,122 @@ ngx_stream_validate_host(ngx_str_t *host h = host->data; - state = sw_usual; + state = sw_host_start; for (i = 0; i < host->len; i++) { ch = h[i]; - switch (ch) { + switch (state) { + + case sw_host_start: + + if (ch == '[') { + state = sw_host_ip_literal; + break; + } + + state = sw_host; - case '.': - if (dot_pos == i - 1) { - return NGX_DECLINED; + /* fall through */ + + case sw_host: + + if (ch >= 'A' && ch <= 'Z') { + alloc = 1; + break; } - dot_pos = i; - break; + + if (ch >= 'a' && ch <= 'z') { + break; + } - case ':': - if (state == sw_usual) { - host_len = i; - state = sw_rest; + if ((ch >= '0' && ch <= '9') || ch == '-') { + break; + } + + if (ch == '.') { + if (dot_pos == i - 1) { + return NGX_DECLINED; + } + + dot_pos = i; + break; } - break; + + /* fall through */ + + case sw_host_end: - case '[': - if (i == 0) { - state = sw_literal; + switch (ch) { + case ':': + host_len = i; + state = sw_port; + break; + default: + return NGX_DECLINED; } break; - case ']': - if (state == sw_literal) { + case sw_host_ip_literal: + + if (ch >= 'A' && ch <= 'Z') { + alloc = 1; + break; + } + + if (ch >= 'a' && ch <= 'z') { + break; + } + + if (ch >= '0' && ch <= '9') { + break; + } + + if (ch == '.') { + if (dot_pos == i - 1) { + return NGX_DECLINED; + } + + dot_pos = i; + break; + } + + switch (ch) { + case ':': + break; + case ']': host_len = i + 1; - state = sw_rest; + state = sw_host_end; + break; + case '-': + case '_': + case '~': + /* unreserved */ + break; + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + /* sub-delims */ + break; + default: + return NGX_DECLINED; } break; - default: - - if (ngx_path_separator(ch)) { - return NGX_DECLINED; + case sw_port: + if (ch >= '0' && ch <= '9') { + break; } - if (ch <= 0x20 || ch == 0x7f) { - return NGX_DECLINED; - } - - if (ch >= 'A' && ch <= 'Z') { - alloc = 1; - } - - break; + return NGX_DECLINED; } } From pluknet at nginx.com Mon May 27 10:21:44 2024 From: pluknet at nginx.com (=?iso-8859-1?q?Sergey_Kandaurov?=) Date: Mon, 27 May 2024 14:21:44 +0400 Subject: [PATCH 2 of 2] Stream: do not reallocate a parsed SNI host In-Reply-To: References: Message-ID: <88fa18a0f05f7dead38a.1716805304@enoparse.local> # HG changeset patch # User Sergey Kandaurov # Date 1716805288 -14400 # Mon May 27 14:21:28 2024 +0400 # Node ID 88fa18a0f05f7dead38a127bb24e5cf861f3d66d # Parent e82a7318ed48fdbc1273771bc96357e9dc232975 Stream: do not reallocate a parsed SNI host. Unlike in http SNI callback, it doesn't need to be saved here. diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -501,7 +501,7 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t host.data = (u_char *) servername; - rc = ngx_stream_validate_host(&host, c->pool, 1); + rc = ngx_stream_validate_host(&host, c->pool, 0); if (rc == NGX_ERROR) { goto error; diff --git a/src/stream/ngx_stream_ssl_preread_module.c b/src/stream/ngx_stream_ssl_preread_module.c --- a/src/stream/ngx_stream_ssl_preread_module.c +++ b/src/stream/ngx_stream_ssl_preread_module.c @@ -519,7 +519,7 @@ ngx_stream_ssl_preread_servername(ngx_st host = *servername; - rc = ngx_stream_validate_host(&host, c->pool, 1); + rc = ngx_stream_validate_host(&host, c->pool, 0); if (rc == NGX_ERROR) { return NGX_ERROR; From pluknet at nginx.com Mon May 27 13:04:30 2024 From: pluknet at nginx.com (Sergey Kandaurov) Date: Mon, 27 May 2024 17:04:30 +0400 Subject: I think I found a fix for the memory leak issue on gRPC module In-Reply-To: <20240527100658.nvgq5ebpk4xnvutd@N00W24XTQX> References: <20240522141426.ahzeenwq2qom3m4f@N00W24XTQX> <20240523094224.6n4ihcqrgsl54nxk@N00W24XTQX> <20240527100658.nvgq5ebpk4xnvutd@N00W24XTQX> Message-ID: On Mon, May 27, 2024 at 02:06:58PM +0400, Roman Arutyunyan wrote: > Hi, > # HG changeset patch > # User Roman Arutyunyan > # Date 1716477338 -14400 > # Thu May 23 19:15:38 2024 +0400 > # Node ID f7d53c7f70140b1cd1eaf51ce4346a873692f879 > # Parent f58b6f6362387eeace46043a6fc0bceb56a6786a > Optimized chain link usage (ticket #2614). > > Previously chain links could sometimes be dropped instead of being reused, > which could result in increased memory consumption during long requests. > > A similar chain link issue in ngx_http_gzip_filter_module was fixed in > da46bfc484ef (1.11.10). > > Based on a patch by Sangmin Lee. > > diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c > --- a/src/core/ngx_output_chain.c > +++ b/src/core/ngx_output_chain.c > @@ -117,7 +117,10 @@ ngx_output_chain(ngx_output_chain_ctx_t > > ngx_debug_point(); > > - ctx->in = ctx->in->next; > + cl = ctx->in; > + ctx->in = cl->next; > + > + ngx_free_chain(ctx->pool, cl); > > continue; > } > @@ -203,7 +206,10 @@ ngx_output_chain(ngx_output_chain_ctx_t > /* delete the completed buf from the ctx->in chain */ > > if (ngx_buf_size(ctx->in->buf) == 0) { > - ctx->in = ctx->in->next; > + cl = ctx->in; > + ctx->in = cl->next; > + > + ngx_free_chain(ctx->pool, cl); > } > > cl = ngx_alloc_chain_link(ctx->pool); > diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c > --- a/src/http/modules/ngx_http_grpc_module.c > +++ b/src/http/modules/ngx_http_grpc_module.c > @@ -1231,7 +1231,7 @@ ngx_http_grpc_body_output_filter(void *d > ngx_buf_t *b; > ngx_int_t rc; > ngx_uint_t next, last; > - ngx_chain_t *cl, *out, **ll; > + ngx_chain_t *cl, *out, *ln, **ll; > ngx_http_upstream_t *u; > ngx_http_grpc_ctx_t *ctx; > ngx_http_grpc_frame_t *f; > @@ -1459,7 +1459,10 @@ ngx_http_grpc_body_output_filter(void *d > last = 1; > } > > + ln = in; > in = in->next; > + > + ngx_free_chain(r->pool, ln); > } Looks good now. > > ctx->in = in; > diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c > --- a/src/http/modules/ngx_http_gunzip_filter_module.c > +++ b/src/http/modules/ngx_http_gunzip_filter_module.c > @@ -333,6 +333,8 @@ static ngx_int_t > ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, > ngx_http_gunzip_ctx_t *ctx) > { > + ngx_chain_t *cl; > + > if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { > return NGX_OK; > } > @@ -344,8 +346,11 @@ ngx_http_gunzip_filter_add_data(ngx_http > return NGX_DECLINED; > } > > - ctx->in_buf = ctx->in->buf; > - ctx->in = ctx->in->next; > + cl = ctx->in; > + ctx->in_buf = cl->buf; > + ctx->in = cl->next; > + > + ngx_free_chain(r->pool, cl); > > ctx->zstream.next_in = ctx->in_buf->pos; > ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; > @@ -374,6 +379,7 @@ static ngx_int_t > ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, > ngx_http_gunzip_ctx_t *ctx) > { > + ngx_chain_t *cl; > ngx_http_gunzip_conf_t *conf; > > if (ctx->zstream.avail_out) { > @@ -383,8 +389,12 @@ ngx_http_gunzip_filter_get_buf(ngx_http_ > conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); > > if (ctx->free) { > - ctx->out_buf = ctx->free->buf; > - ctx->free = ctx->free->next; > + > + cl = ctx->free; > + ctx->out_buf = cl->buf; > + ctx->free = cl->next; > + > + ngx_free_chain(r->pool, cl); > > ctx->out_buf->flush = 0; > > diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c > --- a/src/http/modules/ngx_http_gzip_filter_module.c > +++ b/src/http/modules/ngx_http_gzip_filter_module.c > @@ -985,10 +985,14 @@ static void > ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, > ngx_http_gzip_ctx_t *ctx) > { > - ngx_chain_t *cl; > + ngx_chain_t *cl, *ln; > > - for (cl = ctx->copied; cl; cl = cl->next) { > - ngx_pfree(r->pool, cl->buf->start); > + for (cl = ctx->copied; cl; /* void */) { > + ln = cl; > + cl = cl->next; > + > + ngx_pfree(r->pool, ln->buf->start); > + ngx_free_chain(r->pool, ln); > } > > ctx->copied = NULL; > diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c > --- a/src/http/modules/ngx_http_ssi_filter_module.c > +++ b/src/http/modules/ngx_http_ssi_filter_module.c > @@ -482,9 +482,13 @@ ngx_http_ssi_body_filter(ngx_http_reques > while (ctx->in || ctx->buf) { > > if (ctx->buf == NULL) { > - ctx->buf = ctx->in->buf; > - ctx->in = ctx->in->next; > + > + cl = ctx->in; > + ctx->buf = cl->buf; > + ctx->in = cl->next; > ctx->pos = ctx->buf->pos; > + > + ngx_free_chain(r->pool, cl); > } > > if (ctx->state == ssi_start_state) { > diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c > --- a/src/http/modules/ngx_http_sub_filter_module.c > +++ b/src/http/modules/ngx_http_sub_filter_module.c > @@ -335,9 +335,13 @@ ngx_http_sub_body_filter(ngx_http_reques > while (ctx->in || ctx->buf) { > > if (ctx->buf == NULL) { > - ctx->buf = ctx->in->buf; > - ctx->in = ctx->in->next; > + > + cl = ctx->in; > + ctx->buf = cl->buf; > + ctx->in = cl->next; > ctx->pos = ctx->buf->pos; > + > + ngx_free_chain(r->pool, cl); > } > > if (ctx->buf->flush || ctx->buf->recycled) { From arut at nginx.com Mon May 27 13:54:15 2024 From: arut at nginx.com (=?utf-8?q?Roman_Arutyunyan?=) Date: Mon, 27 May 2024 13:54:15 +0000 Subject: [nginx] Optimized chain link usage (ticket #2614). Message-ID: details: https://hg.nginx.org/nginx/rev/f7d53c7f7014 branches: changeset: 9248:f7d53c7f7014 user: Roman Arutyunyan date: Thu May 23 19:15:38 2024 +0400 description: Optimized chain link usage (ticket #2614). Previously chain links could sometimes be dropped instead of being reused, which could result in increased memory consumption during long requests. A similar chain link issue in ngx_http_gzip_filter_module was fixed in da46bfc484ef (1.11.10). Based on a patch by Sangmin Lee. diffstat: src/core/ngx_output_chain.c | 10 ++++++++-- src/http/modules/ngx_http_grpc_module.c | 5 ++++- src/http/modules/ngx_http_gunzip_filter_module.c | 18 ++++++++++++++---- src/http/modules/ngx_http_gzip_filter_module.c | 10 +++++++--- src/http/modules/ngx_http_ssi_filter_module.c | 8 ++++++-- src/http/modules/ngx_http_sub_filter_module.c | 8 ++++++-- 6 files changed, 45 insertions(+), 14 deletions(-) diffs (158 lines): diff -r f58b6f636238 -r f7d53c7f7014 src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c Thu May 16 11:15:10 2024 +0200 +++ b/src/core/ngx_output_chain.c Thu May 23 19:15:38 2024 +0400 @@ -117,7 +117,10 @@ ngx_output_chain(ngx_output_chain_ctx_t ngx_debug_point(); - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in = cl->next; + + ngx_free_chain(ctx->pool, cl); continue; } @@ -203,7 +206,10 @@ ngx_output_chain(ngx_output_chain_ctx_t /* delete the completed buf from the ctx->in chain */ if (ngx_buf_size(ctx->in->buf) == 0) { - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in = cl->next; + + ngx_free_chain(ctx->pool, cl); } cl = ngx_alloc_chain_link(ctx->pool); diff -r f58b6f636238 -r f7d53c7f7014 src/http/modules/ngx_http_grpc_module.c --- a/src/http/modules/ngx_http_grpc_module.c Thu May 16 11:15:10 2024 +0200 +++ b/src/http/modules/ngx_http_grpc_module.c Thu May 23 19:15:38 2024 +0400 @@ -1231,7 +1231,7 @@ ngx_http_grpc_body_output_filter(void *d ngx_buf_t *b; ngx_int_t rc; ngx_uint_t next, last; - ngx_chain_t *cl, *out, **ll; + ngx_chain_t *cl, *out, *ln, **ll; ngx_http_upstream_t *u; ngx_http_grpc_ctx_t *ctx; ngx_http_grpc_frame_t *f; @@ -1459,7 +1459,10 @@ ngx_http_grpc_body_output_filter(void *d last = 1; } + ln = in; in = in->next; + + ngx_free_chain(r->pool, ln); } ctx->in = in; diff -r f58b6f636238 -r f7d53c7f7014 src/http/modules/ngx_http_gunzip_filter_module.c --- a/src/http/modules/ngx_http_gunzip_filter_module.c Thu May 16 11:15:10 2024 +0200 +++ b/src/http/modules/ngx_http_gunzip_filter_module.c Thu May 23 19:15:38 2024 +0400 @@ -333,6 +333,8 @@ static ngx_int_t ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, ngx_http_gunzip_ctx_t *ctx) { + ngx_chain_t *cl; + if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { return NGX_OK; } @@ -344,8 +346,11 @@ ngx_http_gunzip_filter_add_data(ngx_http return NGX_DECLINED; } - ctx->in_buf = ctx->in->buf; - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in_buf = cl->buf; + ctx->in = cl->next; + + ngx_free_chain(r->pool, cl); ctx->zstream.next_in = ctx->in_buf->pos; ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; @@ -374,6 +379,7 @@ static ngx_int_t ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, ngx_http_gunzip_ctx_t *ctx) { + ngx_chain_t *cl; ngx_http_gunzip_conf_t *conf; if (ctx->zstream.avail_out) { @@ -383,8 +389,12 @@ ngx_http_gunzip_filter_get_buf(ngx_http_ conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); if (ctx->free) { - ctx->out_buf = ctx->free->buf; - ctx->free = ctx->free->next; + + cl = ctx->free; + ctx->out_buf = cl->buf; + ctx->free = cl->next; + + ngx_free_chain(r->pool, cl); ctx->out_buf->flush = 0; diff -r f58b6f636238 -r f7d53c7f7014 src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c Thu May 16 11:15:10 2024 +0200 +++ b/src/http/modules/ngx_http_gzip_filter_module.c Thu May 23 19:15:38 2024 +0400 @@ -985,10 +985,14 @@ static void ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { - ngx_chain_t *cl; + ngx_chain_t *cl, *ln; - for (cl = ctx->copied; cl; cl = cl->next) { - ngx_pfree(r->pool, cl->buf->start); + for (cl = ctx->copied; cl; /* void */) { + ln = cl; + cl = cl->next; + + ngx_pfree(r->pool, ln->buf->start); + ngx_free_chain(r->pool, ln); } ctx->copied = NULL; diff -r f58b6f636238 -r f7d53c7f7014 src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c Thu May 16 11:15:10 2024 +0200 +++ b/src/http/modules/ngx_http_ssi_filter_module.c Thu May 23 19:15:38 2024 +0400 @@ -482,9 +482,13 @@ ngx_http_ssi_body_filter(ngx_http_reques while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { - ctx->buf = ctx->in->buf; - ctx->in = ctx->in->next; + + cl = ctx->in; + ctx->buf = cl->buf; + ctx->in = cl->next; ctx->pos = ctx->buf->pos; + + ngx_free_chain(r->pool, cl); } if (ctx->state == ssi_start_state) { diff -r f58b6f636238 -r f7d53c7f7014 src/http/modules/ngx_http_sub_filter_module.c --- a/src/http/modules/ngx_http_sub_filter_module.c Thu May 16 11:15:10 2024 +0200 +++ b/src/http/modules/ngx_http_sub_filter_module.c Thu May 23 19:15:38 2024 +0400 @@ -335,9 +335,13 @@ ngx_http_sub_body_filter(ngx_http_reques while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { - ctx->buf = ctx->in->buf; - ctx->in = ctx->in->next; + + cl = ctx->in; + ctx->buf = cl->buf; + ctx->in = cl->next; ctx->pos = ctx->buf->pos; + + ngx_free_chain(r->pool, cl); } if (ctx->buf->flush || ctx->buf->recycled) { From arut at nginx.com Mon May 27 15:16:47 2024 From: arut at nginx.com (Roman Arutyunyan) Date: Mon, 27 May 2024 19:16:47 +0400 Subject: [PATCH] Proxy: altered limit_rate to support variables In-Reply-To: <59ACCD59-ABEA-49AB-95EE-5A2B4EE30F5C@nginx.com> References: <59ACCD59-ABEA-49AB-95EE-5A2B4EE30F5C@nginx.com> Message-ID: <20240527151647.miswmw3zzk7qcazs@N00W24XTQX> Hi, On Tue, Dec 26, 2023 at 07:07:37PM +0400, Sergey Kandaurov wrote: > > > On 26 Nov 2023, at 03:37, J Carter wrote: > > > > # HG changeset patch > > # User J Carter > > # Date 1700949429 0 > > # Sat Nov 25 21:57:09 2023 +0000 > > # Node ID 98306e705015758eab0a05103d90e6bdb1da2819 > > # Parent f366007dd23a6ce8e8427c1b3042781b618a2ade > > Proxy: altered limit_rate to support variables > > Since it changes the upstream interface, I'd rather say: > > Upstream: variables support in proxy_limit_rate and friends. > > The change looks good to me, also it compliments variables support > in the stream proxy module's directives. > Any particular use-cases you'd like to share for this functionality? > > > > > diff -r f366007dd23a -r 98306e705015 src/http/modules/ngx_http_fastcgi_module.c > > --- a/src/http/modules/ngx_http_fastcgi_module.c Tue Nov 14 15:26:02 2023 +0400 > > +++ b/src/http/modules/ngx_http_fastcgi_module.c Sat Nov 25 21:57:09 2023 +0000 > > @@ -375,7 +375,7 @@ > > > > { ngx_string("fastcgi_limit_rate"), > > NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, > > - ngx_conf_set_size_slot, > > + ngx_http_set_complex_value_size_slot, > > NGX_HTTP_LOC_CONF_OFFSET, > > offsetof(ngx_http_fastcgi_loc_conf_t, upstream.limit_rate), > > NULL }, > > @@ -2898,7 +2898,7 @@ > > > > conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; > > conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; > > - conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; > > + conf->upstream.limit_rate = NGX_CONF_UNSET_PTR; > > > > conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; > > conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; > > @@ -3015,8 +3015,8 @@ > > prev->upstream.buffer_size, > > (size_t) ngx_pagesize); > > > > - ngx_conf_merge_size_value(conf->upstream.limit_rate, > > - prev->upstream.limit_rate, 0); > > + ngx_conf_merge_ptr_value(conf->upstream.limit_rate, > > + prev->upstream.limit_rate, NULL); > > > > > > ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, > > diff -r f366007dd23a -r 98306e705015 src/http/modules/ngx_http_proxy_module.c > > --- a/src/http/modules/ngx_http_proxy_module.c Tue Nov 14 15:26:02 2023 +0400 > > +++ b/src/http/modules/ngx_http_proxy_module.c Sat Nov 25 21:57:09 2023 +0000 > > @@ -494,7 +494,7 @@ > > > > { ngx_string("proxy_limit_rate"), > > NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, > > - ngx_conf_set_size_slot, > > + ngx_http_set_complex_value_size_slot, > > NGX_HTTP_LOC_CONF_OFFSET, > > offsetof(ngx_http_proxy_loc_conf_t, upstream.limit_rate), > > NULL }, > > @@ -3371,7 +3371,7 @@ > > > > conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; > > conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; > > - conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; > > + conf->upstream.limit_rate = NGX_CONF_UNSET_PTR; > > > > conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; > > conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; > > @@ -3515,8 +3515,8 @@ > > prev->upstream.buffer_size, > > (size_t) ngx_pagesize); > > > > - ngx_conf_merge_size_value(conf->upstream.limit_rate, > > - prev->upstream.limit_rate, 0); > > + ngx_conf_merge_ptr_value(conf->upstream.limit_rate, > > + prev->upstream.limit_rate, NULL); > > > > ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, > > 8, ngx_pagesize); > > diff -r f366007dd23a -r 98306e705015 src/http/modules/ngx_http_scgi_module.c > > --- a/src/http/modules/ngx_http_scgi_module.c Tue Nov 14 15:26:02 2023 +0400 > > +++ b/src/http/modules/ngx_http_scgi_module.c Sat Nov 25 21:57:09 2023 +0000 > > @@ -223,7 +223,7 @@ > > > > { ngx_string("scgi_limit_rate"), > > NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, > > - ngx_conf_set_size_slot, > > + ngx_http_set_complex_value_size_slot, > > NGX_HTTP_LOC_CONF_OFFSET, > > offsetof(ngx_http_scgi_loc_conf_t, upstream.limit_rate), > > NULL }, > > @@ -1301,7 +1301,7 @@ > > > > conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; > > conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; > > - conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; > > + conf->upstream.limit_rate = NGX_CONF_UNSET_PTR; > > > > conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; > > conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; > > @@ -1413,8 +1413,8 @@ > > prev->upstream.buffer_size, > > (size_t) ngx_pagesize); > > > > - ngx_conf_merge_size_value(conf->upstream.limit_rate, > > - prev->upstream.limit_rate, 0); > > + ngx_conf_merge_ptr_value(conf->upstream.limit_rate, > > + prev->upstream.limit_rate, NULL); > > > > > > ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, > > diff -r f366007dd23a -r 98306e705015 src/http/modules/ngx_http_uwsgi_module.c > > --- a/src/http/modules/ngx_http_uwsgi_module.c Tue Nov 14 15:26:02 2023 +0400 > > +++ b/src/http/modules/ngx_http_uwsgi_module.c Sat Nov 25 21:57:09 2023 +0000 > > @@ -289,7 +289,7 @@ > > > > { ngx_string("uwsgi_limit_rate"), > > NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, > > - ngx_conf_set_size_slot, > > + ngx_http_set_complex_value_size_slot, > > NGX_HTTP_LOC_CONF_OFFSET, > > offsetof(ngx_http_uwsgi_loc_conf_t, upstream.limit_rate), > > NULL }, > > @@ -1532,7 +1532,7 @@ > > > > conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; > > conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; > > - conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; > > + conf->upstream.limit_rate = NGX_CONF_UNSET_PTR; > > > > conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; > > conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; > > @@ -1656,8 +1656,8 @@ > > prev->upstream.buffer_size, > > (size_t) ngx_pagesize); > > > > - ngx_conf_merge_size_value(conf->upstream.limit_rate, > > - prev->upstream.limit_rate, 0); > > + ngx_conf_merge_ptr_value(conf->upstream.limit_rate, > > + prev->upstream.limit_rate, NULL); > > > > > > ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, > > diff -r f366007dd23a -r 98306e705015 src/http/ngx_http_upstream.c > > --- a/src/http/ngx_http_upstream.c Tue Nov 14 15:26:02 2023 +0400 > > +++ b/src/http/ngx_http_upstream.c Sat Nov 25 21:57:09 2023 +0000 > > @@ -3236,7 +3236,7 @@ > > p->downstream = c; > > p->pool = r->pool; > > p->log = c->log; > > - p->limit_rate = u->conf->limit_rate; > > + p->limit_rate = ngx_http_complex_value_size(r, u->conf->limit_rate, 0); > > p->start_sec = ngx_time(); > > > > p->cacheable = u->cacheable || u->store; > > diff -r f366007dd23a -r 98306e705015 src/http/ngx_http_upstream.h > > --- a/src/http/ngx_http_upstream.h Tue Nov 14 15:26:02 2023 +0400 > > +++ b/src/http/ngx_http_upstream.h Sat Nov 25 21:57:09 2023 +0000 > > @@ -156,7 +156,7 @@ > > > > size_t send_lowat; > > size_t buffer_size; > > - size_t limit_rate; > > + ngx_http_complex_value_t *limit_rate; > > > > size_t busy_buffers_size; > > size_t max_temp_file_size; Patch looks good to me as well. -- Roman Arutyunyan From pluknet at nginx.com Mon May 27 15:19:01 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Mon, 27 May 2024 15:19:01 +0000 Subject: [nginx] Upstream: variables support in proxy_limit_rate and friends. Message-ID: details: https://hg.nginx.org/nginx/rev/2e9588d65dd9 branches: changeset: 9249:2e9588d65dd9 user: J Carter date: Sat Nov 25 21:57:09 2023 +0000 description: Upstream: variables support in proxy_limit_rate and friends. diffstat: src/http/modules/ngx_http_fastcgi_module.c | 8 ++++---- src/http/modules/ngx_http_proxy_module.c | 8 ++++---- src/http/modules/ngx_http_scgi_module.c | 8 ++++---- src/http/modules/ngx_http_uwsgi_module.c | 8 ++++---- src/http/ngx_http_upstream.c | 2 +- src/http/ngx_http_upstream.h | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diffs (152 lines): diff -r f7d53c7f7014 -r 2e9588d65dd9 src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c Thu May 23 19:15:38 2024 +0400 +++ b/src/http/modules/ngx_http_fastcgi_module.c Sat Nov 25 21:57:09 2023 +0000 @@ -375,7 +375,7 @@ static ngx_command_t ngx_http_fastcgi_c { ngx_string("fastcgi_limit_rate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, + ngx_http_set_complex_value_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_fastcgi_loc_conf_t, upstream.limit_rate), NULL }, @@ -2898,7 +2898,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_con conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; - conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; + conf->upstream.limit_rate = NGX_CONF_UNSET_PTR; conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; @@ -3015,8 +3015,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf prev->upstream.buffer_size, (size_t) ngx_pagesize); - ngx_conf_merge_size_value(conf->upstream.limit_rate, - prev->upstream.limit_rate, 0); + ngx_conf_merge_ptr_value(conf->upstream.limit_rate, + prev->upstream.limit_rate, NULL); ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, diff -r f7d53c7f7014 -r 2e9588d65dd9 src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c Thu May 23 19:15:38 2024 +0400 +++ b/src/http/modules/ngx_http_proxy_module.c Sat Nov 25 21:57:09 2023 +0000 @@ -494,7 +494,7 @@ static ngx_command_t ngx_http_proxy_com { ngx_string("proxy_limit_rate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, + ngx_http_set_complex_value_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_proxy_loc_conf_t, upstream.limit_rate), NULL }, @@ -3371,7 +3371,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; - conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; + conf->upstream.limit_rate = NGX_CONF_UNSET_PTR; conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; @@ -3515,8 +3515,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t prev->upstream.buffer_size, (size_t) ngx_pagesize); - ngx_conf_merge_size_value(conf->upstream.limit_rate, - prev->upstream.limit_rate, 0); + ngx_conf_merge_ptr_value(conf->upstream.limit_rate, + prev->upstream.limit_rate, NULL); ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, 8, ngx_pagesize); diff -r f7d53c7f7014 -r 2e9588d65dd9 src/http/modules/ngx_http_scgi_module.c --- a/src/http/modules/ngx_http_scgi_module.c Thu May 23 19:15:38 2024 +0400 +++ b/src/http/modules/ngx_http_scgi_module.c Sat Nov 25 21:57:09 2023 +0000 @@ -223,7 +223,7 @@ static ngx_command_t ngx_http_scgi_comma { ngx_string("scgi_limit_rate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, + ngx_http_set_complex_value_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_scgi_loc_conf_t, upstream.limit_rate), NULL }, @@ -1301,7 +1301,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; - conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; + conf->upstream.limit_rate = NGX_CONF_UNSET_PTR; conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; @@ -1413,8 +1413,8 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t prev->upstream.buffer_size, (size_t) ngx_pagesize); - ngx_conf_merge_size_value(conf->upstream.limit_rate, - prev->upstream.limit_rate, 0); + ngx_conf_merge_ptr_value(conf->upstream.limit_rate, + prev->upstream.limit_rate, NULL); ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, diff -r f7d53c7f7014 -r 2e9588d65dd9 src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c Thu May 23 19:15:38 2024 +0400 +++ b/src/http/modules/ngx_http_uwsgi_module.c Sat Nov 25 21:57:09 2023 +0000 @@ -289,7 +289,7 @@ static ngx_command_t ngx_http_uwsgi_comm { ngx_string("uwsgi_limit_rate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, + ngx_http_set_complex_value_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_uwsgi_loc_conf_t, upstream.limit_rate), NULL }, @@ -1532,7 +1532,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_ conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; - conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; + conf->upstream.limit_rate = NGX_CONF_UNSET_PTR; conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; @@ -1656,8 +1656,8 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t prev->upstream.buffer_size, (size_t) ngx_pagesize); - ngx_conf_merge_size_value(conf->upstream.limit_rate, - prev->upstream.limit_rate, 0); + ngx_conf_merge_ptr_value(conf->upstream.limit_rate, + prev->upstream.limit_rate, NULL); ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, diff -r f7d53c7f7014 -r 2e9588d65dd9 src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c Thu May 23 19:15:38 2024 +0400 +++ b/src/http/ngx_http_upstream.c Sat Nov 25 21:57:09 2023 +0000 @@ -3236,7 +3236,7 @@ ngx_http_upstream_send_response(ngx_http p->downstream = c; p->pool = r->pool; p->log = c->log; - p->limit_rate = u->conf->limit_rate; + p->limit_rate = ngx_http_complex_value_size(r, u->conf->limit_rate, 0); p->start_sec = ngx_time(); p->cacheable = u->cacheable || u->store; diff -r f7d53c7f7014 -r 2e9588d65dd9 src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h Thu May 23 19:15:38 2024 +0400 +++ b/src/http/ngx_http_upstream.h Sat Nov 25 21:57:09 2023 +0000 @@ -156,7 +156,7 @@ typedef struct { size_t send_lowat; size_t buffer_size; - size_t limit_rate; + ngx_http_complex_value_t *limit_rate; size_t busy_buffers_size; size_t max_temp_file_size; From jordanc.carter at outlook.com Tue May 28 11:53:46 2024 From: jordanc.carter at outlook.com (J Carter) Date: Tue, 28 May 2024 12:53:46 +0100 Subject: [PATCH 1 of 2] Rewritten host header validation to follow generic parsing rules In-Reply-To: References: Message-ID: Hello Sergey, On Mon, 27 May 2024 14:21:43 +0400 Sergey Kandaurov wrote: > # HG changeset patch > # User Sergey Kandaurov > # Date 1716805272 -14400 > # Mon May 27 14:21:12 2024 +0400 > # Node ID e82a7318ed48fdbc1273771bc96357e9dc232975 > # Parent f58b6f6362387eeace46043a6fc0bceb56a6786a > Rewritten host header validation to follow generic parsing rules. > > It now uses a generic model of state-based machine, with more strict > parsing rules borrowed from ngx_http_validate_host(), I think you mean "borrowed from ngx_http_parse_request_line()". > with additional > checks for double dots and stripping a port subcomponent. > > Notably, now a port subcomponent of the Host header is restricted > to digits, using underscores in domain name labels is prohibited. > [...] From noreply at nginx.com Tue May 28 22:00:03 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Tue, 28 May 2024 22:00:03 +0000 Subject: [njs] Test262: improved skipping of tests. Message-ID: details: https://hg.nginx.org/njs/rev/881a1c4cd2fb branches: changeset: 2340:881a1c4cd2fb user: Dmitry Volyntsev date: Tue May 28 14:16:14 2024 -0700 description: Test262: improved skipping of tests. The skipped tests (which are expected to fail) are not executed in order to make output clearer. diffstat: test/test262 | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diffs (27 lines): diff -r f75f670905f0 -r 881a1c4cd2fb test/test262 --- a/test/test262 Thu May 23 22:50:34 2024 -0700 +++ b/test/test262 Tue May 28 14:16:14 2024 -0700 @@ -19,6 +19,11 @@ for njs_test in $NJS_TESTS; do running $njs_test $njs_log END + if [ "$NJS_SKIP_LIST" != "${NJS_SKIP_LIST#*$njs_test*}" ]; then + skip $njs_test + continue + fi + status=0 NJS_PATH=$njs_paths \ @@ -28,11 +33,6 @@ END cat $njs_log >> $NJS_TEST_LOG njs_out=`cat $njs_log` - if [ "$NJS_SKIP_LIST" != "${NJS_SKIP_LIST#*$njs_test*}" ]; then - skip $njs_test - continue - fi - if [ "$status" -eq 0 ]; then if [ -n "$njs_negative" ]; then failed $njs_test $njs_log From noreply at nginx.com Tue May 28 23:45:38 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Tue, 28 May 2024 23:45:38 +0000 Subject: [njs] Added CI based on GitHub Actions. Message-ID: details: https://hg.nginx.org/njs/rev/29ffafd582a7 branches: changeset: 2341:29ffafd582a7 user: Konstantin Pavlov date: Fri Apr 05 13:27:37 2024 -0700 description: Added CI based on GitHub Actions. diffstat: .github/workflows/check-pr.yml | 86 ++++++++++++++++++++++++++++++++++++++++++ .github/workflows/ci.yml | 11 +++++ 2 files changed, 97 insertions(+), 0 deletions(-) diffs (105 lines): diff -r 881a1c4cd2fb -r 29ffafd582a7 .github/workflows/check-pr.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.github/workflows/check-pr.yml Fri Apr 05 13:27:37 2024 -0700 @@ -0,0 +1,86 @@ +name: check-pr + +on: + pull_request: + +jobs: + build: + runs-on: [ ubuntu-latest ] + steps: + - name: checkout v4 + uses: actions/checkout at b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Set the defaults and set up environment + run: | + echo NGINX_CONFIGURE_CMD="auto/configure --prefix=/tmp --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-mail --with-mail_ssl_module --with-select_module --with-poll_module --with-http_auth_request_module --with-http_v2_module --with-http_slice_module --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-stream_realip_module --with-threads --with-cpp_test_module --with-compat --with-http_degradation_module --with-http_xslt_module --with-http_image_filter_module --with-http_perl_module --with-http_geoip_module --with-stream_geoip_module" >> $GITHUB_ENV + export DEB_BUILD_MAINT_OPTIONS="hardening=+all" + export DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" + export DEB_LDFLAGS_MAINT_APPEND=""-Wl,--as-needed"" + echo CC_OPT=$(dpkg-buildflags --get CFLAGS) >> $GITHUB_ENV + echo LD_OPT=$(dpkg-buildflags --get LDFLAGS) >> $GITHUB_ENV + echo MAKE_UTILITY=make >> $GITHUB_ENV + + - name: Install build dependencies + run: | + sudo apt-get update + sudo apt-get install \ + libssl-dev zlib1g-dev libpcre2-dev libxslt1-dev libgeoip-dev \ + libgd-dev libxml2-dev libedit-dev libperl-dev libtest-harness-perl \ + libgd-perl libgeoip-dev expect + + - name: Check out nginx + run: | + git clone https://github.com/nginx/nginx nginx-source + + - name: Check out nginx tests + run: | + git clone https://github.com/nginx/nginx-tests + + - name: Check out and build quickjs + run: | + git clone https://github.com/bellard/quickjs + cd quickjs && curl -OL http://pp.nginx.com/pluknet/quickjs.patch && git apply quickjs.patch + CFLAGS=$CC_OPT LDFLAGS=$LD_OPT $MAKE_UTILITY -j$(nproc) libquickjs.a + + - name: Configure and make njs + run: | + ./configure \ + --cc-opt="$CC_OPT" \ + --ld-opt="$LD_OPT" \ + || cat build/autoconf.err + $MAKE_UTILITY -j$(nproc) + + - name: Test njs + run: | + $MAKE_UTILITY test + $MAKE_UTILITY clean + + - name: Configure and make njs with quickjs + run: | + ./configure \ + --with-quickjs \ + --cc-opt="$CC_OPT -Iquickjs" \ + --ld-opt="$LD_OPT -Lquickjs" \ + || cat build/autoconf.err + $MAKE_UTILITY -j$(nproc) + + - name: Test njs with quickjs + run: | + $MAKE_UTILITY test + $MAKE_UTILITY clean + + - name: Configure and build nginx and njs modules + run: | + cd nginx-source + $NGINX_CONFIGURE_CMD --with-cc-opt="$CC_OPT" --with-ld-opt="$LD_OPT" --add-dynamic-module=../nginx || cat objs/autoconf.err + $MAKE_UTILITY -j$(nproc) modules + $MAKE_UTILITY -j$(nproc) + + - name: Test njs 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 diff -r 881a1c4cd2fb -r 29ffafd582a7 .github/workflows/ci.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.github/workflows/ci.yml Fri Apr 05 13:27:37 2024 -0700 @@ -0,0 +1,11 @@ +name: CI + +on: + workflow_dispatch: + push: + branches: + - master + +jobs: + buildbot: + uses: nginx/ci-self-hosted/.github/workflows/njs-buildbot.yml at main From noreply at nginx.com Wed May 29 00:36:04 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Wed, 29 May 2024 00:36:04 +0000 Subject: [njs] Fixed RegExp.prototype[@@replace](). Message-ID: details: https://hg.nginx.org/njs/rev/cb1baa3906f8 branches: changeset: 2342:cb1baa3906f8 user: Dmitry Volyntsev date: Tue May 28 15:49:39 2024 -0700 description: Fixed RegExp.prototype[@@replace](). With replacement containing "$'", "$\`" and Unicode characters. The similar issue was fixed for String.prototype.replace() in 10127d70e941 (0.7.11). Found by OSS-Fuzz. diffstat: src/njs_regexp.c | 27 ++++++++++++--------------- src/test/njs_unit_test.c | 3 +++ 2 files changed, 15 insertions(+), 15 deletions(-) diffs (84 lines): diff -r 29ffafd582a7 -r cb1baa3906f8 src/njs_regexp.c --- a/src/njs_regexp.c Fri Apr 05 13:27:37 2024 -0700 +++ b/src/njs_regexp.c Tue May 28 15:49:39 2024 -0700 @@ -1330,7 +1330,8 @@ njs_int_t njs_regexp_prototype_symbol_replace(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { - int64_t n, last_index, ncaptures, pos, next_pos, length; + int64_t n, last_index, ncaptures, pos, length; + const u_char *p, *next; njs_str_t rep, m; njs_int_t ret; njs_arr_t results; @@ -1461,8 +1462,8 @@ njs_regexp_prototype_symbol_replace(njs_ } i = 0; - pos = 0; - next_pos = 0; + p = s.start; + next = p; while (i < results.items) { r = njs_arr_item(&results, i++); @@ -1491,13 +1492,7 @@ njs_regexp_prototype_symbol_replace(njs_ goto exception; } - if ((size_t) length != s.size) { - /* UTF-8 string. */ - pos = njs_string_utf8_offset(s.start, s.start + s.size, pos) - - s.start; - } - - pos = njs_max(njs_min(pos, (int64_t) s.size), 0); + pos = njs_max(njs_min(pos, (int64_t) length), 0); ret = njs_object_length(vm, r, &ncaptures); if (njs_slow_path(ret != NJS_OK)) { @@ -1578,15 +1573,17 @@ njs_regexp_prototype_symbol_replace(njs_ goto exception; } - if (pos >= next_pos) { - njs_chb_append(&chain, &s.start[next_pos], pos - next_pos); + p = njs_string_offset(&s, pos); + + if (p >= next) { + njs_chb_append(&chain, next, p - next); njs_string_get(retval, &rep); njs_chb_append_str(&chain, &rep); njs_string_get(&matched, &m); - next_pos = pos + (int64_t) m.length; + next = p + m.length; } if (!func_replace && njs_object_slots(r)) { @@ -1599,8 +1596,8 @@ njs_regexp_prototype_symbol_replace(njs_ } } - if (next_pos < (int64_t) s.size) { - njs_chb_append(&chain, &s.start[next_pos], s.size - next_pos); + if (next < s.start + s.size) { + njs_chb_append(&chain, next, s.start + s.size - next); } ret = njs_string_create_chb(vm, retval, &chain); diff -r 29ffafd582a7 -r cb1baa3906f8 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Apr 05 13:27:37 2024 -0700 +++ b/src/test/njs_unit_test.c Tue May 28 15:49:39 2024 -0700 @@ -9321,6 +9321,9 @@ static njs_unit_test_t njs_test[] = { njs_str("'ABCB'.replaceAll(/(?B)/g, '|$@')"), njs_str("A|@C|@") }, + { njs_str("'α'.repeat(8).replace(/()/g, '$`') == 'α'.repeat(44)"), + njs_str("true") }, + { njs_str("('β' + 'α'.repeat(33)+'β').replace(/(α+)(β+)/, (m, p1) => p1[32])"), njs_str("βα") }, From noreply at nginx.com Wed May 29 01:49:04 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Wed, 29 May 2024 01:49:04 +0000 Subject: [njs] Added code of conduct. Message-ID: details: https://hg.nginx.org/njs/rev/773c816a7360 branches: changeset: 2343:773c816a7360 user: Dmitry Volyntsev date: Tue May 28 18:00:10 2024 -0700 description: Added code of conduct. diffstat: CODE_OF_CONDUCT.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 79 insertions(+), 0 deletions(-) diffs (83 lines): diff -r cb1baa3906f8 -r 773c816a7360 CODE_OF_CONDUCT.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CODE_OF_CONDUCT.md Tue May 28 18:00:10 2024 -0700 @@ -0,0 +1,79 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of + any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at . All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1, available at . + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/inclusion). + +For answers to common questions about this code of conduct, see the FAQ at . Translations are available at . From pluknet at nginx.com Wed May 29 14:57:42 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:57:42 +0000 Subject: [nginx] QUIC: client transport parameter data length checking. Message-ID: details: https://hg.nginx.org/nginx/rev/371b6a7d0673 branches: changeset: 9250:371b6a7d0673 user: Sergey Kandaurov date: Tue May 28 17:17:19 2024 +0400 description: QUIC: client transport parameter data length checking. diffstat: src/event/quic/ngx_event_quic_transport.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diffs (18 lines): diff -r 2e9588d65dd9 -r 371b6a7d0673 src/event/quic/ngx_event_quic_transport.c --- a/src/event/quic/ngx_event_quic_transport.c Sat Nov 25 21:57:09 2023 +0000 +++ b/src/event/quic/ngx_event_quic_transport.c Tue May 28 17:17:19 2024 +0400 @@ -1750,6 +1750,14 @@ ngx_quic_parse_transport_params(u_char * return NGX_ERROR; } + if ((size_t) (end - p) < len) { + ngx_log_error(NGX_LOG_INFO, log, 0, + "quic failed to parse" + " transport param id:0x%xL, data length %uL too long", + id, len); + return NGX_ERROR; + } + rc = ngx_quic_parse_transport_param(p, p + len, id, tp); if (rc == NGX_ERROR) { From pluknet at nginx.com Wed May 29 14:57:45 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:57:45 +0000 Subject: [nginx] HTTP/3: decoder stream pre-creation. Message-ID: details: https://hg.nginx.org/nginx/rev/387470a87c8a branches: changeset: 9251:387470a87c8a user: Roman Arutyunyan date: Tue May 28 17:18:28 2024 +0400 description: HTTP/3: decoder stream pre-creation. Previously a decoder stream was created on demand for sending Section Acknowledgement, Stream Cancellation and Insert Count Increment. If conditions for sending any of these instructions never happen, a decoder stream is not created at all. These conditions include client not using the dynamic table and no streams abandoned by server (RFC 9204, Section 2.2.2.2). However RFC 9204, Section 4.2 defines only one condition for not creating a decoder stream: An endpoint MAY avoid creating a decoder stream if its decoder sets the maximum capacity of the dynamic table to zero. The change enables pre-creation of the decoder stream at HTTP/3 session initialization if maximum dynamic table capacity is not zero. Note that this value is currently hardcoded to 4096 bytes and is not configurable, so the stream is now always created. Also, the change fixes a potential stack overflow when creating a decoder stream in ngx_http_v3_send_cancel_stream() while draining a request stream by ngx_drain_connections(). Creating a decoder stream involves calling ngx_get_connection(), which calls ngx_drain_connections(), which will drain the same request stream again. If client's MAX_STREAMS for uni stream is high enough, these recursive calls will continue until we run out of stack. Otherwise, decoder stream creation will fail at some point and the request stream connection will be drained. This may result in use-after-free, since this connection could still be referenced up the stack. diffstat: src/http/v3/ngx_http_v3_request.c | 20 ++++++++++++++------ src/http/v3/ngx_http_v3_uni.c | 4 +--- src/http/v3/ngx_http_v3_uni.h | 2 ++ 3 files changed, 17 insertions(+), 9 deletions(-) diffs (73 lines): diff -r 371b6a7d0673 -r 387470a87c8a src/http/v3/ngx_http_v3_request.c --- a/src/http/v3/ngx_http_v3_request.c Tue May 28 17:17:19 2024 +0400 +++ b/src/http/v3/ngx_http_v3_request.c Tue May 28 17:18:28 2024 +0400 @@ -134,7 +134,17 @@ ngx_http_v3_init(ngx_connection_t *c) } } - return ngx_http_v3_send_settings(c); + if (ngx_http_v3_send_settings(c) != NGX_OK) { + return NGX_ERROR; + } + + if (h3scf->max_table_capacity > 0) { + if (ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER) == NULL) { + return NGX_ERROR; + } + } + + return NGX_OK; } @@ -398,14 +408,12 @@ ngx_http_v3_wait_request_handler(ngx_eve void ngx_http_v3_reset_stream(ngx_connection_t *c) { - ngx_http_v3_session_t *h3c; - ngx_http_v3_srv_conf_t *h3scf; - - h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); + ngx_http_v3_session_t *h3c; h3c = ngx_http_v3_get_session(c); - if (h3scf->max_table_capacity > 0 && !c->read->eof && !h3c->hq + if (!c->read->eof && !h3c->hq + && h3c->known_streams[NGX_HTTP_V3_STREAM_SERVER_DECODER] && (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) { (void) ngx_http_v3_send_cancel_stream(c, c->quic->id); diff -r 371b6a7d0673 -r 387470a87c8a src/http/v3/ngx_http_v3_uni.c --- a/src/http/v3/ngx_http_v3_uni.c Tue May 28 17:17:19 2024 +0400 +++ b/src/http/v3/ngx_http_v3_uni.c Tue May 28 17:18:28 2024 +0400 @@ -20,8 +20,6 @@ static void ngx_http_v3_close_uni_stream static void ngx_http_v3_uni_read_handler(ngx_event_t *rev); static void ngx_http_v3_uni_dummy_read_handler(ngx_event_t *wev); static void ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev); -static ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, - ngx_uint_t type); void @@ -307,7 +305,7 @@ ngx_http_v3_uni_dummy_write_handler(ngx_ } -static ngx_connection_t * +ngx_connection_t * ngx_http_v3_get_uni_stream(ngx_connection_t *c, ngx_uint_t type) { u_char buf[NGX_HTTP_V3_VARLEN_INT_LEN]; diff -r 371b6a7d0673 -r 387470a87c8a src/http/v3/ngx_http_v3_uni.h --- a/src/http/v3/ngx_http_v3_uni.h Tue May 28 17:17:19 2024 +0400 +++ b/src/http/v3/ngx_http_v3_uni.h Tue May 28 17:18:28 2024 +0400 @@ -19,6 +19,8 @@ ngx_int_t ngx_http_v3_register_uni_strea ngx_int_t ngx_http_v3_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id); +ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, + ngx_uint_t type); ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c); ngx_int_t ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id); ngx_int_t ngx_http_v3_send_ack_section(ngx_connection_t *c, From pluknet at nginx.com Wed May 29 14:57:48 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:57:48 +0000 Subject: [nginx] HTTP/3: fixed dynamic table overflow. Message-ID: details: https://hg.nginx.org/nginx/rev/a0cbbdeebccd branches: changeset: 9252:a0cbbdeebccd user: Roman Arutyunyan date: Tue May 28 17:18:50 2024 +0400 description: HTTP/3: fixed dynamic table overflow. While inserting a new entry into the dynamic table, first the entry is added, and then older entries are evicted until table size is within capacity. After the first step, the number of entries may temporarily exceed the maximum calculated from capacity by one entry, which previously caused table overflow. The easiest way to trigger the issue is to keep adding entries with empty names and values until first eviction. The issue was introduced by 987bee4363d1. diffstat: src/http/v3/ngx_http_v3_table.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 387470a87c8a -r a0cbbdeebccd src/http/v3/ngx_http_v3_table.c --- a/src/http/v3/ngx_http_v3_table.c Tue May 28 17:18:28 2024 +0400 +++ b/src/http/v3/ngx_http_v3_table.c Tue May 28 17:18:50 2024 +0400 @@ -308,7 +308,7 @@ ngx_http_v3_set_capacity(ngx_connection_ prev_max = dt->capacity / 32; if (max > prev_max) { - elts = ngx_alloc(max * sizeof(void *), c->log); + elts = ngx_alloc((max + 1) * sizeof(void *), c->log); if (elts == NULL) { return NGX_ERROR; } From pluknet at nginx.com Wed May 29 14:57:51 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:57:51 +0000 Subject: [nginx] QUIC: ignore CRYPTO frames after handshake completion. Message-ID: details: https://hg.nginx.org/nginx/rev/cf66916bc6a3 branches: changeset: 9253:cf66916bc6a3 user: Roman Arutyunyan date: Tue May 28 17:19:08 2024 +0400 description: QUIC: ignore CRYPTO frames after handshake completion. Sending handshake-level CRYPTO frames after the client's Finished message could lead to memory disclosure and a potential segfault, if those frames are sent in one packet with the Finished frame. diffstat: src/event/quic/ngx_event_quic_ssl.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diffs (15 lines): diff -r a0cbbdeebccd -r cf66916bc6a3 src/event/quic/ngx_event_quic_ssl.c --- a/src/event/quic/ngx_event_quic_ssl.c Tue May 28 17:18:50 2024 +0400 +++ b/src/event/quic/ngx_event_quic_ssl.c Tue May 28 17:19:08 2024 +0400 @@ -326,6 +326,11 @@ ngx_quic_handle_crypto_frame(ngx_connect ngx_quic_crypto_frame_t *f; qc = ngx_quic_get_connection(c); + + if (!ngx_quic_keys_available(qc->keys, pkt->level, 0)) { + return NGX_OK; + } + ctx = ngx_quic_get_send_ctx(qc, pkt->level); f = &frame->u.crypto; From pluknet at nginx.com Wed May 29 14:57:54 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:57:54 +0000 Subject: [nginx] QUIC: ngx_quic_buffer_t use-after-free protection. Message-ID: details: https://hg.nginx.org/nginx/rev/55a6a45b7fa9 branches: changeset: 9254:55a6a45b7fa9 user: Roman Arutyunyan date: Tue May 28 17:19:21 2024 +0400 description: QUIC: ngx_quic_buffer_t use-after-free protection. Previously the last chain field of ngx_quic_buffer_t could still reference freed chains and buffers after calling ngx_quic_free_buffer(). While normally an ngx_quic_buffer_t object should not be used after freeing, resetting last_chain field would prevent a potential use-after-free. diffstat: src/event/quic/ngx_event_quic_frames.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (11 lines): diff -r cf66916bc6a3 -r 55a6a45b7fa9 src/event/quic/ngx_event_quic_frames.c --- a/src/event/quic/ngx_event_quic_frames.c Tue May 28 17:19:08 2024 +0400 +++ b/src/event/quic/ngx_event_quic_frames.c Tue May 28 17:19:21 2024 +0400 @@ -648,6 +648,7 @@ ngx_quic_free_buffer(ngx_connection_t *c ngx_quic_free_chain(c, qb->chain); qb->chain = NULL; + qb->last_chain = NULL; } From pluknet at nginx.com Wed May 29 14:57:57 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:57:57 +0000 Subject: [nginx] HTTP/3: fixed handling of zero-length literal field line. Message-ID: details: https://hg.nginx.org/nginx/rev/ebdeca3b392b branches: changeset: 9255:ebdeca3b392b user: Sergey Kandaurov date: Tue May 28 17:20:45 2024 +0400 description: HTTP/3: fixed handling of zero-length literal field line. Previously, st->value was passed with NULL data pointer to header handlers. diffstat: src/http/v3/ngx_http_v3_parse.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diffs (27 lines): diff -r 55a6a45b7fa9 -r ebdeca3b392b src/http/v3/ngx_http_v3_parse.c --- a/src/http/v3/ngx_http_v3_parse.c Tue May 28 17:19:21 2024 +0400 +++ b/src/http/v3/ngx_http_v3_parse.c Tue May 28 17:20:45 2024 +0400 @@ -810,6 +810,7 @@ ngx_http_v3_parse_field_lri(ngx_connecti st->literal.length = st->pint.value; if (st->literal.length == 0) { + st->value.data = (u_char *) ""; goto done; } @@ -932,6 +933,7 @@ ngx_http_v3_parse_field_l(ngx_connection st->literal.length = st->pint.value; if (st->literal.length == 0) { + st->value.data = (u_char *) ""; goto done; } @@ -1072,6 +1074,7 @@ ngx_http_v3_parse_field_lpbi(ngx_connect st->literal.length = st->pint.value; if (st->literal.length == 0) { + st->value.data = (u_char *) ""; goto done; } From pluknet at nginx.com Wed May 29 14:58:00 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:00 +0000 Subject: [nginx] nginx-1.27.0-RELEASE Message-ID: details: https://hg.nginx.org/nginx/rev/2166e329fb4e branches: changeset: 9256:2166e329fb4e user: Sergey Kandaurov date: Tue May 28 17:19:38 2024 +0400 description: nginx-1.27.0-RELEASE diffstat: docs/xml/nginx/changes.xml | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 68 insertions(+), 0 deletions(-) diffs (78 lines): diff -r ebdeca3b392b -r 2166e329fb4e docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml Tue May 28 17:20:45 2024 +0400 +++ b/docs/xml/nginx/changes.xml Tue May 28 17:19:38 2024 +0400 @@ -5,6 +5,74 @@ + + + + +при использовании HTTP/3 обработка специально созданной QUIC-сессии могла +приводить к падению рабочего процесса, отправке клиенту содержимого памяти +рабочего процесса на системах с MTU больше 4096 байт, а также потенциально +могла иметь другие последствия +(CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161).
+Спасибо Nils Bars из CISPA. +
+ +when using HTTP/3, processing of a specially crafted QUIC session might +cause a worker process crash, worker process memory disclosure on systems +with MTU larger than 4096 bytes, or might have potential other impact +(CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161).
+Thanks to Nils Bars of CISPA. +
+
+ + + +директивы proxy_limit_rate, fastcgi_limit_rate, +scgi_limit_rate и uwsgi_limit_rate поддерживают переменные. + + +variables support +in the "proxy_limit_rate", "fastcgi_limit_rate", "scgi_limit_rate", +and "uwsgi_limit_rate" directives. + + + + + +уменьшено потребление памяти для долгоживущих запросов, +если используются директивы gzip, gunzip, ssi, sub_filter или grpc_pass. + + +reduced memory consumption for long-lived requests +if "gzip", "gunzip", "ssi", "sub_filter", or "grpc_pass" directives are used. + + + + + +nginx не собирался gcc 14, +если использовался параметр --with-atomic.
+Спасибо Edgar Bonet. +
+ +nginx could not be built by gcc 14 +if the --with-atomic option was used.
+Thanks to Edgar Bonet. +
+
+ + + +Исправления в HTTP/3. + + +Bugfixes in HTTP/3. + + + +
+ + From pluknet at nginx.com Wed May 29 14:58:03 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:03 +0000 Subject: [nginx] release-1.27.0 tag Message-ID: details: https://hg.nginx.org/nginx/rev/02e9411009b9 branches: changeset: 9257:02e9411009b9 user: Sergey Kandaurov date: Tue May 28 17:22:30 2024 +0400 description: release-1.27.0 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff -r 2166e329fb4e -r 02e9411009b9 .hgtags --- a/.hgtags Tue May 28 17:19:38 2024 +0400 +++ b/.hgtags Tue May 28 17:22:30 2024 +0400 @@ -478,3 +478,4 @@ 1d839f05409d1a50d0f15a2bf36547001f99ae40 294a3d07234f8f65d7b0e0b0e2c5b05c12c5da0a release-1.25.3 173a0a7dbce569adbb70257c6ec4f0f6bc585009 release-1.25.4 8618e4d900cc71082fbe7dc72af087937d64faf5 release-1.25.5 +2166e329fb4ed7d6da7c823ee6499f7d06d7bc00 release-1.27.0 From pluknet at nginx.com Wed May 29 14:58:06 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:06 +0000 Subject: [nginx] Version bump. Message-ID: details: https://hg.nginx.org/nginx/rev/73770db03e73 branches: stable-1.26 changeset: 9258:73770db03e73 user: Sergey Kandaurov date: Tue May 28 17:14:08 2024 +0400 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff -r cdf74ac25b47 -r 73770db03e73 src/core/nginx.h --- a/src/core/nginx.h Tue Apr 23 18:04:32 2024 +0400 +++ b/src/core/nginx.h Tue May 28 17:14:08 2024 +0400 @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1026000 -#define NGINX_VERSION "1.26.0" +#define nginx_version 1026001 +#define NGINX_VERSION "1.26.1" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From pluknet at nginx.com Wed May 29 14:58:09 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:09 +0000 Subject: [nginx] Configure: fixed building libatomic test. Message-ID: details: https://hg.nginx.org/nginx/rev/31fe21f04103 branches: stable-1.26 changeset: 9259:31fe21f04103 user: Edgar Bonet date: Thu May 16 11:15:10 2024 +0200 description: Configure: fixed building libatomic test. Using "long *" instead of "AO_t *" leads either to -Wincompatible-pointer-types or -Wpointer-sign warnings, depending on whether long and size_t are compatible types (e.g., ILP32 versus LP64 data models). Notably, -Wpointer-sign warnings are enabled by default in Clang only, and -Wincompatible-pointer-types is an error starting from GCC 14. Signed-off-by: Edgar Bonet diffstat: auto/lib/libatomic/conf | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 73770db03e73 -r 31fe21f04103 auto/lib/libatomic/conf --- a/auto/lib/libatomic/conf Tue May 28 17:14:08 2024 +0400 +++ b/auto/lib/libatomic/conf Thu May 16 11:15:10 2024 +0200 @@ -19,7 +19,7 @@ else #include " ngx_feature_path= ngx_feature_libs="-latomic_ops" - ngx_feature_test="long n = 0; + ngx_feature_test="AO_t n = 0; if (!AO_compare_and_swap(&n, 0, 1)) return 1; if (AO_fetch_and_add(&n, 1) != 1) From pluknet at nginx.com Wed May 29 14:58:12 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:12 +0000 Subject: [nginx] Optimized chain link usage (ticket #2614). Message-ID: details: https://hg.nginx.org/nginx/rev/b317a71f75ae branches: stable-1.26 changeset: 9260:b317a71f75ae user: Roman Arutyunyan date: Thu May 23 19:15:38 2024 +0400 description: Optimized chain link usage (ticket #2614). Previously chain links could sometimes be dropped instead of being reused, which could result in increased memory consumption during long requests. A similar chain link issue in ngx_http_gzip_filter_module was fixed in da46bfc484ef (1.11.10). Based on a patch by Sangmin Lee. diffstat: src/core/ngx_output_chain.c | 10 ++++++++-- src/http/modules/ngx_http_grpc_module.c | 5 ++++- src/http/modules/ngx_http_gunzip_filter_module.c | 18 ++++++++++++++---- src/http/modules/ngx_http_gzip_filter_module.c | 10 +++++++--- src/http/modules/ngx_http_ssi_filter_module.c | 8 ++++++-- src/http/modules/ngx_http_sub_filter_module.c | 8 ++++++-- 6 files changed, 45 insertions(+), 14 deletions(-) diffs (158 lines): diff -r 31fe21f04103 -r b317a71f75ae src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c Thu May 16 11:15:10 2024 +0200 +++ b/src/core/ngx_output_chain.c Thu May 23 19:15:38 2024 +0400 @@ -117,7 +117,10 @@ ngx_output_chain(ngx_output_chain_ctx_t ngx_debug_point(); - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in = cl->next; + + ngx_free_chain(ctx->pool, cl); continue; } @@ -203,7 +206,10 @@ ngx_output_chain(ngx_output_chain_ctx_t /* delete the completed buf from the ctx->in chain */ if (ngx_buf_size(ctx->in->buf) == 0) { - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in = cl->next; + + ngx_free_chain(ctx->pool, cl); } cl = ngx_alloc_chain_link(ctx->pool); diff -r 31fe21f04103 -r b317a71f75ae src/http/modules/ngx_http_grpc_module.c --- a/src/http/modules/ngx_http_grpc_module.c Thu May 16 11:15:10 2024 +0200 +++ b/src/http/modules/ngx_http_grpc_module.c Thu May 23 19:15:38 2024 +0400 @@ -1231,7 +1231,7 @@ ngx_http_grpc_body_output_filter(void *d ngx_buf_t *b; ngx_int_t rc; ngx_uint_t next, last; - ngx_chain_t *cl, *out, **ll; + ngx_chain_t *cl, *out, *ln, **ll; ngx_http_upstream_t *u; ngx_http_grpc_ctx_t *ctx; ngx_http_grpc_frame_t *f; @@ -1459,7 +1459,10 @@ ngx_http_grpc_body_output_filter(void *d last = 1; } + ln = in; in = in->next; + + ngx_free_chain(r->pool, ln); } ctx->in = in; diff -r 31fe21f04103 -r b317a71f75ae src/http/modules/ngx_http_gunzip_filter_module.c --- a/src/http/modules/ngx_http_gunzip_filter_module.c Thu May 16 11:15:10 2024 +0200 +++ b/src/http/modules/ngx_http_gunzip_filter_module.c Thu May 23 19:15:38 2024 +0400 @@ -333,6 +333,8 @@ static ngx_int_t ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, ngx_http_gunzip_ctx_t *ctx) { + ngx_chain_t *cl; + if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { return NGX_OK; } @@ -344,8 +346,11 @@ ngx_http_gunzip_filter_add_data(ngx_http return NGX_DECLINED; } - ctx->in_buf = ctx->in->buf; - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in_buf = cl->buf; + ctx->in = cl->next; + + ngx_free_chain(r->pool, cl); ctx->zstream.next_in = ctx->in_buf->pos; ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; @@ -374,6 +379,7 @@ static ngx_int_t ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, ngx_http_gunzip_ctx_t *ctx) { + ngx_chain_t *cl; ngx_http_gunzip_conf_t *conf; if (ctx->zstream.avail_out) { @@ -383,8 +389,12 @@ ngx_http_gunzip_filter_get_buf(ngx_http_ conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); if (ctx->free) { - ctx->out_buf = ctx->free->buf; - ctx->free = ctx->free->next; + + cl = ctx->free; + ctx->out_buf = cl->buf; + ctx->free = cl->next; + + ngx_free_chain(r->pool, cl); ctx->out_buf->flush = 0; diff -r 31fe21f04103 -r b317a71f75ae src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c Thu May 16 11:15:10 2024 +0200 +++ b/src/http/modules/ngx_http_gzip_filter_module.c Thu May 23 19:15:38 2024 +0400 @@ -985,10 +985,14 @@ static void ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { - ngx_chain_t *cl; + ngx_chain_t *cl, *ln; - for (cl = ctx->copied; cl; cl = cl->next) { - ngx_pfree(r->pool, cl->buf->start); + for (cl = ctx->copied; cl; /* void */) { + ln = cl; + cl = cl->next; + + ngx_pfree(r->pool, ln->buf->start); + ngx_free_chain(r->pool, ln); } ctx->copied = NULL; diff -r 31fe21f04103 -r b317a71f75ae src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c Thu May 16 11:15:10 2024 +0200 +++ b/src/http/modules/ngx_http_ssi_filter_module.c Thu May 23 19:15:38 2024 +0400 @@ -482,9 +482,13 @@ ngx_http_ssi_body_filter(ngx_http_reques while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { - ctx->buf = ctx->in->buf; - ctx->in = ctx->in->next; + + cl = ctx->in; + ctx->buf = cl->buf; + ctx->in = cl->next; ctx->pos = ctx->buf->pos; + + ngx_free_chain(r->pool, cl); } if (ctx->state == ssi_start_state) { diff -r 31fe21f04103 -r b317a71f75ae src/http/modules/ngx_http_sub_filter_module.c --- a/src/http/modules/ngx_http_sub_filter_module.c Thu May 16 11:15:10 2024 +0200 +++ b/src/http/modules/ngx_http_sub_filter_module.c Thu May 23 19:15:38 2024 +0400 @@ -335,9 +335,13 @@ ngx_http_sub_body_filter(ngx_http_reques while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { - ctx->buf = ctx->in->buf; - ctx->in = ctx->in->next; + + cl = ctx->in; + ctx->buf = cl->buf; + ctx->in = cl->next; ctx->pos = ctx->buf->pos; + + ngx_free_chain(r->pool, cl); } if (ctx->buf->flush || ctx->buf->recycled) { From pluknet at nginx.com Wed May 29 14:58:16 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:16 +0000 Subject: [nginx] QUIC: client transport parameter data length checking. Message-ID: details: https://hg.nginx.org/nginx/rev/04bc350b2919 branches: stable-1.26 changeset: 9261:04bc350b2919 user: Sergey Kandaurov date: Tue May 28 17:17:19 2024 +0400 description: QUIC: client transport parameter data length checking. diffstat: src/event/quic/ngx_event_quic_transport.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diffs (18 lines): diff -r b317a71f75ae -r 04bc350b2919 src/event/quic/ngx_event_quic_transport.c --- a/src/event/quic/ngx_event_quic_transport.c Thu May 23 19:15:38 2024 +0400 +++ b/src/event/quic/ngx_event_quic_transport.c Tue May 28 17:17:19 2024 +0400 @@ -1750,6 +1750,14 @@ ngx_quic_parse_transport_params(u_char * return NGX_ERROR; } + if ((size_t) (end - p) < len) { + ngx_log_error(NGX_LOG_INFO, log, 0, + "quic failed to parse" + " transport param id:0x%xL, data length %uL too long", + id, len); + return NGX_ERROR; + } + rc = ngx_quic_parse_transport_param(p, p + len, id, tp); if (rc == NGX_ERROR) { From pluknet at nginx.com Wed May 29 14:58:18 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:18 +0000 Subject: [nginx] HTTP/3: decoder stream pre-creation. Message-ID: details: https://hg.nginx.org/nginx/rev/08f8e9c33a08 branches: stable-1.26 changeset: 9262:08f8e9c33a08 user: Roman Arutyunyan date: Tue May 28 17:18:28 2024 +0400 description: HTTP/3: decoder stream pre-creation. Previously a decoder stream was created on demand for sending Section Acknowledgement, Stream Cancellation and Insert Count Increment. If conditions for sending any of these instructions never happen, a decoder stream is not created at all. These conditions include client not using the dynamic table and no streams abandoned by server (RFC 9204, Section 2.2.2.2). However RFC 9204, Section 4.2 defines only one condition for not creating a decoder stream: An endpoint MAY avoid creating a decoder stream if its decoder sets the maximum capacity of the dynamic table to zero. The change enables pre-creation of the decoder stream at HTTP/3 session initialization if maximum dynamic table capacity is not zero. Note that this value is currently hardcoded to 4096 bytes and is not configurable, so the stream is now always created. Also, the change fixes a potential stack overflow when creating a decoder stream in ngx_http_v3_send_cancel_stream() while draining a request stream by ngx_drain_connections(). Creating a decoder stream involves calling ngx_get_connection(), which calls ngx_drain_connections(), which will drain the same request stream again. If client's MAX_STREAMS for uni stream is high enough, these recursive calls will continue until we run out of stack. Otherwise, decoder stream creation will fail at some point and the request stream connection will be drained. This may result in use-after-free, since this connection could still be referenced up the stack. diffstat: src/http/v3/ngx_http_v3_request.c | 20 ++++++++++++++------ src/http/v3/ngx_http_v3_uni.c | 4 +--- src/http/v3/ngx_http_v3_uni.h | 2 ++ 3 files changed, 17 insertions(+), 9 deletions(-) diffs (73 lines): diff -r 04bc350b2919 -r 08f8e9c33a08 src/http/v3/ngx_http_v3_request.c --- a/src/http/v3/ngx_http_v3_request.c Tue May 28 17:17:19 2024 +0400 +++ b/src/http/v3/ngx_http_v3_request.c Tue May 28 17:18:28 2024 +0400 @@ -134,7 +134,17 @@ ngx_http_v3_init(ngx_connection_t *c) } } - return ngx_http_v3_send_settings(c); + if (ngx_http_v3_send_settings(c) != NGX_OK) { + return NGX_ERROR; + } + + if (h3scf->max_table_capacity > 0) { + if (ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER) == NULL) { + return NGX_ERROR; + } + } + + return NGX_OK; } @@ -398,14 +408,12 @@ ngx_http_v3_wait_request_handler(ngx_eve void ngx_http_v3_reset_stream(ngx_connection_t *c) { - ngx_http_v3_session_t *h3c; - ngx_http_v3_srv_conf_t *h3scf; - - h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); + ngx_http_v3_session_t *h3c; h3c = ngx_http_v3_get_session(c); - if (h3scf->max_table_capacity > 0 && !c->read->eof && !h3c->hq + if (!c->read->eof && !h3c->hq + && h3c->known_streams[NGX_HTTP_V3_STREAM_SERVER_DECODER] && (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) { (void) ngx_http_v3_send_cancel_stream(c, c->quic->id); diff -r 04bc350b2919 -r 08f8e9c33a08 src/http/v3/ngx_http_v3_uni.c --- a/src/http/v3/ngx_http_v3_uni.c Tue May 28 17:17:19 2024 +0400 +++ b/src/http/v3/ngx_http_v3_uni.c Tue May 28 17:18:28 2024 +0400 @@ -20,8 +20,6 @@ static void ngx_http_v3_close_uni_stream static void ngx_http_v3_uni_read_handler(ngx_event_t *rev); static void ngx_http_v3_uni_dummy_read_handler(ngx_event_t *wev); static void ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev); -static ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, - ngx_uint_t type); void @@ -307,7 +305,7 @@ ngx_http_v3_uni_dummy_write_handler(ngx_ } -static ngx_connection_t * +ngx_connection_t * ngx_http_v3_get_uni_stream(ngx_connection_t *c, ngx_uint_t type) { u_char buf[NGX_HTTP_V3_VARLEN_INT_LEN]; diff -r 04bc350b2919 -r 08f8e9c33a08 src/http/v3/ngx_http_v3_uni.h --- a/src/http/v3/ngx_http_v3_uni.h Tue May 28 17:17:19 2024 +0400 +++ b/src/http/v3/ngx_http_v3_uni.h Tue May 28 17:18:28 2024 +0400 @@ -19,6 +19,8 @@ ngx_int_t ngx_http_v3_register_uni_strea ngx_int_t ngx_http_v3_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id); +ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, + ngx_uint_t type); ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c); ngx_int_t ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id); ngx_int_t ngx_http_v3_send_ack_section(ngx_connection_t *c, From pluknet at nginx.com Wed May 29 14:58:21 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:21 +0000 Subject: [nginx] HTTP/3: fixed dynamic table overflow. Message-ID: details: https://hg.nginx.org/nginx/rev/ed593e26c79a branches: stable-1.26 changeset: 9263:ed593e26c79a user: Roman Arutyunyan date: Tue May 28 17:18:50 2024 +0400 description: HTTP/3: fixed dynamic table overflow. While inserting a new entry into the dynamic table, first the entry is added, and then older entries are evicted until table size is within capacity. After the first step, the number of entries may temporarily exceed the maximum calculated from capacity by one entry, which previously caused table overflow. The easiest way to trigger the issue is to keep adding entries with empty names and values until first eviction. The issue was introduced by 987bee4363d1. diffstat: src/http/v3/ngx_http_v3_table.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 08f8e9c33a08 -r ed593e26c79a src/http/v3/ngx_http_v3_table.c --- a/src/http/v3/ngx_http_v3_table.c Tue May 28 17:18:28 2024 +0400 +++ b/src/http/v3/ngx_http_v3_table.c Tue May 28 17:18:50 2024 +0400 @@ -308,7 +308,7 @@ ngx_http_v3_set_capacity(ngx_connection_ prev_max = dt->capacity / 32; if (max > prev_max) { - elts = ngx_alloc(max * sizeof(void *), c->log); + elts = ngx_alloc((max + 1) * sizeof(void *), c->log); if (elts == NULL) { return NGX_ERROR; } From pluknet at nginx.com Wed May 29 14:58:25 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:25 +0000 Subject: [nginx] QUIC: ignore CRYPTO frames after handshake completion. Message-ID: details: https://hg.nginx.org/nginx/rev/e4e9d7003b31 branches: stable-1.26 changeset: 9264:e4e9d7003b31 user: Roman Arutyunyan date: Tue May 28 17:19:08 2024 +0400 description: QUIC: ignore CRYPTO frames after handshake completion. Sending handshake-level CRYPTO frames after the client's Finished message could lead to memory disclosure and a potential segfault, if those frames are sent in one packet with the Finished frame. diffstat: src/event/quic/ngx_event_quic_ssl.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diffs (15 lines): diff -r ed593e26c79a -r e4e9d7003b31 src/event/quic/ngx_event_quic_ssl.c --- a/src/event/quic/ngx_event_quic_ssl.c Tue May 28 17:18:50 2024 +0400 +++ b/src/event/quic/ngx_event_quic_ssl.c Tue May 28 17:19:08 2024 +0400 @@ -326,6 +326,11 @@ ngx_quic_handle_crypto_frame(ngx_connect ngx_quic_crypto_frame_t *f; qc = ngx_quic_get_connection(c); + + if (!ngx_quic_keys_available(qc->keys, pkt->level, 0)) { + return NGX_OK; + } + ctx = ngx_quic_get_send_ctx(qc, pkt->level); f = &frame->u.crypto; From pluknet at nginx.com Wed May 29 14:58:27 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:27 +0000 Subject: [nginx] QUIC: ngx_quic_buffer_t use-after-free protection. Message-ID: details: https://hg.nginx.org/nginx/rev/b32b516f36b1 branches: stable-1.26 changeset: 9265:b32b516f36b1 user: Roman Arutyunyan date: Tue May 28 17:19:21 2024 +0400 description: QUIC: ngx_quic_buffer_t use-after-free protection. Previously the last chain field of ngx_quic_buffer_t could still reference freed chains and buffers after calling ngx_quic_free_buffer(). While normally an ngx_quic_buffer_t object should not be used after freeing, resetting last_chain field would prevent a potential use-after-free. diffstat: src/event/quic/ngx_event_quic_frames.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (11 lines): diff -r e4e9d7003b31 -r b32b516f36b1 src/event/quic/ngx_event_quic_frames.c --- a/src/event/quic/ngx_event_quic_frames.c Tue May 28 17:19:08 2024 +0400 +++ b/src/event/quic/ngx_event_quic_frames.c Tue May 28 17:19:21 2024 +0400 @@ -648,6 +648,7 @@ ngx_quic_free_buffer(ngx_connection_t *c ngx_quic_free_chain(c, qb->chain); qb->chain = NULL; + qb->last_chain = NULL; } From pluknet at nginx.com Wed May 29 14:58:30 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:30 +0000 Subject: [nginx] HTTP/3: fixed handling of zero-length literal field line. Message-ID: details: https://hg.nginx.org/nginx/rev/5b3f409d55f0 branches: stable-1.26 changeset: 9266:5b3f409d55f0 user: Sergey Kandaurov date: Tue May 28 17:20:45 2024 +0400 description: HTTP/3: fixed handling of zero-length literal field line. Previously, st->value was passed with NULL data pointer to header handlers. diffstat: src/http/v3/ngx_http_v3_parse.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diffs (27 lines): diff -r b32b516f36b1 -r 5b3f409d55f0 src/http/v3/ngx_http_v3_parse.c --- a/src/http/v3/ngx_http_v3_parse.c Tue May 28 17:19:21 2024 +0400 +++ b/src/http/v3/ngx_http_v3_parse.c Tue May 28 17:20:45 2024 +0400 @@ -810,6 +810,7 @@ ngx_http_v3_parse_field_lri(ngx_connecti st->literal.length = st->pint.value; if (st->literal.length == 0) { + st->value.data = (u_char *) ""; goto done; } @@ -932,6 +933,7 @@ ngx_http_v3_parse_field_l(ngx_connection st->literal.length = st->pint.value; if (st->literal.length == 0) { + st->value.data = (u_char *) ""; goto done; } @@ -1072,6 +1074,7 @@ ngx_http_v3_parse_field_lpbi(ngx_connect st->literal.length = st->pint.value; if (st->literal.length == 0) { + st->value.data = (u_char *) ""; goto done; } From pluknet at nginx.com Wed May 29 14:58:33 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:33 +0000 Subject: [nginx] nginx-1.26.1-RELEASE Message-ID: details: https://hg.nginx.org/nginx/rev/a63c124e34bc branches: stable-1.26 changeset: 9267:a63c124e34bc user: Sergey Kandaurov date: Tue May 28 17:26:54 2024 +0400 description: nginx-1.26.1-RELEASE diffstat: docs/xml/nginx/changes.xml | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 56 insertions(+), 0 deletions(-) diffs (66 lines): diff -r 5b3f409d55f0 -r a63c124e34bc docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml Tue May 28 17:20:45 2024 +0400 +++ b/docs/xml/nginx/changes.xml Tue May 28 17:26:54 2024 +0400 @@ -5,6 +5,62 @@ + + + + +при использовании HTTP/3 обработка специально созданной QUIC-сессии могла +приводить к падению рабочего процесса, отправке клиенту содержимого памяти +рабочего процесса на системах с MTU больше 4096 байт, а также потенциально +могла иметь другие последствия +(CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161).
+Спасибо Nils Bars из CISPA. +
+ +when using HTTP/3, processing of a specially crafted QUIC session might +cause a worker process crash, worker process memory disclosure on systems +with MTU larger than 4096 bytes, or might have potential other impact +(CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161).
+Thanks to Nils Bars of CISPA. +
+
+ + + +уменьшено потребление памяти для долгоживущих запросов, +если используются директивы gzip, gunzip, ssi, sub_filter или grpc_pass. + + +reduced memory consumption for long-lived requests +if "gzip", "gunzip", "ssi", "sub_filter", or "grpc_pass" directives are used. + + + + + +nginx не собирался gcc 14, +если использовался параметр --with-atomic.
+Спасибо Edgar Bonet. +
+ +nginx could not be built by gcc 14 +if the --with-atomic option was used.
+Thanks to Edgar Bonet. +
+
+ + + +в HTTP/3. + + +in HTTP/3. + + + +
+ + From pluknet at nginx.com Wed May 29 14:58:37 2024 From: pluknet at nginx.com (=?utf-8?q?Sergey_Kandaurov?=) Date: Wed, 29 May 2024 14:58:37 +0000 Subject: [nginx] release-1.26.1 tag Message-ID: details: https://hg.nginx.org/nginx/rev/dd5bc1844be3 branches: stable-1.26 changeset: 9268:dd5bc1844be3 user: Sergey Kandaurov date: Tue May 28 17:28:07 2024 +0400 description: release-1.26.1 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff -r a63c124e34bc -r dd5bc1844be3 .hgtags --- a/.hgtags Tue May 28 17:26:54 2024 +0400 +++ b/.hgtags Tue May 28 17:28:07 2024 +0400 @@ -479,3 +479,4 @@ 294a3d07234f8f65d7b0e0b0e2c5b05c12c5da0a 173a0a7dbce569adbb70257c6ec4f0f6bc585009 release-1.25.4 8618e4d900cc71082fbe7dc72af087937d64faf5 release-1.25.5 a58202a8c41bf0bd97eef1b946e13105a105520d release-1.26.0 +a63c124e34bcf2d1d1feb8d40ff075103b967c4c release-1.26.1 From noreply at nginx.com Wed May 29 23:08:03 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Wed, 29 May 2024 23:08:03 +0000 Subject: [njs] Added security policy. Message-ID: details: https://hg.nginx.org/njs/rev/5c1a1fa63bf0 branches: changeset: 2344:5c1a1fa63bf0 user: Dmitry Volyntsev date: Tue May 28 18:41:49 2024 -0700 description: Added security policy. diffstat: SECURITY.md | 24 ++++++++++++++++++++++++ 1 files changed, 24 insertions(+), 0 deletions(-) diffs (28 lines): diff -r 773c816a7360 -r 5c1a1fa63bf0 SECURITY.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SECURITY.md Tue May 28 18:41:49 2024 -0700 @@ -0,0 +1,24 @@ +# Security Policy + +## Latest Versions + +We advise users to run or update to the most recent release of njs. Older versions may not have all enhancements and/or bug fixes applied to them. + +## Special Considerations + +njs does not evaluate dynamic code, especially code received from the network, in any way. The only way to evaluate such code using njs is to configure the `js_import` directive in nginx. JavaScript code is loaded once during nginx start. + +In the nginx/njs threat model, JavaScript code is considered a trusted source in the same way as `nginx.conf` and site certificates. This means in practice: + +- Memory disclosure and other security issues triggered by JavaScript code modification are not considered security issues, but as ordinary bugs. +- Measures should be taken to protect JavaScript code used by njs. +- If no `js_import` directives are present in `nginx.conf`, nginx is safe from JavaScript-related vulnerabilities. + +## Reporting a Vulnerability + +The F5 Security Incident Response Team (F5 SIRT) has an email alias that makes it easy to report potential security vulnerabilities. + +- If you’re an F5 customer with an active support contract, please contact [F5 Technical Support](https://www.f5.com/services/support). +- If you aren’t an F5 customer, please report any potential or current instances of security vulnerabilities with any F5 product to the F5 Security Incident Response Team at F5SIRT at f5.com + +For more information visit [https://www.f5.com/services/support/report-a-vulnerability](https://www.f5.com/services/support/report-a-vulnerability) From noreply at nginx.com Thu May 30 00:08:03 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 30 May 2024 00:08:03 +0000 Subject: [njs] Added support guide. Message-ID: details: https://hg.nginx.org/njs/rev/4b116e8fcb03 branches: changeset: 2345:4b116e8fcb03 user: Dmitry Volyntsev date: Wed May 29 16:29:47 2024 -0700 description: Added support guide. diffstat: SUPPORT.md | 37 +++++++++++++++++++++++++++++++++++++ 1 files changed, 37 insertions(+), 0 deletions(-) diffs (41 lines): diff -r 5c1a1fa63bf0 -r 4b116e8fcb03 SUPPORT.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SUPPORT.md Wed May 29 16:29:47 2024 -0700 @@ -0,0 +1,37 @@ +# Support + +## Ask a Question + +We use GitHub for tracking bugs and feature requests related to njs. + +Don't know how something in this project works? Curious if this project can achieve your desired functionality? Please open an issue on GitHub with the label `question`. + +## NGINX Specific Questions and/or Issues + +This isn't the right place to get support for NGINX specific questions, but the following resources are available below. Thanks for your understanding! + +### Community Slack + +We have a community [Slack](https://nginxcommunity.slack.com/)! + +If you are not a member, click [here](https://community.nginx.org/joinslack) to sign up (and let us know if the link does not seem to be working!) + +Once you join, check out the `#beginner-questions` and `nginx-users` channels :) + +### Documentation + +For a comprehensive list of all NGINX directives, check out . + +For a comprehensive list of admin and deployment guides for all NGINX products, check out . + +### Mailing List + +Want to get in touch with the NGINX development team directly? Try using the relevant mailing list found at ! + +## Contributing + +Please see the [contributing guide](CONTRIBUTING.md) for guidelines on how to best contribute to this project. + +## Commercial Support + +Commercial support for this project may be available. Please get in touch with [NGINX sales](https://www.nginx.com/contact-sales/) or check your contract details for more info! From noreply at nginx.com Thu May 30 03:12:03 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 30 May 2024 03:12:03 +0000 Subject: [njs] Added issue templates. Message-ID: details: https://hg.nginx.org/njs/rev/d80048eb970d branches: changeset: 2346:d80048eb970d user: Dmitry Volyntsev date: Wed May 29 17:04:27 2024 -0700 description: Added issue templates. diffstat: .github/ISSUE_TEMPLATE/bug_report.md | 52 +++++++++++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 22 +++++++++++++ .github/pull_request_template.md | 10 +++++ 3 files changed, 84 insertions(+), 0 deletions(-) diffs (96 lines): diff -r 4b116e8fcb03 -r d80048eb970d .github/ISSUE_TEMPLATE/bug_report.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.github/ISSUE_TEMPLATE/bug_report.md Wed May 29 17:04:27 2024 -0700 @@ -0,0 +1,52 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "" +labels: "bug" +--- + +### Describe the bug + +A clear and concise description of what the bug is. +Before submitting a bug report, please check the following: + +- [ ] The bug is reproducible with the latest version of njs. +- [ ] I minimized the code and NGINX configuration to the smallest +possible to reproduce the issue. + +### To reproduce + +Steps to reproduce the behavior: + +- JS script +```js +// Your JS code here +``` +or put the code in a [gist](https://gist.github.com/) and link it here. +- NGINX configuration if applicable +``` +# Your NGINX configuration here +``` +or put the configuration in a [gist](https://gist.github.com/) and link it here. +- NGINX logs if applicable +``` +# Your NGINX logs here +``` +or post the full log to a [gist](https://gist.github.com/) and link it here. +- Output of the `nginx -V` command if applicable. +- Exact steps to reproduce the behavior + +### Expected behavior + +A clear and concise description of what you expected to happen. + +### Your environment + +- Version of njs or specific commit +- Version of NGINX if applicable +- List of other enabled nginx modules if applicable +- OS: [e.g. Ubuntu 20.04] + +### Additional context + +Add any other context about the problem here. diff -r 4b116e8fcb03 -r d80048eb970d .github/ISSUE_TEMPLATE/feature_request.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.github/ISSUE_TEMPLATE/feature_request.md Wed May 29 17:04:27 2024 -0700 @@ -0,0 +1,22 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "" +labels: "feature" +--- + +### Is your feature request related to a problem? Please describe + +A clear and concise description of what the problem is. + +### Describe the solution you'd like + +A clear and concise description of what you want to happen. + +### Describe alternatives you've considered + +A clear and concise description of any alternative solutions or features you've considered. + +### Additional context + +Add any other context or screenshots about the feature request here. diff -r 4b116e8fcb03 -r d80048eb970d .github/pull_request_template.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.github/pull_request_template.md Wed May 29 17:04:27 2024 -0700 @@ -0,0 +1,10 @@ +### Proposed changes + +Describe the use case and detail of the change. If this PR addresses an issue on GitHub, make sure to include a link to that issue using one of the [supported keywords](https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) here in this description (not in the title of the PR). + +### Checklist + +Before creating a PR, run through this checklist and mark each as complete: +- [ ] I have read the [`CONTRIBUTING`](CONTRIBUTING.md) document +- [ ] If applicable, I have added tests that prove my fix is effective or that my feature works +- [ ] If applicable, I have checked that any relevant tests pass after adding my changes From noreply at nginx.com Thu May 30 16:26:03 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 30 May 2024 16:26:03 +0000 Subject: [njs] Test262: fixed flaky fs tests. Message-ID: details: https://hg.nginx.org/njs/rev/7d73d18e19f8 branches: changeset: 2347:7d73d18e19f8 user: Dmitry Volyntsev date: Wed May 29 22:23:55 2024 -0700 description: Test262: fixed flaky fs tests. Previously, two tests running in parallel could occasionally generate identical file names because Math.random() was used for part of the file name, leading to one of the tests failing. The fix is to use a single global counter to generate file names, ensuring deterministic and unique file names for each test. diffstat: test/fs/methods.t.js | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diffs (21 lines): diff -r d80048eb970d -r 7d73d18e19f8 test/fs/methods.t.js --- a/test/fs/methods.t.js Wed May 29 17:04:27 2024 -0700 +++ b/test/fs/methods.t.js Wed May 29 22:23:55 2024 -0700 @@ -3,6 +3,8 @@ includes: [compatFs.js, compatBuffer.js, flags: [async] ---*/ +let unique = 0; + function p(args, default_opts) { let params = Object.assign({}, default_opts, args); @@ -10,7 +12,7 @@ function p(args, default_opts) { let fname = params.args[0]; if (fname[0] == '@') { - let gen = `${test_dir}/fs_test_${Math.round(Math.random() * 1000000)}`; + let gen = `${test_dir}/fs_test_${unique++}`; params.args = params.args.map(v => v); params.args[0] = gen + fname.slice(1); } From noreply at nginx.com Thu May 30 16:26:05 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 30 May 2024 16:26:05 +0000 Subject: [njs] Test262: fixed unstable fs test. Message-ID: details: https://hg.nginx.org/njs/rev/7c671d50f646 branches: changeset: 2348:7c671d50f646 user: Dmitry Volyntsev date: Wed May 29 22:26:09 2024 -0700 description: Test262: fixed unstable fs test. Ensuring that symlink file is removed even if regular file does not exist. diffstat: test/fs/methods.t.js | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diffs (13 lines): diff -r 7d73d18e19f8 -r 7c671d50f646 test/fs/methods.t.js --- a/test/fs/methods.t.js Wed May 29 22:23:55 2024 -0700 +++ b/test/fs/methods.t.js Wed May 29 22:26:09 2024 -0700 @@ -484,7 +484,8 @@ let stat_tests = () => [ /* making symbolic link. */ - try { fs.unlinkSync(fname); fs.unlinkSync(lname); } catch (e) {} + try { fs.unlinkSync(fname); } catch (e) {} + try { fs.unlinkSync(lname); } catch (e) {} fs.writeFileSync(fname, fname); From arut at nginx.com Thu May 30 16:48:07 2024 From: arut at nginx.com (Roman Arutyunyan) Date: Thu, 30 May 2024 20:48:07 +0400 Subject: [PATCH 2 of 2] Stream: do not reallocate a parsed SNI host In-Reply-To: <88fa18a0f05f7dead38a.1716805304@enoparse.local> References: <88fa18a0f05f7dead38a.1716805304@enoparse.local> Message-ID: <20240530164807.m3sz6xaxuemggsmv@N00W24XTQX> Hi, On Mon, May 27, 2024 at 02:21:44PM +0400, Sergey Kandaurov wrote: > # HG changeset patch > # User Sergey Kandaurov > # Date 1716805288 -14400 > # Mon May 27 14:21:28 2024 +0400 > # Node ID 88fa18a0f05f7dead38a127bb24e5cf861f3d66d > # Parent e82a7318ed48fdbc1273771bc96357e9dc232975 > Stream: do not reallocate a parsed SNI host. > > Unlike in http SNI callback, it doesn't need to be saved here. > > diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c > --- a/src/stream/ngx_stream_ssl_module.c > +++ b/src/stream/ngx_stream_ssl_module.c > @@ -501,7 +501,7 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t > > host.data = (u_char *) servername; > > - rc = ngx_stream_validate_host(&host, c->pool, 1); > + rc = ngx_stream_validate_host(&host, c->pool, 0); > > if (rc == NGX_ERROR) { > goto error; While it's true the host variable is only used within this function, its content can be referenced by session after exiting it. And that's why we should keep the reallocation here. ngx_stream_find_virtual_server() calls ngx_stream_regex_exec() for server name regex, which can save references to parts of the host in capture variables. > diff --git a/src/stream/ngx_stream_ssl_preread_module.c b/src/stream/ngx_stream_ssl_preread_module.c > --- a/src/stream/ngx_stream_ssl_preread_module.c > +++ b/src/stream/ngx_stream_ssl_preread_module.c > @@ -519,7 +519,7 @@ ngx_stream_ssl_preread_servername(ngx_st > > host = *servername; > > - rc = ngx_stream_validate_host(&host, c->pool, 1); > + rc = ngx_stream_validate_host(&host, c->pool, 0); > > if (rc == NGX_ERROR) { > return NGX_ERROR; > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://mailman.nginx.org/mailman/listinfo/nginx-devel -- Roman Arutyunyan From maksim.yevmenkin at gmail.com Thu May 30 20:05:31 2024 From: maksim.yevmenkin at gmail.com (Maksim Yevmenkin) Date: Thu, 30 May 2024 13:05:31 -0700 Subject: proxy_cache_lock for content revalidation Message-ID: hello! it seems that the proxy_cache_lock directive operates only for cache misses (new content). while this behavior is documented, i am curious about the reasoning behind it. there are scenarios where proxy_cache_lock could be very beneficial for content revalidation. what are the community's thoughts on this? thanks! max From noreply at nginx.com Fri May 31 01:05:03 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Fri, 31 May 2024 01:05:03 +0000 Subject: [njs] Added contributing guide. Message-ID: details: https://hg.nginx.org/njs/rev/509ae247a002 branches: changeset: 2349:509ae247a002 user: Dmitry Volyntsev date: Tue May 28 18:34:22 2024 -0700 description: Added contributing guide. diffstat: CONTRIBUTING.md | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 95 insertions(+), 0 deletions(-) diffs (99 lines): diff -r 7c671d50f646 -r 509ae247a002 CONTRIBUTING.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CONTRIBUTING.md Tue May 28 18:34:22 2024 -0700 @@ -0,0 +1,95 @@ +# Contributing guidelines + +The following is a set of guidelines for contributing to njs. We do +appreciate that you are considering contributing! + +## Table of contents + +- [Getting started](#getting-started) +- [Ask a question](#ask-a-question) +- [Contributing](#contributing) +- [Git style guide](#git-style-guide) + + +## Getting started + +Check out the [Getting started](README.md#getting-started-with-nginx-javascript) +and [njs examples](https://github.com/nginx/njs-examples) guides to get NGINX with +njs up and running. + + +## Ask a question + +Please open an [issue](https://github.com/nginx/njs/issues/new) on GitHub with +the label `question`. You can also ask a question on the NGINX mailing list, +nginx at nginx.org (subscribe [here](https://mailman.nginx.org/mailman/listinfo/nginx)). + + +## Contributing + +### Report a bug + +Please ensure the bug has not already been reported as +[issue](https://github.com/nginx/njs/issues). + +If the bug is a potential security vulnerability, please report using our +[security policy](SECURITY.md). + +To report a non-security bug, open an +[issue](https://github.com/nginx/njs/issues/new) on GitHub with the label +`bug`. Be sure to include a title and clear description, as much relevant +information as possible, and a code sample or an executable test case showing +the expected behavior that doesn't occur. + + +### Suggest a feature or enhancement + +To suggest a feature or enhancement, please create an [issue](https://github.com/nginx/njs/issues/new) +on GitHub with the label `feature` or `enhancement` using the available feature +request issue template. Please ensure the feature or enhancement has not +already been suggested. + +> [!NOTE] +> If you’d like to implement a new feature, please consider creating a +> feature request issue first to start a discussion about the feature +> before implementing it. + + +### Open a pull request + +Fork the repo, create a branch, implement your changes, add any relevant tests, +submit a PR when your changes are tested and ready for review. + +Before submitting a PR, please read the NGINX code guidelines to learn more +about coding conventions and style. + +- Try to make it clear why the suggested change is needed, and provide a use + case, if possible. + +- Changes should be formatted according to the code style used by njs. + njs mostly follows the [NGINX coding style](https://nginx.org/en/docs/dev/development_guide.html#code_style), + with some minor differences. Sometimes, there is no clear rule; in such + cases examine how existing njs sources are formatted and mimic this style. + +- Submitting changes implies granting project a permission to use it under + an [BSD-2-Clause license](LICENSE). + + +## Git style guide + +- Keep a clean, concise and meaningful git commit history on your branch, + rebasing locally and squashing before submitting a PR + +- In the subject line, use the past tense ("Added feature", not "Add feature"); + also, use past tense to describe past scenarios, and present tense for + current behavior + +- Limit the subject line to 67 characters, and the rest of the commit message + to 80 characters + +- Use subject line prefixes for commits that affect a specific portion of the + code; examples include "Tests:", "HTTP:", or "Core:". See the commit history + to get an idea of the prefixes used. + +- Reference issues and PRs liberally after the subject line; if the commit + remedies a GitHub issue, [name it](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) accordingly From noreply at nginx.com Fri May 31 18:57:03 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Fri, 31 May 2024 18:57:03 +0000 Subject: [njs] Updated README Message-ID: details: https://hg.nginx.org/njs/rev/5e18d7e5f632 branches: changeset: 2350:5e18d7e5f632 user: Michael Vernik date: Thu May 30 23:24:30 2024 -0700 description: Updated README New Readme content and added .md extension diffstat: NGINX-js-1660x332.png | Bin README | 27 --- README.md | 365 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 365 insertions(+), 27 deletions(-) diffs (402 lines): diff -r 509ae247a002 -r 5e18d7e5f632 NGINX-js-1660x332.png Binary file NGINX-js-1660x332.png has changed diff -r 509ae247a002 -r 5e18d7e5f632 README --- a/README Tue May 28 18:34:22 2024 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ - -NGINX JavaScript (njs) ----------------------- - -njs is a subset of the JavaScript language that allows extending nginx -functionality. njs is created in compliance with ECMAScript 5.1 (strict mode) -with some ECMAScript 6 and later extensions. The compliance is still evolving. - -The documentation is available online: - - https://nginx.org/en/docs/njs/ - -Additional examples and howtos can be found here: - - https://github.com/nginx/njs-examples - -Please ask questions, report issues, and send patches to the mailing list: - - nginx-devel at nginx.org (https://mailman.nginx.org/mailman/listinfo/nginx-devel) - -or via Github: - - https://github.com/nginx/njs - --- -NGINX, Inc., https://nginx.com - diff -r 509ae247a002 -r 5e18d7e5f632 README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Thu May 30 23:24:30 2024 -0700 @@ -0,0 +1,365 @@ +![NGINX JavaScript Banner](NGINX-js-1660x332.png "NGINX JavaScript Banner") + +# NGINX JavaScript +NGINX JavaScript, also known as [NJS](https://nginx.org/en/docs/njs/), is a dynamic module for [NGINX](https://nginx.org/en/download.html) that enables the extension of built-in functionality using familiar JavaScript syntax. The NJS language is a subset of JavaScript, compliant with [ES5](https://262.ecma-international.org/5.1/) (ECMAScript 5.1 [Strict Variant](https://262.ecma-international.org/5.1/#sec-4.2.2)) with some [ES6](https://262.ecma-international.org/6.0/) (ECMAScript 6) and newer extensions. See [compatibility](https://nginx.org/en/docs/njs/compatibility.html) for more details. + +# Table of Contents +- [How it works](#how-it-works) +- [Downloading and installing](#downloading-and-installing) + - [Provisioning the NGINX package repository](#provisioning-the-nginx-package-repository) + - [Installing the NGINX JavaScript modules](#installing-the-nginx-javascipt-modules) + - [Installed files and locations](#installed-files-and-locations) +- [Getting started with NGINX JavaScript](#getting-started-with-nginx-javascript) + - [Verify NGINX is running](#verify-nginx-is-running) + - [Enabling the NGINX JavaScript modules](#enabling-the-nginx-javascipt-modules) + - [Basics of writing .js script files](#basics-of-writing-js-script-files) + - [Reference of custom objects, methods, and properties](#reference-of-custom-objects-methods-and-properties) + - [Example: Hello World](#hello-world) + - [The NJS command line interface (CLI)](#the-njs-command-line-interface-cli) +- [Building from source](#building-from-source) + - [Installing dependencies](#installing-dependencies) + - [Cloning the NGINX JavaScript GitHub repository](#cloning-the-nginx-javascript-github-repository) + - [Building standalone command line interface utility (optional)](#building-standalone-command-line-interface-utility-optional) + - [Cloning the NGINX GitHub repository](#cloning-the-nginx-github-repository) + - [Building NGINX JavaScript as a module of NGINX](#building-nginx-javascript-as-a-module-of-nginx) +- [NGINX JavaScript technical specifications](#nginx-javascript-technical-specifications) + - [Supported distributions](#supported-distributions) + - [Supported deployment environments](#supported-deployment-environments) + - [Supported NGINX versions](#supported-nginx-versions) + - [Sizing recommendations](#sizing-recommendations) +- [Asking questions, reporting issues, and contributing](#asking-questions-reporting-issues-and-contributing) +- [Change log](#change-log) +- [License](#license) + +# How it works +[NGINX JavaScript](https://nginx.org/en/docs/njs/) is provided as two [dynamic modules](https://nginx.org/en/linux_packages.html#dynmodules) for NGINX ([ngx_http_js_module](https://nginx.org/en/docs/http/ngx_http_js_module.html) and [ngx_stream_js_module](https://nginx.org/en/docs/stream/ngx_stream_js_module.html)) and can be added to any supported [NGINX Open Source](https://nginx.org/en/download.html) or [NGINX Plus](https://www.f5.com/products/nginx/nginx-plus) installation without recompilation. + +The NJS module allows NGINX administrators to: +- Add complex access control and security checks before requests reach upstream servers +- Manipulate response headers +- Write flexible, asynchronous content handlers, filters, and more! + +See [examples](https://github.com/nginx/njs-examples/) and our various projects developed with NJS: + +#### https://github.com/nginxinc/nginx-openid-connect +Extends NGINX Plus functionality to communicate directly with OIDC-compatible Identity Providers, authenticating users and authorizing content delivered by NGINX Plus. + +#### https://github.com/nginxinc/nginx-saml +Reference implementation of NGINX Plus as a service provider for SAML authentication. + +#### https://github.com/nginxinc/njs-prometheus-module +Exposes Prometheus metrics endpoint directly from NGINX Plus. + +> [!TIP] +> NJS can also be used with the [NGINX Unit](https://unit.nginx.org/) application server. Learn more about NGINX Unit's [Control API](https://unit.nginx.org/controlapi/) and how to [define function calls with NJS](https://unit.nginx.org/scripting/). + +# Downloading and installing +Follow these steps to download and install precompiled NGINX and NGINX JavaScript Linux binaries. You may also choose to [build the module locally from source code](#building-from-source). + +## Provisioning the NGINX package repository +Follow [this guide](https://nginx.org/en/linux_packages.html) to add the official NGINX package repository to your system and install NGINX Open Source. If you already have NGINX Open Source or NGINX Plus installed, skip the NGINX installation portion in the last step. + +## Installing the NGINX JavaScript modules +Once the repository has been provisioned, you may install NJS by issuing the following command: + +### Ubuntu or Debian based systems +```bash +sudo apt install nginx-module-njs +``` + +### RHEL, RedHat and its derivatives +```bash +sudo yum install nginx-module-njs +``` + +### Alpine or similar systems +```bash +sudo apk add nginx-module-njs at nginx +``` + +### SuSE, SLES or similar systems +```bash +sudo zypper install nginx-module-njs +``` + +> [!TIP] +> The package repository includes an alternate module that enables debug symbols. Although not recommended for production environments, this module may be helpful when developing NJS-based configurations. To download and install the debug version of the module, replace the module name in the previous command with `nginx-module-njs-dbg`. + +## Installed files and locations +The package installation scripts install two modules, supporting NGINX [`http`](https://nginx.org/en/docs/http/ngx_http_core_module.html#http) and [`stream`](https://nginx.org/en/docs/stream/ngx_stream_core_module.html#stream) contexts. + +- [ngx_http_js_module](https://nginx.org/en/docs/http/ngx_http_js_module.html) + + This NJS module enables manipulation of data transmitted over HTTP. +- [ngx_stream_js_module](https://nginx.org/en/docs/stream/ngx_stream_js_module.html) + + This NJS module enables manipulation of data transmitted via stream protocols such as TCP and UDP. + +By default, both modules are installed into the `/etc/nginx/modules` directory. + +# Getting started with NGINX JavaScript +Usage of NJS involves enabling the module, adding JavaScript files with defined functions, and invoking exported functions in NGINX configuration files. + +## Verify NGINX is running +NGINX JavaScript is a module for NGINX Open Source or NGINX Plus. If you haven't done so already, follow these steps to install [NGINX Open Source](https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/) or [NGINX Plus](https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-plus/). Once installed, ensure the NGINX instance is running and able to respond to HTTP requests. + +### Starting NGINX +Issue the following command to start NGINX: + +```bash +sudo nginx +``` + +### Verify NGINX is responding to HTTP requests +```bash +curl -I 127.0.0.1 +``` + +You should see the following response: +```bash +HTTP/1.1 200 OK +Server: nginx/1.25.5 +``` + +## Enabling the NGINX JavaScript modules +Once installed, either (or both) NJS module(s) must be included in the NGINX configuration file. On most systems, the NGINX configuration file is located at `/etc/nginx/nginx.conf` by default. + +### Edit the NGINX configuration file + +```bash +sudo vi /etc/nginx/nginx.conf +``` + +### Enable dynamic loading of NJS modules +Use the [load_module](https://nginx.org/en/docs/ngx_core_module.html#load_module) directive in the top-level (“main”) context to enable either (or both) module(s). + +```nginx +load_module modules/ngx_http_js_module.so; +load_module modules/ngx_stream_js_module.so; +``` + +## Basics of writing .js script files +NJS script files are typically named with a .js extension and placed in the `/etc/nginx/njs/` directory. They are usually comprised of functions that are then exported, making them available in NGINX configuration files. + +## Reference of custom objects, methods, and properties +NJS provides a collection of objects with associated methods and properties that are not part of ECMAScript definitions. See the [complete reference](https://nginx.org/en/docs/njs/reference.html) to these objects and how they can be used to further extend and customize NGINX. + +## Example: Hello World +Here's a basic "Hello World" example. + +### example.js +The `hello` function in this file returns an HTTP 200 OK status response code along with the string "Hello World!", followed by a line feed. The function is then exported for use in an NGINX configuration file. + +Add this file to the `/etc/nginx/njs` directory: + +```JavaScript +function hello(r) { + r.return(200, "Hello world!\n"); +} + +export default {hello} +``` + +### nginx.conf +We modify our NGINX configuration (`/etc/nginx/nginx.conf`) to import the JavaScript file and execute the function under specific circumstances. + +```nginx +# Load the ngx_http_js_module module +load_module modules/ngx_http_js_module.so; + +events {} + +http { + # Set the path to our njs JavaScript files + js_path "/etc/nginx/njs/"; + + # Import our JavaScript file into the variable "main" + js_import main from http/hello.js; + + server { + listen 80; + + location / { + # Execute the "hello" function defined in our JavaScript file on all HTTP requests + # and respond with the contents of our function. + js_content main.hello; + } + } +} +``` + +For a full list of njs directives, see the [ngx_http_js_module](https://nginx.org/en/docs/http/ngx_http_js_module.html) and [ngx_stream_js_module](https://nginx.org/en/docs/stream/ngx_stream_js_module.html) module documentation pages. + +> [!TIP] +> A more detailed version of this and other examples can be found in the official [njs-examples repository](https://github.com/nginx/njs-examples/tree/master). + +## The NJS command line interface (CLI) +NGINX JavaScript installs with a command line interface utility. The interface can be opened as an interactive shell or used to process JavaScript syntax from predefined files or standard input. Since the utility runs independently, NGINX-specific objects such as [HTTP](https://nginx.org/en/docs/njs/reference.html#http) and [Stream](https://nginx.org/en/docs/njs/reference.html#http) are not available within its runtime. + +### Example usage of the interactive CLI +```JavaScript +$ njs +>> globalThis +global { + njs: njs { + version: '0.8.4' + }, + global: [Circular], + process: process { + argv: ['/usr/bin/njs'], + env: { + PATH: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + HOSTNAME: 'f777c149d4f8', + TERM: 'xterm', + NGINX_VERSION: '1.25.5', + NJS_VERSION: '0.8.4', + PKG_RELEASE: '1~buster', + HOME: '/root' + } + }, + console: { + log: [Function: native], + dump: [Function: native], + time: [Function: native], + timeEnd: [Function: native] + }, + print: [Function: native] +} +>> +``` + +### Example usage of the non-interactive CLI +```bash +$ echo "2**3" | njs -q +8 +``` + +# Building from source +The following steps can be used to build NGINX JavaScript as a dynamic module to be integrated into NGINX or a standalone binary for use as a command line interface utility. + +> [!IMPORTANT] +> To build the module for use with NGINX, you will also need to clone, configure and build NGINX by following the steps outlined in this document. + +## Installing dependencies +Most Linux distributions will require several dependencies to be installed in order to build NGINX and NGINX JavaScript. The following instructions are specific to the `apt` package manager, widely available on most Ubuntu/Debian distributions and their derivatives. + +### Installing compiler and make utility + +```bash +sudo apt install gcc make +``` + +### Installing dependency libraries + +```bash +sudo apt install libpcre3-dev zlib1g-dev libssl-dev libxml2-dev libxslt-dev +``` + +> [!WARNING] +> This is the minimal set of dependency libraries needed to build NGINX and NJS. Other dependencies may be required if you choose to build NGINX with additional modules. Monitor the output of the `configure` command discussed in the following sections for information on which modules may be missing. + +## Cloning the NGINX JavaScript GitHub repository +Using your preferred method, clone the NGINX JavaScript repository into your development directory. See [Cloning a GitHub Repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) for additional help. + +```bash +https://github.com/nginx/njs.git +``` + +## Building the standalone command line interface utility (Optional) +The following steps are optional and only needed if you choose to build NJS as a standalone utility. + +### Install dependencies +To use the NJS interactive shell, you will need to install the libedit-dev library + +```bash +sudo apt install libedit-dev +``` + +### Configure and build +Run the following commands from the root directory of your cloned repository: + +```bash +./configure +``` + +Build NGINX JavaScript: +```bash +make +``` + +The utility should now be available at `/build/njs`. See [The NJS Command Line Interface (CLI)](#the-njs-command-line-interface-cli) for information on usage. + +## Cloning the NGINX GitHub repository +Clone the NGINX source code repository in a directory outside of the previously cloned NJS source repository. + +```bash +https://github.com/nginx/nginx.git +``` + +## Building NGINX JavaScript as a module of NGINX +To build NGINX JavaScript as a dynamic module, execute the following commands from the NGINX source code repository's root directory: + +```bash +auto/configure --add-dynamic-module=/nginx +``` + +> [!WARNING] +> By default, this method will only build the `ngx_http_js_module` module. To use NJS with the NGINX Stream module, you'll need to enable it during the `configure` step so it builds with the NGINX binary. Doing so will automatically compile the `ngx_stream_js_module` module when NJS is added to the build. One way of accomplishing this is to alter the `configure` step to: +> ```bash +> auto/configure --with-stream --add-dynamic-module=/nginx +> ``` + +Compile the module +```bash +make +``` + +> [!TIP] +> To build NGINX with NGINX JavaScript embedded into a single binary, alter the `configure` step to the following: +> ```bash +> auto/configure --add-module=/nginx +> ``` + +### Install module +If built as a dynamic module(s), the NGINX JavaScript module(s) will be available in the `/objs/` directory. The module(s) can then be copied to an existing NGINX installation and enabled. See [Enabling the NGINX JavaScript Modules](#enabling-the-nginx-javascipt-modules) for details. + +### Install compiled NGINX and NGINX JavaScript binaries +Alternatively, you may choose to install the built NGINX and NGINX JavaScript binaries by issuing the following command: + +> [!IMPORTANT] +> If built into the NGINX binary as a standard (not dynamic) module, this will be the easiest method of installation + +```bash +make install +``` + +By default, the NGINX binary will be installed into `/usr/local/nginx/sbin/nginx`. The NGINX JavaScript module(s) will be copied to `/usr/local/nginx/modules/`. + +# NGINX JavaScript technical specifications +Technical specifications for NJS are identical to those of NGINX. + +## Supported distributions +See [Tested Operating Systems and Platforms](https://nginx.org/en/#tested_os_and_platforms) for a complete list of supported distributions. + +## Supported deployment environments +- Container +- Public cloud (AWS, Google Cloud Platform, Microsoft Azure) +- Virtual machine + +## Supported NGINX versions +NGINX JavaScript is supported by all NGINX Open Source versions starting with nginx-1.14 and all NGINX Plus versions starting with NGINX Plus R15. + +# Asking questions, reporting issues, and contributing +We encourage you to engage with us. Please see the [Contributing](CONTRIBUTING.md) guide for information on how to ask questions, report issues and contribute code. + +# Change log +See our [release page](https://nginx.org/en/docs/njs/changes.html) to keep track of updates. + +# License +[2-clause BSD-like license](LICENSE) + +--- +Additional documentation available at: https://nginx.org/en/docs/njs/ + +©2024 F5, Inc. All rights reserved. +https://www.f5.com/products/nginx