From noreply at nginx.com Wed Dec 4 01:27:02 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Wed, 4 Dec 2024 01:27:02 +0000 (UTC) Subject: [njs] Fetch: optimized use of SSL contexts. Message-ID: <20241204012702.7402C4876B@pubserv1.nginx> details: https://github.com/nginx/njs/commit/f2955c8b25873d06527815a98e10e487cc1d55cf branches: master commit: f2955c8b25873d06527815a98e10e487cc1d55cf user: Dmitry Volyntsev date: Mon, 2 Dec 2024 18:46:45 -0800 description: Fetch: optimized use of SSL contexts. To ensure optimal use of memory, SSL contexts for ngx.fetch() are now inherited from previous levels as long as relevant js_fetch_* directives are not redefined. --- nginx/ngx_js.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c index 05f6aa7e..12b577a2 100644 --- a/nginx/ngx_js.c +++ b/nginx/ngx_js.c @@ -3946,19 +3946,60 @@ ngx_js_create_conf(ngx_conf_t *cf, size_t size) #if defined(NGX_HTTP_SSL) || defined(NGX_STREAM_SSL) +static ngx_int_t +ngx_js_merge_ssl(ngx_conf_t *cf, ngx_js_loc_conf_t *conf, + ngx_js_loc_conf_t *prev) +{ + ngx_uint_t preserve; + + if (conf->ssl_protocols == 0 + && conf->ssl_ciphers.data == NULL + && conf->ssl_verify == NGX_CONF_UNSET + && conf->ssl_verify_depth == NGX_CONF_UNSET + && conf->ssl_trusted_certificate.data == NULL) + { + if (prev->ssl) { + conf->ssl = prev->ssl; + return NGX_OK; + } + + preserve = 1; + + } else { + preserve = 0; + } + + conf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); + if (conf->ssl == NULL) { + return NGX_ERROR; + } + + conf->ssl->log = cf->log; + + /* + * special handling to preserve conf->ssl + * in the "http" section to inherit it to all servers + */ + + if (preserve) { + prev->ssl = conf->ssl; + } + + return NGX_OK; +} + + static char * ngx_js_set_ssl(ngx_conf_t *cf, ngx_js_loc_conf_t *conf) { ngx_ssl_t *ssl; ngx_pool_cleanup_t *cln; - ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); - if (ssl == NULL) { - return NGX_CONF_ERROR; + if (conf->ssl->ctx) { + return NGX_OK; } - conf->ssl = ssl; - ssl->log = cf->log; + ssl = conf->ssl; if (ngx_ssl_create(ssl, conf->ssl_protocols, NULL) != NGX_OK) { return NGX_CONF_ERROR; @@ -4013,6 +4054,11 @@ ngx_js_merge_conf(ngx_conf_t *cf, void *parent, void *child, } #if defined(NGX_HTTP_SSL) || defined(NGX_STREAM_SSL) + + if (ngx_js_merge_ssl(cf, conf, prev) != NGX_OK) { + return NGX_CONF_ERROR; + } + ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); From noreply at nginx.com Tue Dec 10 04:56:02 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Tue, 10 Dec 2024 04:56:02 +0000 (UTC) Subject: [njs] Version 0.8.8. Message-ID: <20241210045602.24E244885A@pubserv1.nginx> details: https://github.com/nginx/njs/commit/78e3edf7505cd04a5df0b7936bcd2d89e95bdda8 branches: master commit: 78e3edf7505cd04a5df0b7936bcd2d89e95bdda8 user: Dmitry Volyntsev date: Mon, 9 Dec 2024 14:27:30 -0800 description: Version 0.8.8. --- CHANGES | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CHANGES b/CHANGES index 746039ec..cc7ebef4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,28 @@ +Changes with njs 0.8.8 10 Dec 2024 + + nginx modules: + + *) Feature: implemented shared dictionary for QuickJS engine. + + *) Improvement: js_preload_object is refactored. + + *) Bugfix: fixed limit rated output. + + *) Bugfix: optimized use of SSL contexts for + js_fetch_trusted_certificate directive. + + Core: + + *) Feature: implemented process object for QuickJS engine. + + *) Feature: implemented process.kill() method. + + *) Bugfix: fixed tests with libxml2 2.13 and later. + + *) Bugfix: fixed promise resolving when Promise is inherited. + + *) Bugfix: fixed absolute scope in cloned VMs. + Changes with njs 0.8.7 22 Oct 2024 nginx modules: From noreply at nginx.com Tue Dec 10 05:13:02 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Tue, 10 Dec 2024 05:13:02 +0000 (UTC) Subject: [njs] Lightweight tag created: 0.8.8 Message-ID: <20241210051302.1D96A488BC@pubserv1.nginx> details: https://github.com/nginx/njs/releases/tag/0.8.8 branches: commit: 78e3edf7505cd04a5df0b7936bcd2d89e95bdda8 user: Dmitry Volyntsev date: Mon Dec 9 14:27:30 2024 -0800 description: Version 0.8.8. From noreply at nginx.com Tue Dec 10 13:18:03 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Tue, 10 Dec 2024 13:18:03 +0000 (UTC) Subject: [nginx] QUIC: fixed client request timeout in 0-RTT scenarios. Message-ID: <20241210131803.227D0489BD@pubserv1.nginx> details: https://github.com/nginx/nginx/commit/930caed3bfc84e43bf4bd034150c17604dc5dc73 branches: master commit: 930caed3bfc84e43bf4bd034150c17604dc5dc73 user: nandsky date: Mon, 25 Nov 2024 15:26:29 +0800 description: QUIC: fixed client request timeout in 0-RTT scenarios. Since 0-RTT and 1-RTT data exist in the same packet number space, ngx_quic_discard_ctx incorrectly discards 1-RTT packets when 0-RTT keys are discarded. The issue was introduced by 58b92177e7c3c50f77f807ab3846ad5c7bbf0ebe. --- src/event/quic/ngx_event_quic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c index c03b1d003..308597e27 100644 --- a/src/event/quic/ngx_event_quic.c +++ b/src/event/quic/ngx_event_quic.c @@ -1029,7 +1029,7 @@ ngx_quic_handle_payload(ngx_connection_t *c, ngx_quic_header_t *pkt) * After receiving a 1-RTT packet, servers MUST discard * 0-RTT keys within a short time */ - ngx_quic_discard_ctx(c, ssl_encryption_early_data); + ngx_quic_keys_discard(qc->keys, ssl_encryption_early_data); } if (qc->closing) { From noreply at nginx.com Thu Dec 19 20:19:04 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:04 +0000 (UTC) Subject: [njs] Test262: renaming fs tests. Message-ID: <20241219201904.BB757489E2@pubserv1.nginx> details: https://github.com/nginx/njs/commit/dfec49b18644559a7e90395203aedc16200761db branches: master commit: dfec49b18644559a7e90395203aedc16200761db user: Dmitry Volyntsev date: Wed, 4 Dec 2024 18:00:57 -0800 description: Test262: renaming fs tests. --- test/fs/{promises_02.t.mjs => access.t.mjs} | 0 test/fs/{promises_05.t.mjs => mkdir.t.mjs} | 0 test/fs/{promises_08.t.mjs => mkdir2.t.mjs} | 0 test/fs/{promises_01.t.mjs => read_write.t.mjs} | 0 test/fs/{promises_07.t.mjs => readdir.t.mjs} | 0 test/fs/{promises_04.t.mjs => realpath.t.mjs} | 0 test/fs/{promises_06.t.mjs => rename.t.mjs} | 0 test/fs/{promises_09.t.mjs => rmdir.t.mjs} | 0 test/fs/{promises_03.t.mjs => unlink.t.mjs} | 0 9 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test/fs/promises_02.t.mjs b/test/fs/access.t.mjs similarity index 100% rename from test/fs/promises_02.t.mjs rename to test/fs/access.t.mjs diff --git a/test/fs/promises_05.t.mjs b/test/fs/mkdir.t.mjs similarity index 100% rename from test/fs/promises_05.t.mjs rename to test/fs/mkdir.t.mjs diff --git a/test/fs/promises_08.t.mjs b/test/fs/mkdir2.t.mjs similarity index 100% rename from test/fs/promises_08.t.mjs rename to test/fs/mkdir2.t.mjs diff --git a/test/fs/promises_01.t.mjs b/test/fs/read_write.t.mjs similarity index 100% rename from test/fs/promises_01.t.mjs rename to test/fs/read_write.t.mjs diff --git a/test/fs/promises_07.t.mjs b/test/fs/readdir.t.mjs similarity index 100% rename from test/fs/promises_07.t.mjs rename to test/fs/readdir.t.mjs diff --git a/test/fs/promises_04.t.mjs b/test/fs/realpath.t.mjs similarity index 100% rename from test/fs/promises_04.t.mjs rename to test/fs/realpath.t.mjs diff --git a/test/fs/promises_06.t.mjs b/test/fs/rename.t.mjs similarity index 100% rename from test/fs/promises_06.t.mjs rename to test/fs/rename.t.mjs diff --git a/test/fs/promises_09.t.mjs b/test/fs/rmdir.t.mjs similarity index 100% rename from test/fs/promises_09.t.mjs rename to test/fs/rmdir.t.mjs diff --git a/test/fs/promises_03.t.mjs b/test/fs/unlink.t.mjs similarity index 100% rename from test/fs/promises_03.t.mjs rename to test/fs/unlink.t.mjs From noreply at nginx.com Thu Dec 19 20:19:04 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:04 +0000 (UTC) Subject: [njs] Test262: fixed check for crypto object. Message-ID: <20241219201904.AD807489E0@pubserv1.nginx> details: https://github.com/nginx/njs/commit/1442b5ea9c2bd3377bcd6de08ae49ffe75143134 branches: master commit: 1442b5ea9c2bd3377bcd6de08ae49ffe75143134 user: Dmitry Volyntsev date: Wed, 4 Dec 2024 17:52:32 -0800 description: Test262: fixed check for crypto object. --- test/harness/compatWebcrypto.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/harness/compatWebcrypto.js b/test/harness/compatWebcrypto.js index aca3ada5..adc0fb41 100644 --- a/test/harness/compatWebcrypto.js +++ b/test/harness/compatWebcrypto.js @@ -3,6 +3,6 @@ if (typeof crypto == 'undefined' && typeof require == 'function') { } function has_webcrypto() { - return (typeof crypto != 'undefied') ? crypto : null; + return (typeof crypto != 'undefined') ? crypto : null; } From noreply at nginx.com Thu Dec 19 20:19:04 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:04 +0000 (UTC) Subject: [njs] Tests: skipping stream_js_periodic.t for QuickJS engine. Message-ID: <20241219201904.A9640489DE@pubserv1.nginx> details: https://github.com/nginx/njs/commit/ca23804e399635431b6861cb558182045e4f72c1 branches: master commit: ca23804e399635431b6861cb558182045e4f72c1 user: Dmitry Volyntsev date: Fri, 6 Dec 2024 17:37:22 -0800 description: Tests: skipping stream_js_periodic.t for QuickJS engine. --- nginx/t/stream_js_periodic.t | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/nginx/t/stream_js_periodic.t b/nginx/t/stream_js_periodic.t index 3c4dfd1a..4b9e319b 100644 --- a/nginx/t/stream_js_periodic.t +++ b/nginx/t/stream_js_periodic.t @@ -53,7 +53,7 @@ stream { } server { - listen 127.0.0.1:8080; + listen 127.0.0.1:8081; js_periodic test.tick interval=30ms jitter=1ms; js_periodic test.timer interval=1s worker_affinity=all; @@ -78,10 +78,16 @@ stream { http { %%TEST_GLOBALS_HTTP%% + js_import test.js; + server { - listen 127.0.0.1:8081; + listen 127.0.0.1:8080; server_name localhost; + location /engine { + js_content test.engine; + } + location /fetch_ok { return 200 'ok'; } @@ -94,11 +100,15 @@ http { EOF -my $p1 = port(8081); +my $p1 = port(8080); $t->write_file('test.js', <write_file('test.js', <run_daemon(\&stream_daemon, port(8090)); -$t->try_run('no js_periodic')->plan(9); +$t->try_run('no js_periodic'); +plan(skip_all => 'not yet') if http_get('/engine') =~ /QuickJS$/m; +$t->plan(9); $t->waitforsocket('127.0.0.1:' . port(8090)); ############################################################################### select undef, undef, undef, 0.2; -is(stream('127.0.0.1:' . port(8080))->io('affinity'), 'affinity', +is(stream('127.0.0.1:' . port(8081))->io('affinity'), 'affinity', 'affinity test'); -is(stream('127.0.0.1:' . port(8080))->io('tick'), 'tick', '3x tick test'); -is(stream('127.0.0.1:' . port(8080))->io('timer'), 'timer', 'timer test'); -is(stream('127.0.0.1:' . port(8080))->io('file'), 'file', 'file test'); -is(stream('127.0.0.1:' . port(8080))->io('fetch'), 'fetch', 'fetch test'); -is(stream('127.0.0.1:' . port(8080))->io('multiple_fetches'), +is(stream('127.0.0.1:' . port(8081))->io('tick'), 'tick', '3x tick test'); +is(stream('127.0.0.1:' . port(8081))->io('timer'), 'timer', 'timer test'); +is(stream('127.0.0.1:' . port(8081))->io('file'), 'file', 'file test'); +is(stream('127.0.0.1:' . port(8081))->io('fetch'), 'fetch', 'fetch test'); +is(stream('127.0.0.1:' . port(8081))->io('multiple_fetches'), 'multiple_fetches', 'muliple fetches test'); -is(stream('127.0.0.1:' . port(8080))->io('timeout_exception'), +is(stream('127.0.0.1:' . port(8081))->io('timeout_exception'), 'timeout_exception', 'timeout exception test'); -is(stream('127.0.0.1:' . port(8080))->io('vars'), 'vars', 'vars test'); +is(stream('127.0.0.1:' . port(8081))->io('vars'), 'vars', 'vars test'); $t->stop(); From noreply at nginx.com Thu Dec 19 20:19:04 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:04 +0000 (UTC) Subject: [njs] Test262: skipping individual tests. Message-ID: <20241219201904.C32ED489E6@pubserv1.nginx> details: https://github.com/nginx/njs/commit/d6d74ba39167be10870e9a6eef17ae022b67074c branches: master commit: d6d74ba39167be10870e9a6eef17ae022b67074c user: Dmitry Volyntsev date: Thu, 5 Dec 2024 19:53:11 -0800 description: Test262: skipping individual tests. --- test/harness/runTsuite.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/harness/runTsuite.js b/test/harness/runTsuite.js index f7ec8f48..5ba0ef46 100644 --- a/test/harness/runTsuite.js +++ b/test/harness/runTsuite.js @@ -22,6 +22,10 @@ async function run(tlist) { function map(ts) { return ts.tests.map(t => { try { + if (t.skip && t.skip()) { + return Promise.resolve("SKIPPED"); + } + return ts.T(ts.prepare_args(t, ts.opts)); } catch (e) { From noreply at nginx.com Thu Dec 19 20:19:04 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:04 +0000 (UTC) Subject: [njs] Test262: collecting all tests results before exiting. Message-ID: <20241219201904.BF7BE489E4@pubserv1.nginx> details: https://github.com/nginx/njs/commit/524431e0a88f69988ca88b4095018a58b19f62b9 branches: master commit: 524431e0a88f69988ca88b4095018a58b19f62b9 user: Dmitry Volyntsev date: Thu, 5 Dec 2024 16:09:38 -0800 description: Test262: collecting all tests results before exiting. --- test/harness/runTsuite.js | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/test/harness/runTsuite.js b/test/harness/runTsuite.js index 8103f661..f7ec8f48 100644 --- a/test/harness/runTsuite.js +++ b/test/harness/runTsuite.js @@ -19,6 +19,17 @@ async function run(tlist) { return false; } + function map(ts) { + return ts.tests.map(t => { + try { + return ts.T(ts.prepare_args(t, ts.opts)); + + } catch (e) { + return Promise.reject(e); + } + }); + } + for (let k = 0; k < tlist.length; k++) { let ts = tlist[k]; @@ -26,12 +37,19 @@ async function run(tlist) { continue; } - let results = await Promise.allSettled(ts.tests.map(t => ts.T(ts.prepare_args(t, ts.opts)))); - let r = results.map((r, i) => validate(ts.tests, r, i)); + let results = await Promise.allSettled(map(ts)); + let r = results.map((r, i) => { r.passed = validate(ts.tests, r, i); return r; }); + + let passed = r.filter(r => r.passed).length; + if (passed != ts.tests.length) { + r.forEach((r, i) => { + if (!r.passed) { + console.log(` ${JSON.stringify(ts.tests[i])}\n with reason: ${r.reason}`); + } + }) - r.forEach((v, i) => { - assert.sameValue(v, true, `FAILED ${ts.name}: ${JSON.stringify(ts.tests[i])}\n with reason: ${results[i].reason}`); - }) + console.log(`${ts.name} FAILED: [${passed}/${ts.tests.length}]`); + } } } From noreply at nginx.com Thu Dec 19 20:19:04 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:04 +0000 (UTC) Subject: [njs] Test262: running tests within their own directory. Message-ID: <20241219201904.C6CEB489E7@pubserv1.nginx> details: https://github.com/nginx/njs/commit/3ca33c0590b019498382ef584848bfe6ad86248a branches: master commit: 3ca33c0590b019498382ef584848bfe6ad86248a user: Dmitry Volyntsev date: Fri, 13 Dec 2024 22:43:25 -0800 description: Test262: running tests within their own directory. --- test/test262 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test262 b/test/test262 index ce1f4a93..e7d888b2 100755 --- a/test/test262 +++ b/test/test262 @@ -8,6 +8,8 @@ set -e . test/options . test/setup +export NJS_TEST_DIR + for njs_test in $NJS_TESTS; do . test/prepare From noreply at nginx.com Thu Dec 19 20:19:04 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:04 +0000 (UTC) Subject: [njs] Test262: making "fs" module required. Message-ID: <20241219201904.B71B5489DF@pubserv1.nginx> details: https://github.com/nginx/njs/commit/958f8f095b6a302c746c51a16819ce91f8ec8458 branches: master commit: 958f8f095b6a302c746c51a16819ce91f8ec8458 user: Dmitry Volyntsev date: Wed, 4 Dec 2024 17:07:22 -0800 description: Test262: making "fs" module required. --- test/fs/{methods.t.js => methods.t.mjs} | 58 +++++++++++----------- test/fs/{promises_01.t.js => promises_01.t.mjs} | 7 +-- test/fs/{promises_02.t.js => promises_02.t.mjs} | 11 ++-- test/fs/{promises_03.t.js => promises_03.t.mjs} | 11 ++-- test/fs/{promises_04.t.js => promises_04.t.mjs} | 2 +- test/fs/{promises_05.t.js => promises_05.t.mjs} | 11 ++-- test/fs/{promises_06.t.js => promises_06.t.mjs} | 11 ++-- test/fs/{promises_07.t.js => promises_07.t.mjs} | 2 +- test/fs/{promises_08.t.js => promises_08.t.mjs} | 7 +-- test/fs/{promises_09.t.js => promises_09.t.mjs} | 2 +- test/harness/compatFs.js | 16 +----- test/webcrypto/{aes.t.js => aes.t.mjs} | 2 +- .../{aes_decoding.t.js => aes_decoding.t.mjs} | 2 +- test/webcrypto/{derive.t.js => derive.t.mjs} | 2 +- test/webcrypto/{digest.t.js => digest.t.mjs} | 2 +- test/webcrypto/{export.t.js => export.t.mjs} | 8 +-- test/webcrypto/{rsa.t.js => rsa.t.mjs} | 2 +- .../{rsa_decoding.t.js => rsa_decoding.t.mjs} | 2 +- test/webcrypto/{sign.t.js => sign.t.mjs} | 8 +-- test/webcrypto/{verify.t.js => verify.t.mjs} | 8 +-- test/xml/{saml_verify.t.js => saml_verify.t.mjs} | 2 +- 21 files changed, 73 insertions(+), 103 deletions(-) diff --git a/test/fs/methods.t.js b/test/fs/methods.t.mjs similarity index 95% rename from test/fs/methods.t.js rename to test/fs/methods.t.mjs index 72afb494..9b695296 100644 --- a/test/fs/methods.t.js +++ b/test/fs/methods.t.mjs @@ -157,7 +157,7 @@ let readfile_tests = () => [ let readFile_tsuite = { name: "fs readFile", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: readfile_test, prepare_args: p, opts: { type: "callback" }, @@ -166,7 +166,7 @@ let readFile_tsuite = { let readFileSync_tsuite = { name: "fs readFileSync", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: readfile_test, prepare_args: p, opts: { type: "sync" }, @@ -175,7 +175,7 @@ let readFileSync_tsuite = { let readFileP_tsuite = { name: "fsp readFile", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: readfile_test, prepare_args: p, opts: { type: "promise" }, @@ -246,7 +246,7 @@ let writefile_tests = () => [ let writeFile_tsuite = { name: "fs writeFile", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: writefile_test, prepare_args: p, opts: { type: "callback" }, @@ -255,7 +255,7 @@ let writeFile_tsuite = { let writeFileSync_tsuite = { name: "fs writeFileSync", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: writefile_test, prepare_args: p, opts: { type: "sync" }, @@ -264,7 +264,7 @@ let writeFileSync_tsuite = { let writeFileP_tsuite = { name: "fsp writeFile", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: writefile_test, prepare_args: p, opts: { type: "promise" }, @@ -336,7 +336,7 @@ let append_tests = () => [ let appendFile_tsuite = { name: "fs appendFile", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: append_test, prepare_args: p, opts: { type: "callback" }, @@ -345,7 +345,7 @@ let appendFile_tsuite = { let appendFileSync_tsuite = { name: "fs appendFileSync", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: append_test, prepare_args: p, opts: { type: "sync" }, @@ -354,7 +354,7 @@ let appendFileSync_tsuite = { let appendFileP_tsuite = { name: "fsp appendFile", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: append_test, prepare_args: p, opts: { type: "promise" }, @@ -384,7 +384,7 @@ let exists_tests = () => [ let existsSync_tsuite = { name: "fs existsSync", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: exists_test, prepare_args: p, opts: { type: "sync" }, @@ -410,7 +410,7 @@ let realpath_tests = () => [ let realpath_tsuite = { name: "fs realpath", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: realpath_test, prepare_args: p, opts: { type: "callback" }, @@ -419,7 +419,7 @@ let realpath_tsuite = { let realpathSync_tsuite = { name: "fs realpathSync", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: realpath_test, prepare_args: p, opts: { type: "sync" }, @@ -428,7 +428,7 @@ let realpathSync_tsuite = { let realpathP_tsuite = { name: "fsp realpath", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: realpath_test, prepare_args: p, opts: { type: "promise" }, @@ -460,7 +460,7 @@ let readlink_tests = () => [ let readlink_tsuite = { name: "fs readlink", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: readlink_test, prepare_args: p, opts: { type: "callback" }, @@ -469,7 +469,7 @@ let readlink_tsuite = { let readlinkSync_tsuite = { name: "fs readlinkSync", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: readlink_test, prepare_args: p, opts: { type: "sync" }, @@ -478,7 +478,7 @@ let readlinkSync_tsuite = { let readlinkP_tsuite = { name: "fsp readlink", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: readlink_test, prepare_args: p, opts: { type: "promise" }, @@ -620,7 +620,7 @@ let stat_tests = () => [ let stat_tsuite = { name: "fs stat", - skip: () => (!has_fs() || !has_fs_symbolic_link() || !has_buffer()), + skip: () => (!has_fs_symbolic_link() || !has_buffer()), T: method_test, prepare_args: p, opts: { type: "callback", method: "stat" }, @@ -629,7 +629,7 @@ let stat_tsuite = { let statSync_tsuite = { name: "fs statSync", - skip: () => (!has_fs() || !has_fs_symbolic_link() || !has_buffer()), + skip: () => (!has_fs_symbolic_link() || !has_buffer()), T: method_test, prepare_args: p, opts: { type: "sync", method: "stat" }, @@ -638,7 +638,7 @@ let statSync_tsuite = { let statP_tsuite = { name: "fsp stat", - skip: () => (!has_fs() || !has_fs_symbolic_link() || !has_buffer()), + skip: () => (!has_fs_symbolic_link() || !has_buffer()), T: method_test, prepare_args: p, opts: { type: "promise", method: "stat" }, @@ -647,7 +647,7 @@ let statP_tsuite = { let lstat_tsuite = { name: "fs lstat", - skip: () => (!has_fs() || !has_fs_symbolic_link() || !has_buffer()), + skip: () => (!has_fs_symbolic_link() || !has_buffer()), T: method_test, prepare_args: p, opts: { type: "callback", method: "lstat" }, @@ -656,7 +656,7 @@ let lstat_tsuite = { let lstatSync_tsuite = { name: "fs lstatSync", - skip: () => (!has_fs() || !has_fs_symbolic_link() || !has_buffer()), + skip: () => (!has_fs_symbolic_link() || !has_buffer()), T: method_test, prepare_args: p, opts: { type: "sync", method: "lstat" }, @@ -665,7 +665,7 @@ let lstatSync_tsuite = { let lstatP_tsuite = { name: "fsp lstat", - skip: () => (!has_fs() || !has_fs_symbolic_link() || !has_buffer()), + skip: () => (!has_fs_symbolic_link() || !has_buffer()), T: method_test, prepare_args: p, opts: { type: "promise", method: "lstat" }, @@ -770,7 +770,7 @@ let open_tests = () => [ let openSync_tsuite = { name: "fs openSync", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: method_test, prepare_args: p, opts: { type: "sync", method: "open" }, @@ -779,7 +779,7 @@ let openSync_tsuite = { let openP_tsuite = { name: "fsp open", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: method_test, prepare_args: p, opts: { type: "promise", method: "open" }, @@ -813,7 +813,7 @@ let close_tests = () => [ let closeSync_tsuite = { name: "fs closeSync", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: method_test, prepare_args: p, opts: { type: "sync", method: "close" }, @@ -1005,7 +1005,7 @@ let read_tests = () => [ let readSync_tsuite = { name: "fs readSync", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: read_test, prepare_args: p, opts: {}, @@ -1014,7 +1014,7 @@ let readSync_tsuite = { let readFh_tsuite = { name: "fh read", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: readFh_test, prepare_args: p, opts: {}, @@ -1210,7 +1210,7 @@ let write_tests = () => [ let writeSync_tsuite = { name: "fs writeSync", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: write_test, prepare_args: p, opts: {}, @@ -1219,7 +1219,7 @@ let writeSync_tsuite = { let writeFh_tsuite = { name: "fh write", - skip: () => (!has_fs() || !has_buffer()), + skip: () => (!has_buffer()), T: writeFh_test, prepare_args: p, opts: {}, diff --git a/test/fs/promises_01.t.js b/test/fs/promises_01.t.mjs similarity index 87% rename from test/fs/promises_01.t.js rename to test/fs/promises_01.t.mjs index 69f0ce38..74628d45 100644 --- a/test/fs/promises_01.t.js +++ b/test/fs/promises_01.t.mjs @@ -41,10 +41,7 @@ let test = () => Promise.resolve() }) let p = Promise.resolve() -if (has_fs()) { - p = p - .then(test) - .then(() => assert.compareArray(stages, ["init", "short circut", "chain", "errors ok"])) -} + .then(test) + .then(() => assert.compareArray(stages, ["init", "short circut", "chain", "errors ok"])) p.then($DONE, $DONE); diff --git a/test/fs/promises_02.t.js b/test/fs/promises_02.t.mjs similarity index 91% rename from test/fs/promises_02.t.js rename to test/fs/promises_02.t.mjs index 604ac8ca..36cd480a 100644 --- a/test/fs/promises_02.t.js +++ b/test/fs/promises_02.t.mjs @@ -80,12 +80,9 @@ let testFsp = () => Promise.resolve() }) let p = Promise.resolve() -if (has_fs()) { - p = p - .then(testSync) - .then(testCallback) - .then(testFsp) - .then(() => assert.compareArray(stages, ["testSync", "testCallback", "testPromise"])) -} + .then(testSync) + .then(testCallback) + .then(testFsp) + .then(() => assert.compareArray(stages, ["testSync", "testCallback", "testPromise"])) p.then($DONE, $DONE); diff --git a/test/fs/promises_03.t.js b/test/fs/promises_03.t.mjs similarity index 92% rename from test/fs/promises_03.t.js rename to test/fs/promises_03.t.mjs index 491d9903..a5e2d072 100644 --- a/test/fs/promises_03.t.js +++ b/test/fs/promises_03.t.mjs @@ -94,12 +94,9 @@ let testFsp = () => Promise.resolve() }) let p = Promise.resolve() -if (has_fs()) { - p = p - .then(testSync) - .then(testCallback) - .then(testFsp) - .then(() => assert.compareArray(stages, ['unlinkSync', 'unlink', 'fsp.unlink'])) -} + .then(testSync) + .then(testCallback) + .then(testFsp) + .then(() => assert.compareArray(stages, ['unlinkSync', 'unlink', 'fsp.unlink'])) p.then($DONE, $DONE); diff --git a/test/fs/promises_04.t.js b/test/fs/promises_04.t.mjs similarity index 99% rename from test/fs/promises_04.t.js rename to test/fs/promises_04.t.mjs index 763e0954..396d4803 100644 --- a/test/fs/promises_04.t.js +++ b/test/fs/promises_04.t.mjs @@ -180,7 +180,7 @@ let testFsp = () => Promise.resolve() }) let p = Promise.resolve() -if (has_fs() && has_fs_symbolic_link()) { +if (has_fs_symbolic_link()) { p = p .then(testSync) .then(testCallback) diff --git a/test/fs/promises_05.t.js b/test/fs/promises_05.t.mjs similarity index 95% rename from test/fs/promises_05.t.js rename to test/fs/promises_05.t.mjs index e40dfb1f..1fe33be4 100644 --- a/test/fs/promises_05.t.js +++ b/test/fs/promises_05.t.mjs @@ -143,12 +143,9 @@ let testFsp = () => Promise.resolve() }) let p = Promise.resolve() -if (has_fs()) { - p = p - .then(testSync) - .then(testCallback) - .then(testFsp) - .then(() => assert.compareArray(stages, ['mkdirSync', 'mkdir', 'fsp.mkdir'])) -} + .then(testSync) + .then(testCallback) + .then(testFsp) + .then(() => assert.compareArray(stages, ['mkdirSync', 'mkdir', 'fsp.mkdir'])) p.then($DONE, $DONE); diff --git a/test/fs/promises_06.t.js b/test/fs/promises_06.t.mjs similarity index 92% rename from test/fs/promises_06.t.js rename to test/fs/promises_06.t.mjs index 91fdba01..104b4a5b 100644 --- a/test/fs/promises_06.t.js +++ b/test/fs/promises_06.t.mjs @@ -94,12 +94,9 @@ let testFsp = () => Promise.resolve() }) let p = Promise.resolve() -if (has_fs()) { - p = p - .then(testSync) - .then(testCallback) - .then(testFsp) - .then(() => assert.compareArray(stages, ["renameSync", "rename", "fsp.rename"])) -} + .then(testSync) + .then(testCallback) + .then(testFsp) + .then(() => assert.compareArray(stages, ["renameSync", "rename", "fsp.rename"])) p.then($DONE, $DONE); diff --git a/test/fs/promises_07.t.js b/test/fs/promises_07.t.mjs similarity index 99% rename from test/fs/promises_07.t.js rename to test/fs/promises_07.t.mjs index f32b11a5..02b12a3a 100644 --- a/test/fs/promises_07.t.js +++ b/test/fs/promises_07.t.mjs @@ -229,7 +229,7 @@ let testFsp = () => Promise.resolve() }) let p = Promise.resolve() -if (has_fs() && has_fs_symbolic_link()) { +if (has_fs_symbolic_link()) { p = p .then(testSync) .then(testCallback) diff --git a/test/fs/promises_08.t.js b/test/fs/promises_08.t.mjs similarity index 94% rename from test/fs/promises_08.t.js rename to test/fs/promises_08.t.mjs index cffa7c20..d3efa820 100644 --- a/test/fs/promises_08.t.js +++ b/test/fs/promises_08.t.mjs @@ -78,10 +78,7 @@ var testSync = () => new Promise((resolve, reject) => { }); let p = Promise.resolve() -if (has_fs()) { - p = p - .then(testSync) - .then(() => assert.compareArray(stages, ["mkdirSync"])) -} + .then(testSync) + .then(() => assert.compareArray(stages, ["mkdirSync"])) p.then($DONE, $DONE); diff --git a/test/fs/promises_09.t.js b/test/fs/promises_09.t.mjs similarity index 98% rename from test/fs/promises_09.t.js rename to test/fs/promises_09.t.mjs index 91789eed..480f54b5 100644 --- a/test/fs/promises_09.t.js +++ b/test/fs/promises_09.t.mjs @@ -101,7 +101,7 @@ var testSync = () => new Promise((resolve, reject) => { }); let p = Promise.resolve() -if (has_fs() && has_fs_symbolic_link()) { +if (has_fs_symbolic_link()) { p = p .then(testSync) .then(() => assert.compareArray(stages, ['rmdirSync'])) diff --git a/test/harness/compatFs.js b/test/harness/compatFs.js index dd96a592..911be465 100644 --- a/test/harness/compatFs.js +++ b/test/harness/compatFs.js @@ -1,10 +1,5 @@ -let fs = null; -let fsp = null; - -if (typeof require == 'function') { - fs = require('fs'); - fsp = fs.promises; -} +import fs from 'fs'; +let fsp = fs.promises; if (typeof process == 'undefined') { globalThis.process = {}; @@ -13,14 +8,7 @@ if (typeof process == 'undefined') { let test_dir = process.env && process.env['NJS_TEST_DIR'] || 'build'; test_dir = `${test_dir}/test`; -function has_fs() { - return fs; -} - function has_fs_symbolic_link() { - if (!fs) { - return false; - } let fname = test_dir + '/a'; let lname = test_dir + '/b'; diff --git a/test/webcrypto/aes.t.js b/test/webcrypto/aes.t.mjs similarity index 98% rename from test/webcrypto/aes.t.js rename to test/webcrypto/aes.t.mjs index 1f5c136f..80cddabb 100644 --- a/test/webcrypto/aes.t.js +++ b/test/webcrypto/aes.t.mjs @@ -46,7 +46,7 @@ function p(args, default_opts) { let aes_tsuite = { name: "AES encoding/decoding", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { diff --git a/test/webcrypto/aes_decoding.t.js b/test/webcrypto/aes_decoding.t.mjs similarity index 97% rename from test/webcrypto/aes_decoding.t.js rename to test/webcrypto/aes_decoding.t.mjs index c1aff369..80eaf642 100644 --- a/test/webcrypto/aes_decoding.t.js +++ b/test/webcrypto/aes_decoding.t.mjs @@ -40,7 +40,7 @@ function p(args, default_opts) { let aes_tsuite = { name: "AES decoding", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { diff --git a/test/webcrypto/derive.t.js b/test/webcrypto/derive.t.mjs similarity index 98% rename from test/webcrypto/derive.t.js rename to test/webcrypto/derive.t.mjs index 60a21889..5ac13459 100644 --- a/test/webcrypto/derive.t.js +++ b/test/webcrypto/derive.t.mjs @@ -43,7 +43,7 @@ function p(args, default_opts) { let derive_tsuite = { name: "derive", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { diff --git a/test/webcrypto/digest.t.js b/test/webcrypto/digest.t.mjs similarity index 97% rename from test/webcrypto/digest.t.js rename to test/webcrypto/digest.t.mjs index f6413348..4318fe16 100644 --- a/test/webcrypto/digest.t.js +++ b/test/webcrypto/digest.t.mjs @@ -22,7 +22,7 @@ function p(args) { let digest_tsuite = { name: "SHA digest", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { }, diff --git a/test/webcrypto/export.t.js b/test/webcrypto/export.t.mjs similarity index 99% rename from test/webcrypto/export.t.js rename to test/webcrypto/export.t.mjs index 631b3fa6..81b549df 100644 --- a/test/webcrypto/export.t.js +++ b/test/webcrypto/export.t.mjs @@ -247,7 +247,7 @@ function validate_rsa_jwk(exp, params) { let rsa_tsuite = { name: "RSA exporting", - skip: () => (!has_fs() || !has_webcrypto()), + skip: () => (!has_webcrypto()), T: test, prepare_args: p, opts: { @@ -368,7 +368,7 @@ function validate_ec_jwk(exp, params) { let ec_tsuite = { name: "EC exporting", - skip: () => (!has_fs() || !has_webcrypto()), + skip: () => (!has_webcrypto()), T: test, prepare_args: p, opts: { @@ -430,7 +430,7 @@ function validate_hmac_jwk(exp, params) { let hmac_tsuite = { name: "HMAC exporting", - skip: () => (!has_fs() || !has_webcrypto()), + skip: () => (!has_webcrypto()), T: test, prepare_args: p, opts: { @@ -515,7 +515,7 @@ function validate_aes_jwk(exp, params) { let aes_tsuite = { name: "AES exporting", - skip: () => (!has_fs() || !has_webcrypto()), + skip: () => (!has_webcrypto()), T: test, prepare_args: p, opts: { diff --git a/test/webcrypto/rsa.t.js b/test/webcrypto/rsa.t.mjs similarity index 98% rename from test/webcrypto/rsa.t.js rename to test/webcrypto/rsa.t.mjs index b87a0909..977537e0 100644 --- a/test/webcrypto/rsa.t.js +++ b/test/webcrypto/rsa.t.mjs @@ -99,7 +99,7 @@ function p(args, default_opts) { let rsa_tsuite = { name: "RSA-OAEP encoding/decoding", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { diff --git a/test/webcrypto/rsa_decoding.t.js b/test/webcrypto/rsa_decoding.t.mjs similarity index 95% rename from test/webcrypto/rsa_decoding.t.js rename to test/webcrypto/rsa_decoding.t.mjs index 3253daba..24733279 100644 --- a/test/webcrypto/rsa_decoding.t.js +++ b/test/webcrypto/rsa_decoding.t.mjs @@ -4,7 +4,7 @@ flags: [async] ---*/ async function test(params) { - if (!has_fs() || !has_buffer() || !has_webcrypto()) { + if (!has_buffer() || !has_webcrypto()) { return 'SKIPPED'; } diff --git a/test/webcrypto/sign.t.js b/test/webcrypto/sign.t.mjs similarity index 99% rename from test/webcrypto/sign.t.js rename to test/webcrypto/sign.t.mjs index e35473c2..4fa78716 100644 --- a/test/webcrypto/sign.t.js +++ b/test/webcrypto/sign.t.mjs @@ -153,7 +153,7 @@ function p(args, default_opts) { let hmac_tsuite = { name: "HMAC sign", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { @@ -208,7 +208,7 @@ let hmac_tsuite = { let rsassa_pkcs1_v1_5_tsuite = { name: "RSASSA-PKCS1-v1_5 sign", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { @@ -354,7 +354,7 @@ let rsassa_pkcs1_v1_5_tsuite = { let rsa_pss_tsuite = { name: "RSA-PSS sign", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { @@ -397,7 +397,7 @@ let rsa_pss_tsuite = { let ecdsa_tsuite = { name: "ECDSA sign", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { diff --git a/test/webcrypto/verify.t.js b/test/webcrypto/verify.t.mjs similarity index 95% rename from test/webcrypto/verify.t.js rename to test/webcrypto/verify.t.mjs index df384724..70f608f3 100644 --- a/test/webcrypto/verify.t.js +++ b/test/webcrypto/verify.t.mjs @@ -53,7 +53,7 @@ function p(args, default_opts) { let hmac_tsuite = { name: "HMAC verify", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { @@ -78,7 +78,7 @@ let hmac_tsuite = { let rsassa_pkcs1_v1_5_tsuite = { name: "RSASSA-PKCS1-v1_5 verify", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { @@ -103,7 +103,7 @@ let rsassa_pkcs1_v1_5_tsuite = { let rsa_pss_tsuite = { name: "RSA-PSS verify", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { @@ -133,7 +133,7 @@ let rsa_pss_tsuite = { let ecdsa_tsuite = { name: "ECDSA verify", - skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()), + skip: () => (!has_buffer() || !has_webcrypto()), T: test, prepare_args: p, opts: { diff --git a/test/xml/saml_verify.t.js b/test/xml/saml_verify.t.mjs similarity index 99% rename from test/xml/saml_verify.t.js rename to test/xml/saml_verify.t.mjs index be6bae82..875fbd40 100644 --- a/test/xml/saml_verify.t.js +++ b/test/xml/saml_verify.t.mjs @@ -280,7 +280,7 @@ function p(args, default_opts) { let saml_verify_tsuite = { name: "SAML verify", - skip: () => (!has_njs() || !has_fs() || !has_webcrypto() || !has_xml()), + skip: () => (!has_njs() || !has_webcrypto() || !has_xml()), T: verify, prepare_args: p, opts: { From noreply at nginx.com Thu Dec 19 20:19:04 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:04 +0000 (UTC) Subject: [njs] QuickJS: added fs module. Message-ID: <20241219201904.D14F2489E5@pubserv1.nginx> details: https://github.com/nginx/njs/commit/1f8f9992d03e2865f354da3415f8a49931cf2fe8 branches: master commit: 1f8f9992d03e2865f354da3415f8a49931cf2fe8 user: Dmitry Volyntsev date: Wed, 4 Dec 2024 17:31:23 -0800 description: QuickJS: added fs module. --- auto/qjs_modules | 6 + external/qjs_fs_module.c | 3068 ++++++++++++++++++++++++++++++++++++++++++++++ src/qjs.h | 9 +- test/fs/methods.t.mjs | 6 +- 4 files changed, 3083 insertions(+), 6 deletions(-) diff --git a/auto/qjs_modules b/auto/qjs_modules index 0216d376..e74679d3 100644 --- a/auto/qjs_modules +++ b/auto/qjs_modules @@ -7,6 +7,12 @@ njs_module_srcs=src/qjs_buffer.c . auto/qjs_module +njs_module_name=qjs_fs_module +njs_module_incs= +njs_module_srcs=external/qjs_fs_module.c + +. auto/qjs_module + if [ $NJS_ZLIB = YES -a $NJS_HAVE_ZLIB = YES ]; then njs_module_name=qjs_zlib_module njs_module_incs= diff --git a/external/qjs_fs_module.c b/external/qjs_fs_module.c new file mode 100644 index 00000000..fc2222ff --- /dev/null +++ b/external/qjs_fs_module.c @@ -0,0 +1,3068 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) F5, Inc. + */ + +#include +#include + +#include +#include + + +#if (NJS_SOLARIS) + +#define DT_DIR 0 +#define DT_REG 1 +#define DT_CHR 2 +#define DT_LNK 3 +#define DT_BLK 4 +#define DT_FIFO 5 +#define DT_SOCK 6 +#define QJS_DT_INVALID -1 + +#define qjs_dentry_type(_dentry) \ + (QJS_DT_INVALID) + +#else + +#define QJS_DT_INVALID -1 + +#define qjs_dentry_type(_dentry) \ + ((_dentry)->d_type) + +#endif + + +#define qjs_fs_magic(calltype, mode) \ + (((mode) << 2) | calltype) + +#define qjs_fs_magic2(field, type) \ + (((type) << 4) | field) + + +typedef enum { + QJS_FS_DIRECT, + QJS_FS_PROMISE, + QJS_FS_CALLBACK, +} qjs_fs_calltype_t; + + +typedef enum { + QJS_FTW_PHYS = 1, + QJS_FTW_MOUNT = 2, + QJS_FTW_DEPTH = 8, +} qjs_ftw_flags_t; + + +typedef enum { + QJS_FTW_F, + QJS_FTW_D, + QJS_FTW_DNR, + QJS_FTW_NS, + QJS_FTW_SL, + QJS_FTW_DP, + QJS_FTW_SLN, +} qjs_ftw_type_t; + + +typedef enum { + QJS_FS_TRUNC, + QJS_FS_APPEND, +} qjs_fs_writemode_t; + + +typedef enum { + QJS_FS_STAT, + QJS_FS_LSTAT, + QJS_FS_FSTAT, +} njs_fs_statmode_t; + + +typedef struct { + long tv_sec; + long tv_nsec; +} qjs_timespec_t; + + +typedef struct { + uint64_t st_dev; + uint64_t st_mode; + uint64_t st_nlink; + uint64_t st_uid; + uint64_t st_gid; + uint64_t st_rdev; + uint64_t st_ino; + uint64_t st_size; + uint64_t st_blksize; + uint64_t st_blocks; + qjs_timespec_t st_atim; + qjs_timespec_t st_mtim; + qjs_timespec_t st_ctim; + qjs_timespec_t st_birthtim; +} qjs_stat_t; + + +typedef enum { + QJS_FS_STAT_DEV, + QJS_FS_STAT_INO, + QJS_FS_STAT_MODE, + QJS_FS_STAT_NLINK, + QJS_FS_STAT_UID, + QJS_FS_STAT_GID, + QJS_FS_STAT_RDEV, + QJS_FS_STAT_SIZE, + QJS_FS_STAT_BLKSIZE, + QJS_FS_STAT_BLOCKS, + QJS_FS_STAT_ATIME, + QJS_FS_STAT_BIRTHTIME, + QJS_FS_STAT_CTIME, + QJS_FS_STAT_MTIME, +} qjs_stat_prop_t; + + +typedef struct { + njs_str_t name; + int value; +} qjs_fs_entry_t; + + +typedef int (*qjs_file_tree_walk_cb_t)(const char *, const struct stat *, + qjs_ftw_type_t); + + +static JSValue qjs_fs_access(JSContext *cx, JSValueConst this_val, + int argc, JSValueConst *argv, int calltype); +static JSValue qjs_fs_exists_sync(JSContext *cx, JSValueConst this_val, + int argc,JSValueConst *argv); +static JSValue qjs_fs_close(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype); +static JSValue qjs_fs_mkdir(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype); +static JSValue qjs_fs_open(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype); +static JSValue qjs_fs_read(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype); +static JSValue qjs_fs_read_file(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype); +static JSValue qjs_fs_readlink(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype); +static JSValue qjs_fs_readdir(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype); +static JSValue qjs_fs_realpath(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype); +static JSValue qjs_fs_rename(JSContext *cx, JSValueConst this_val, + int argc, JSValueConst *argv, int calltype); +static JSValue qjs_fs_rmdir(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype); +static JSValue qjs_fs_stat(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int magic); +static JSValue qjs_fs_symlink(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype); +static JSValue qjs_fs_write(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype); +static JSValue qjs_fs_write_file(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int magic); +static JSValue qjs_fs_unlink(JSContext *cx, JSValueConst this_val, + int argc, JSValueConst *argv, int calltype); + +static JSValue qjs_fs_stats_to_string_tag(JSContext *cx, JSValueConst this_val); +static JSValue qjs_fs_stats_test(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int testtype); +static int qjs_fs_stats_get_own_property(JSContext *cx, + JSPropertyDescriptor *pdesc, JSValueConst obj, JSAtom prop); +static int qjs_fs_stats_get_own_property_names(JSContext *cx, + JSPropertyEnum **ptab, uint32_t *plen, JSValueConst obj); +static void qjs_fs_stats_finalizer(JSRuntime *rt, JSValue val); + +static JSValue qjs_fs_dirent_to_string_tag(JSContext *cx, + JSValueConst this_val); +static JSValue qjs_fs_dirent_ctor(JSContext *cx, JSValueConst new_target, + int argc, JSValueConst *argv); +static JSValue qjs_fs_dirent_test(JSContext *cx, JSValueConst this_val, + int argc, JSValueConst *argv, int testtype); + +static JSValue qjs_fs_filehandle_to_string_tag(JSContext *cx, + JSValueConst this_val); +static JSValue qjs_fs_filehandle_fd(JSContext *cx, JSValueConst this_val); +static JSValue qjs_fs_filehandle_value_of(JSContext *cx, JSValueConst this_val, + int argc, JSValueConst *argv); +static void qjs_fs_filehandle_finalizer(JSRuntime *rt, JSValue val); + +static char *qjs_fs_path(JSContext *cx, char storage[NJS_MAX_PATH + 1], + JSValue src, const char *prop_name); +static JSValue qjs_fs_result(JSContext *cx, JSValue result, int calltype, + JSValue callback); +static JSValue qjs_fs_error(JSContext *cx, const char *syscall, + const char *description, const char *path, int errn); +static JSValue qjs_fs_encode(JSContext *cx, + const qjs_buffer_encoding_t *encoding, njs_str_t *str); +static int qjs_fs_flags(JSContext *cx, JSValue value, int default_flags); +static mode_t qjs_fs_mode(JSContext *cx, JSValue value, mode_t default_mode); +static JSModuleDef *qjs_fs_init(JSContext *cx, const char *name); + + +static qjs_fs_entry_t qjs_flags_table[] = { + { njs_str("a"), O_APPEND | O_CREAT | O_WRONLY }, + { njs_str("a+"), O_APPEND | O_CREAT | O_RDWR }, + { njs_str("as"), O_APPEND | O_CREAT | O_SYNC | O_WRONLY }, + { njs_str("as+"), O_APPEND | O_CREAT | O_RDWR | O_SYNC }, + { njs_str("ax"), O_APPEND | O_CREAT | O_EXCL | O_WRONLY }, + { njs_str("ax+"), O_APPEND | O_CREAT | O_EXCL | O_RDWR }, + { njs_str("r"), O_RDONLY }, + { njs_str("r+"), O_RDWR }, + { njs_str("rs+"), O_RDWR | O_SYNC }, + { njs_str("w"), O_CREAT | O_TRUNC | O_WRONLY }, + { njs_str("w+"), O_CREAT | O_TRUNC | O_RDWR }, + { njs_str("wx"), O_CREAT | O_TRUNC | O_EXCL | O_WRONLY }, + { njs_str("wx+"), O_CREAT | O_TRUNC | O_EXCL | O_RDWR }, + { njs_null_str, 0 } +}; + + +static const JSCFunctionListEntry qjs_fs_stats_proto[] = { + JS_CGETSET_DEF("[Symbol.toStringTag]", qjs_fs_stats_to_string_tag, NULL), + JS_CFUNC_MAGIC_DEF("isBlockDevice", 0, qjs_fs_stats_test, DT_BLK), + JS_CFUNC_MAGIC_DEF("isCharacterDevice", 0, qjs_fs_stats_test, DT_CHR), + JS_CFUNC_MAGIC_DEF("isDirectory", 0, qjs_fs_stats_test, DT_DIR), + JS_CFUNC_MAGIC_DEF("isFIFO", 0, qjs_fs_stats_test, DT_FIFO), + JS_CFUNC_MAGIC_DEF("isFile", 0, qjs_fs_stats_test, DT_REG), + JS_CFUNC_MAGIC_DEF("isSocket", 0, qjs_fs_stats_test, DT_SOCK), + JS_CFUNC_MAGIC_DEF("isSymbolicLink", 0, qjs_fs_stats_test, DT_LNK), +}; + + +static const JSCFunctionListEntry qjs_fs_dirent_proto[] = { + JS_CGETSET_DEF("[Symbol.toStringTag]", qjs_fs_dirent_to_string_tag, NULL), + JS_CFUNC_MAGIC_DEF("isBlockDevice", 0, qjs_fs_dirent_test, DT_BLK), + JS_CFUNC_MAGIC_DEF("isCharacterDevice", 0, qjs_fs_dirent_test, DT_CHR), + JS_CFUNC_MAGIC_DEF("isDirectory", 0, qjs_fs_dirent_test, DT_DIR), + JS_CFUNC_MAGIC_DEF("isFIFO", 0, qjs_fs_dirent_test, DT_FIFO), + JS_CFUNC_MAGIC_DEF("isFile", 0, qjs_fs_dirent_test, DT_REG), + JS_CFUNC_MAGIC_DEF("isSocket", 0, qjs_fs_dirent_test, DT_SOCK), + JS_CFUNC_MAGIC_DEF("isSymbolicLink", 0, qjs_fs_dirent_test, DT_LNK), + JS_CFUNC_SPECIAL_DEF("constructor", 1, constructor, qjs_fs_dirent_ctor), +}; + + +static const JSCFunctionListEntry qjs_fs_filehandle_proto[] = { + JS_CGETSET_DEF("[Symbol.toStringTag]", qjs_fs_filehandle_to_string_tag, + NULL), + JS_CFUNC_MAGIC_DEF("close", 0, qjs_fs_close, QJS_FS_PROMISE), + JS_CGETSET_DEF("fd", qjs_fs_filehandle_fd, NULL), + JS_CFUNC_MAGIC_DEF("stat", 4, qjs_fs_stat, + qjs_fs_magic(QJS_FS_PROMISE, QJS_FS_FSTAT)), + JS_CFUNC_MAGIC_DEF("read", 4, qjs_fs_read, QJS_FS_PROMISE), + JS_CFUNC_DEF("valueOf", 0, qjs_fs_filehandle_value_of), + JS_CFUNC_MAGIC_DEF("write", 4, qjs_fs_write, QJS_FS_PROMISE), +}; + + +static const JSCFunctionListEntry qjs_fs_constants[] = { + JS_PROP_INT32_DEF("F_OK", F_OK, JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("R_OK", R_OK, JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("W_OK", W_OK, JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("X_OK", X_OK, JS_PROP_ENUMERABLE), +}; + + +static const JSCFunctionListEntry qjs_fs_promises[] = { + JS_CFUNC_MAGIC_DEF("access", 2, qjs_fs_access, QJS_FS_PROMISE), + JS_CFUNC_MAGIC_DEF("appendFile", 3, qjs_fs_write_file, + qjs_fs_magic(QJS_FS_PROMISE, QJS_FS_APPEND)), + JS_CFUNC_MAGIC_DEF("fstat", 2, qjs_fs_stat, + qjs_fs_magic(QJS_FS_PROMISE, QJS_FS_FSTAT)), + JS_CFUNC_MAGIC_DEF("lstat", 2, qjs_fs_stat, + qjs_fs_magic(QJS_FS_PROMISE, QJS_FS_LSTAT)), + JS_CFUNC_MAGIC_DEF("mkdir", 2, qjs_fs_mkdir, QJS_FS_PROMISE), + JS_CFUNC_MAGIC_DEF("open", 3, qjs_fs_open, QJS_FS_PROMISE), + JS_CFUNC_MAGIC_DEF("readFile", 2, qjs_fs_read_file, QJS_FS_PROMISE), + JS_CFUNC_MAGIC_DEF("realpath", 2, qjs_fs_realpath, QJS_FS_PROMISE), + JS_CFUNC_MAGIC_DEF("readdir", 2, qjs_fs_readdir, QJS_FS_PROMISE), + JS_CFUNC_MAGIC_DEF("readlink", 2, qjs_fs_readlink, QJS_FS_PROMISE), + JS_CFUNC_MAGIC_DEF("rename", 2, qjs_fs_rename, QJS_FS_PROMISE), + JS_CFUNC_MAGIC_DEF("rmdir", 2, qjs_fs_rmdir, QJS_FS_PROMISE), + JS_CFUNC_MAGIC_DEF("stat", 2, qjs_fs_stat, + qjs_fs_magic(QJS_FS_PROMISE, QJS_FS_STAT)), + JS_CFUNC_MAGIC_DEF("symlink", 3, qjs_fs_symlink, QJS_FS_PROMISE), + JS_CFUNC_MAGIC_DEF("writeFile", 3, qjs_fs_write_file, + qjs_fs_magic(QJS_FS_PROMISE, QJS_FS_TRUNC)), + JS_CFUNC_MAGIC_DEF("unlink", 1, qjs_fs_unlink, QJS_FS_PROMISE), +}; + + +static const JSCFunctionListEntry qjs_fs_export[] = { + JS_OBJECT_DEF("constants", + qjs_fs_constants, + njs_nitems(qjs_fs_constants), + JS_PROP_CONFIGURABLE), + JS_OBJECT_DEF("promises", + qjs_fs_promises, + njs_nitems(qjs_fs_promises), + JS_PROP_CONFIGURABLE), + JS_CFUNC_MAGIC_DEF("access", 3, qjs_fs_access, QJS_FS_CALLBACK), + JS_CFUNC_MAGIC_DEF("accessSync", 2, qjs_fs_access, QJS_FS_DIRECT), + JS_CFUNC_MAGIC_DEF("appendFile", 4, qjs_fs_write_file, + qjs_fs_magic(QJS_FS_CALLBACK, QJS_FS_APPEND)), + JS_CFUNC_MAGIC_DEF("appendFileSync", 3, qjs_fs_write_file, + qjs_fs_magic(QJS_FS_DIRECT, QJS_FS_APPEND)), + JS_CFUNC_MAGIC_DEF("closeSync", 1, qjs_fs_close, QJS_FS_DIRECT), + JS_CFUNC_SPECIAL_DEF("Dirent", 1, constructor, qjs_fs_dirent_ctor), + JS_CFUNC_DEF("existsSync", 1, qjs_fs_exists_sync), + JS_CFUNC_MAGIC_DEF("fstatSync", 2, qjs_fs_stat, + qjs_fs_magic(QJS_FS_DIRECT, QJS_FS_FSTAT)), + JS_CFUNC_MAGIC_DEF("lstat", 3, qjs_fs_stat, + qjs_fs_magic(QJS_FS_CALLBACK, QJS_FS_LSTAT)), + JS_CFUNC_MAGIC_DEF("lstatSync", 2, qjs_fs_stat, + qjs_fs_magic(QJS_FS_DIRECT, QJS_FS_LSTAT)), + JS_CFUNC_MAGIC_DEF("mkdir", 3, qjs_fs_mkdir, QJS_FS_CALLBACK), + JS_CFUNC_MAGIC_DEF("mkdirSync", 2, qjs_fs_mkdir, QJS_FS_DIRECT), + JS_CFUNC_MAGIC_DEF("openSync", 3, qjs_fs_open, QJS_FS_DIRECT), + JS_CFUNC_MAGIC_DEF("readSync", 5, qjs_fs_read, QJS_FS_DIRECT), + JS_CFUNC_MAGIC_DEF("readFile", 3, qjs_fs_read_file, QJS_FS_CALLBACK), + JS_CFUNC_MAGIC_DEF("readFileSync", 2, qjs_fs_read_file, QJS_FS_DIRECT), + JS_CFUNC_MAGIC_DEF("realpath", 3, qjs_fs_realpath, QJS_FS_CALLBACK), + JS_CFUNC_MAGIC_DEF("realpathSync", 2, qjs_fs_realpath, QJS_FS_DIRECT), + JS_CFUNC_MAGIC_DEF("readdir", 3, qjs_fs_readdir, QJS_FS_CALLBACK), + JS_CFUNC_MAGIC_DEF("readdirSync", 2, qjs_fs_readdir, QJS_FS_DIRECT), + JS_CFUNC_MAGIC_DEF("readlink", 3, qjs_fs_readlink, QJS_FS_CALLBACK), + JS_CFUNC_MAGIC_DEF("readlinkSync", 2, qjs_fs_readlink, QJS_FS_DIRECT), + JS_CFUNC_MAGIC_DEF("rename", 3, qjs_fs_rename, QJS_FS_CALLBACK), + JS_CFUNC_MAGIC_DEF("renameSync", 2, qjs_fs_rename, QJS_FS_DIRECT), + JS_CFUNC_MAGIC_DEF("rmdir", 3, qjs_fs_rmdir, QJS_FS_CALLBACK), + JS_CFUNC_MAGIC_DEF("rmdirSync", 2, qjs_fs_rmdir, QJS_FS_DIRECT), + JS_CFUNC_MAGIC_DEF("stat", 3, qjs_fs_stat, + qjs_fs_magic(QJS_FS_CALLBACK, QJS_FS_STAT)), + JS_CFUNC_MAGIC_DEF("statSync", 2, qjs_fs_stat, + qjs_fs_magic(QJS_FS_DIRECT, QJS_FS_STAT)), + JS_CFUNC_MAGIC_DEF("symlink", 4, qjs_fs_symlink, QJS_FS_CALLBACK), + JS_CFUNC_MAGIC_DEF("symlinkSync", 3, qjs_fs_symlink, QJS_FS_DIRECT), + JS_CFUNC_MAGIC_DEF("writeSync", 5, qjs_fs_write, QJS_FS_DIRECT), + JS_CFUNC_MAGIC_DEF("writeFile", 4, qjs_fs_write_file, + qjs_fs_magic(QJS_FS_CALLBACK, QJS_FS_TRUNC)), + JS_CFUNC_MAGIC_DEF("writeFileSync", 3, qjs_fs_write_file, + qjs_fs_magic(QJS_FS_DIRECT, QJS_FS_TRUNC)), + JS_CFUNC_MAGIC_DEF("unlink", 2, qjs_fs_unlink, QJS_FS_CALLBACK), + JS_CFUNC_MAGIC_DEF("unlinkSync", 1, qjs_fs_unlink, QJS_FS_DIRECT), +}; + + +static JSClassDef qjs_fs_stats_class = { + "Stats", + .finalizer = qjs_fs_stats_finalizer, + .exotic = & (JSClassExoticMethods) { + .get_own_property = qjs_fs_stats_get_own_property, + .get_own_property_names = qjs_fs_stats_get_own_property_names, + }, +}; + + +static JSClassDef qjs_fs_filehandle_class = { + "FileHandle", + .finalizer = qjs_fs_filehandle_finalizer, +}; + + +qjs_module_t qjs_fs_module = { + .name = "fs", + .init = qjs_fs_init, +}; + + +static JSValue +qjs_fs_access(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype) +{ + int md, ret; + JSValue callback, mode, result; + const char *path; + char path_buf[NJS_MAX_PATH + 1]; + + path = qjs_fs_path(cx, path_buf, argv[0], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + mode = argv[1]; + callback = JS_UNDEFINED; + + if (calltype == QJS_FS_CALLBACK) { + if (argc > 0) { + callback = argv[njs_min(argc - 1, 2)]; + } + + if (!JS_IsFunction(cx, callback)) { + JS_ThrowTypeError(cx, "\"callback\" must be a function"); + return JS_EXCEPTION; + } + + if (JS_SameValue(cx, mode, callback)) { + mode = JS_UNDEFINED; + } + } + + if (JS_IsNumber(mode)) { + md = JS_VALUE_GET_INT(mode); + + } else if (JS_IsUndefined(mode)) { + md = F_OK; + + } else { + JS_ThrowTypeError(cx, "\"mode\" must be a number"); + return JS_EXCEPTION; + } + + result = JS_UNDEFINED; + + ret = access(path, md); + if (ret != 0) { + result = qjs_fs_error(cx, "access", strerror(errno), path, errno); + } + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, callback); +} + + +static JSValue +qjs_fs_exists_sync(JSContext *cx, JSValueConst this_val, int nargs, + JSValueConst *args) +{ + const char *path; + char path_buf[NJS_MAX_PATH + 1]; + + path = qjs_fs_path(cx, path_buf, args[0], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + return (access(path, F_OK) == 0) ? JS_TRUE : JS_FALSE; +} + + +static JSValue +qjs_fs_close(JSContext *cx, JSValueConst this_val, int nargs, + JSValueConst *args, int calltype) +{ + int fd; + JSValue result; + + if (calltype == QJS_FS_DIRECT) { + if (JS_ToInt32(cx, &fd, args[0]) < 0) { + return JS_EXCEPTION; + } + + } else { + fd = (intptr_t) JS_GetOpaque(this_val, QJS_CORE_CLASS_ID_FS_FILEHANDLE); + if (fd == -1) { + JS_ThrowTypeError(cx, "file was already closed"); + return JS_EXCEPTION; + } + + JS_SetOpaque(this_val, (void *) -1); + } + + result = JS_UNDEFINED; + + if (close(fd) != 0) { + result = qjs_fs_error(cx, "close", strerror(errno), NULL, errno); + goto done; + } + +done: + + return qjs_fs_result(cx, result, calltype, JS_UNDEFINED); +} + + +static JSValue +qjs_fs_make_path(JSContext *cx, char *path, mode_t md, int recursive) +{ + int err; + njs_int_t ret; + const char *p, *prev, *end; + struct stat sb; + + end = path + strlen(path); + + if (!recursive) { + ret = mkdir(path, md); + if (ret != 0) { + err = errno; + goto failed; + } + + return JS_UNDEFINED; + } + + p = path; + prev = p; + + for ( ;; ) { + p = strchr(prev + 1, '/'); + if (p == NULL) { + p = end; + } + + if ((p - path) > NJS_MAX_PATH) { + JS_ThrowInternalError(cx, "too large path"); + return JS_EXCEPTION; + } + + path[p - path] = '\0'; + + ret = mkdir(path, md); + err = errno; + + switch (ret) { + case 0: + break; + + case EACCES: + case ENOTDIR: + case EPERM: + goto failed; + + case EEXIST: + default: + ret = stat(path, &sb); + if (ret == 0) { + if (!S_ISDIR(sb.st_mode)) { + err = ENOTDIR; + goto failed; + } + + break; + } + + goto failed; + } + + if (p == end) { + break; + } + + path[p - path] = '/'; + prev = p; + } + + return JS_UNDEFINED; + +failed: + + return qjs_fs_error(cx, "mkdir", strerror(err), path, err); +} + + +static JSValue +qjs_fs_mkdir(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype) +{ + int recursive; + char *path; + mode_t md; + JSValue callback, v, options, result; + char path_buf[NJS_MAX_PATH + 1]; + + path = qjs_fs_path(cx, path_buf, argv[0], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + callback = JS_UNDEFINED; + options = argv[1]; + + if (calltype == QJS_FS_CALLBACK) { + if (argc > 0) { + callback = argv[njs_min(argc - 1, 2)]; + } + + if (!JS_IsFunction(cx, callback)) { + JS_ThrowTypeError(cx, "\"callback\" must be a function"); + return JS_EXCEPTION; + } + + if (JS_SameValue(cx, options, callback)) { + options = JS_UNDEFINED; + } + } + + md = 0777; + recursive = 0; + + if (JS_IsNumber(options)) { + md = JS_VALUE_GET_INT(options); + + } else if (!JS_IsUndefined(options)) { + if (!JS_IsObject(options)) { + JS_ThrowTypeError(cx, "Unknown options type (a number or object " + "required)"); + return JS_EXCEPTION; + } + + v = JS_GetPropertyStr(cx, options, "mode"); + if (!JS_IsUndefined(v) && !JS_IsException(v)) { + md = qjs_fs_mode(cx, v, 0777); + if (md == (mode_t) -1) { + JS_FreeValue(cx, v); + return JS_EXCEPTION; + } + } + + v = JS_GetPropertyStr(cx, options, "recursive"); + if (!JS_IsUndefined(v) && !JS_IsException(v)) { + recursive = JS_ToBool(cx, v); + } + } + + result = qjs_fs_make_path(cx, path, md, recursive); + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, callback); +} + + +static JSValue +qjs_fs_open(JSContext *cx, JSValueConst this_val, int argc, JSValueConst *argv, + int calltype) +{ + int fd, flags; + mode_t md; + JSValue result; + const char *path; + char path_buf[NJS_MAX_PATH + 1]; + + path = qjs_fs_path(cx, path_buf, argv[0], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + flags = qjs_fs_flags(cx, argv[1], O_RDONLY); + if (flags == -1) { + return JS_EXCEPTION; + } + + md = qjs_fs_mode(cx, argv[2], 0666); + if (md == (mode_t) -1) { + return JS_EXCEPTION; + } + + fd = open(path, flags, md); + if (fd < 0) { + result = qjs_fs_error(cx, "open", strerror(errno), path, errno); + goto done; + } + + if (calltype == QJS_FS_DIRECT) { + /* Leaks fd if user does not close it. */ + result = JS_NewInt32(cx, fd); + + } else { + result = JS_NewObjectClass(cx, QJS_CORE_CLASS_ID_FS_FILEHANDLE); + if (JS_IsException(result)) { + (void) close(fd); + goto done; + } + + JS_SetOpaque(result, (void *) (intptr_t) fd); + } + +done: + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, JS_UNDEFINED); +} + + +static JSValue +qjs_fs_fd_read(JSContext *cx, int fd, njs_str_t *data) +{ + u_char *p, *end, *start; + size_t size; + ssize_t n; + + size = data->length; + + if (size == 0) { + size = 4096; + } + + data->start = js_malloc(cx, size); + if (data->start == NULL) { + JS_ThrowOutOfMemory(cx); + return JS_EXCEPTION; + } + + p = data->start; + end = p + size; + + for ( ;; ) { + n = read(fd, p, end - p); + + if (n < 0) { + js_free(cx, data->start); + return JS_FALSE; + } + + p += n; + + if (n == 0) { + break; + } + + if (end - p < 2048) { + size *= 2; + + start = js_realloc(cx, data->start, size); + if (start == NULL) { + js_free(cx, data->start); + JS_ThrowOutOfMemory(cx); + return JS_EXCEPTION; + } + + p = start + (p - data->start); + end = start + size; + data->start = start; + } + } + + data->length = p - data->start; + + return JS_TRUE; +} + + +static JSValue +qjs_fs_read(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype) +{ + int fd, fd_offset; + int64_t length, pos, offset; + ssize_t n; + JSValue ret, result; + njs_str_t buffer; + + /* + * fh.read(buffer, offset[, length[, position]]) + * fs.readSync(fd, buffer, offset[, length[, position]]) + */ + + if (calltype == QJS_FS_DIRECT) { + fd_offset = 0; + if (JS_ToInt32(cx, &fd, argv[0]) < 0) { + return JS_EXCEPTION; + } + + } else { + fd_offset = -1; + if (JS_ToInt32(cx, &fd, this_val) < 0) { + return JS_EXCEPTION; + } + } + + ret = qjs_typed_array_data(cx, argv[fd_offset + 1], &buffer); + if (JS_IsException(ret)) { + return ret; + } + + if (JS_ToInt64(cx, &offset, argv[fd_offset + 2]) < 0) { + return JS_EXCEPTION; + } + + if (offset < 0 || (size_t) offset > buffer.length) { + JS_ThrowRangeError(cx, "offset is out of range (must be <= %zu)", + buffer.length); + return JS_EXCEPTION; + } + + buffer.length -= offset; + buffer.start += offset; + + if (!JS_IsUndefined(argv[fd_offset + 3])) { + if (JS_ToInt64(cx, &length, argv[fd_offset + 3]) < 0) { + return JS_EXCEPTION; + } + + if (length < 0 || (size_t) length > buffer.length) { + JS_ThrowRangeError(cx, "length is out of range (must be <= %zu)", + buffer.length); + return JS_EXCEPTION; + } + + buffer.length = length; + } + + pos = -1; + + if (!JS_IsNullOrUndefined(argv[fd_offset + 4])) { + if (JS_ToInt64(cx, &pos, argv[fd_offset + 4]) < 0) { + return JS_EXCEPTION; + } + } + + if (pos == -1) { + n = read(fd, buffer.start, buffer.length); + + } else { + n = pread(fd, buffer.start, buffer.length, pos); + } + + if (n == -1) { + result = qjs_fs_error(cx, "read", strerror(errno), NULL, errno); + goto done; + } + + if (calltype == QJS_FS_PROMISE) { + result = JS_NewObject(cx); + if (JS_IsException(result)) { + goto done; + } + + if (JS_DefinePropertyValueStr(cx, result, "bytesRead", + JS_NewInt32(cx, n), JS_PROP_ENUMERABLE) + < 0) + { + JS_FreeValue(cx, result); + result = JS_EXCEPTION; + goto done; + } + + if (JS_DefinePropertyValueStr(cx, result, "buffer", + JS_DupValue(cx, argv[fd_offset + 1]), + JS_PROP_ENUMERABLE) + < 0) + { + JS_FreeValue(cx, result); + result = JS_EXCEPTION; + goto done; + } + + } else { + result = JS_NewInt32(cx, n); + } + +done: + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, JS_UNDEFINED); +} + + +static JSValue +qjs_fs_read_file(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype) +{ + int fd, flags; + njs_str_t str; + JSValue callback, v, encode, options, result; + const char *path; + struct stat sb; + const qjs_buffer_encoding_t *encoding; + char path_buf[NJS_MAX_PATH + 1]; + + path = qjs_fs_path(cx, path_buf, argv[0], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + flags = O_RDONLY; + + options = argv[1]; + encode = JS_UNDEFINED; + callback = JS_UNDEFINED; + + if (calltype == QJS_FS_CALLBACK) { + if (argc > 0) { + callback = argv[njs_min(argc - 1, 2)]; + } + + if (!JS_IsFunction(cx, callback)) { + JS_ThrowTypeError(cx, "\"callback\" must be a function"); + return JS_EXCEPTION; + } + + if (JS_SameValue(cx, options, callback)) { + options = JS_UNDEFINED; + } + } + + if (JS_IsString(options)) { + encode = JS_DupValue(cx, options); + + } else if (!JS_IsUndefined(options)) { + if (!JS_IsObject(options)) { + JS_ThrowTypeError(cx, "Unknown options type (a string or object " + "required)"); + return JS_EXCEPTION; + } + + v = JS_GetPropertyStr(cx, options, "flag"); + if (!JS_IsUndefined(v) && !JS_IsException(v)) { + flags = qjs_fs_flags(cx, v, O_RDONLY); + if (flags == -1) { + JS_FreeValue(cx, v); + return JS_EXCEPTION; + } + } + + v = JS_GetPropertyStr(cx, options, "encoding"); + if (!JS_IsUndefined(v) && !JS_IsException(v)) { + encode = v; + } + } + + encoding = NULL; + if (!JS_IsUndefined(encode)) { + encoding = qjs_buffer_encoding(cx, encode, 1); + if (encoding == NULL) { + JS_FreeValue(cx, encode); + return JS_EXCEPTION; + } + } + + JS_FreeValue(cx, encode); + + fd = open(path, flags); + if (fd < 0) { + result = qjs_fs_error(cx, "open", strerror(errno), path, errno); + goto done; + } + + if (fstat(fd, &sb) == -1) { + result = qjs_fs_error(cx, "stat", strerror(errno), path, errno); + goto done; + } + + if (!S_ISREG(sb.st_mode)) { + result = qjs_fs_error(cx, "stat", "File is not regular", path, 0); + goto done; + } + + str.start = NULL; + str.length = sb.st_size; + + v = qjs_fs_fd_read(cx, fd, &str); + if (!JS_SameValue(cx, v, JS_TRUE)) { + if (JS_IsException(v)) { + result = JS_EXCEPTION; + + } else { + result = qjs_fs_error(cx, "read", strerror(errno), path, errno); + } + + goto done; + } + + result = qjs_fs_encode(cx, encoding, &str); + js_free(cx, str.start); + +done: + + if (fd != -1) { + (void) close(fd); + } + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, callback); +} + + +static JSValue +qjs_fs_readlink(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype) +{ + ssize_t n; + JSValue callback, v, result, encode, options; + njs_str_t str; + const char *path, *enc; + const qjs_buffer_encoding_t *encoding; + char path_buf[NJS_MAX_PATH + 1], + dst_buf[NJS_MAX_PATH + 1]; + + path = qjs_fs_path(cx, path_buf, argv[0], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + options = argv[1]; + encode = JS_UNDEFINED; + callback = JS_UNDEFINED; + + if (calltype == QJS_FS_CALLBACK) { + callback = argv[njs_min(argc - 1, 2)]; + + if (!JS_IsFunction(cx, callback)) { + JS_ThrowTypeError(cx, "\"callback\" must be a function"); + return JS_EXCEPTION; + } + + if (JS_SameValue(cx, options, callback)) { + options = JS_UNDEFINED; + } + } + + if (JS_IsString(options)) { + encode = JS_DupValue(cx, options); + + } else if (!JS_IsUndefined(options)) { + if (!JS_IsObject(options)) { + JS_ThrowTypeError(cx, "Unknown options type (a string or object " + "required)"); + return JS_EXCEPTION; + } + + v = JS_GetPropertyStr(cx, options, "encoding"); + if (!JS_IsUndefined(v) && !JS_IsException(v)) { + encode = v; + } + } + + encoding = NULL; + enc = JS_ToCString(cx, encode); + if (enc == NULL) { + JS_FreeValue(cx, encode); + return JS_EXCEPTION; + } + + if (strncmp(enc, "buffer", 6) != 0) { + encoding = qjs_buffer_encoding(cx, encode, 1); + if (encoding == NULL) { + JS_FreeCString(cx, enc); + JS_FreeValue(cx, encode); + return JS_EXCEPTION; + } + } + + JS_FreeCString(cx, enc); + JS_FreeValue(cx, encode); + + str.start = (u_char *) dst_buf; + n = readlink(path, dst_buf, sizeof(dst_buf) - 1); + if (n < 0) { + result = qjs_fs_error(cx, "readlink", strerror(errno), path, errno); + goto done; + } + + str.length = n; + + result = qjs_fs_encode(cx, encoding, &str); + +done: + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, callback); +} + + +static JSValue +qjs_fs_dirent_create(JSContext *cx, JSValueConst name, struct dirent *entry) +{ + JSValue obj; + + obj = JS_NewObjectClass(cx, QJS_CORE_CLASS_ID_FS_DIRENT); + if (JS_IsException(obj)) { + return JS_EXCEPTION; + } + + if (JS_DefinePropertyValueStr(cx, obj, "name", name, + JS_PROP_ENUMERABLE) < 0) + { + JS_FreeValue(cx, obj); + return JS_EXCEPTION; + } + + if (entry != NULL) { + if (JS_DefinePropertyValueStr(cx, obj, "type", + JS_NewInt32(cx, qjs_dentry_type(entry)), + 0) < 0) + { + JS_FreeValue(cx, obj); + return JS_EXCEPTION; + } + } + + return obj; +} + + +static JSValue +qjs_fs_dirent_ctor(JSContext *cx, JSValueConst new_target, int argc, + JSValueConst *argv) +{ + if (argc < 1) { + JS_ThrowTypeError(cx, "name is required"); + return JS_EXCEPTION; + } + + return qjs_fs_dirent_create(cx, JS_DupValue(cx, argv[0]), NULL); +} + + +static JSValue +qjs_fs_readdir(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype) +{ + DIR *dir; + int types, idx; + njs_str_t str; + JSValue callback, v, result, encode, options, ename; + const char *path, *enc; + struct dirent *entry; + const qjs_buffer_encoding_t *encoding; + char path_buf[NJS_MAX_PATH + 1]; + + path = qjs_fs_path(cx, path_buf, argv[0], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + types = 0; + options = argv[1]; + encode = JS_UNDEFINED; + callback = JS_UNDEFINED; + + if (calltype == QJS_FS_CALLBACK) { + if (argc > 0) { + callback = argv[njs_min(argc - 1, 2)]; + } + + if (!JS_IsFunction(cx, callback)) { + JS_ThrowTypeError(cx, "\"callback\" must be a function"); + return JS_EXCEPTION; + } + + if (JS_SameValue(cx, options, callback)) { + options = JS_UNDEFINED; + } + } + + if (JS_IsString(options)) { + encode = JS_DupValue(cx, options); + + } else if (!JS_IsUndefined(options)) { + if (!JS_IsObject(options)) { + JS_ThrowTypeError(cx, "Unknown options type (a string or object " + "required)"); + return JS_EXCEPTION; + } + + v = JS_GetPropertyStr(cx, options, "encoding"); + if (!JS_IsUndefined(v) && !JS_IsException(v)) { + encode = v; + } + + v = JS_GetPropertyStr(cx, options, "withFileTypes"); + if (!JS_IsUndefined(v) && !JS_IsException(v)) { + types = JS_ToBool(cx, v); + } + } + + encoding = NULL; + + enc = JS_ToCString(cx, encode); + if (enc == NULL) { + JS_FreeValue(cx, encode); + return JS_EXCEPTION; + } + + if (strncmp(enc, "buffer", 6) != 0) { + encoding = qjs_buffer_encoding(cx, encode, 1); + if (encoding == NULL) { + JS_FreeCString(cx, enc); + JS_FreeValue(cx, encode); + return JS_EXCEPTION; + } + } + + JS_FreeCString(cx, enc); + JS_FreeValue(cx, encode); + + idx = 0; + dir = opendir(path); + + if (dir == NULL) { + result = qjs_fs_error(cx, "opendir", strerror(errno), path, errno); + goto done; + } + + result = JS_NewArray(cx); + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + for ( ;; ) { + errno = 0; + entry = readdir(dir); + if (entry == NULL) { + if (errno != 0) { + JS_FreeValue(cx, result); + result = qjs_fs_error(cx, "readdir", strerror(errno), path, + errno); + } + + break; + } + + if (entry->d_name[0] == '.' && (entry->d_name[1] == '\0' + || (entry->d_name[1] == '.' && entry->d_name[2] == '\0'))) + { + continue; + } + + str.start = (u_char *) entry->d_name; + str.length = strlen((const char *) str.start); + + if (str.length == 0) { + continue; + } + + ename = qjs_fs_encode(cx, encoding, &str); + if (JS_IsException(ename)) { + JS_FreeValue(cx, result); + goto done; + } + + if (!types) { + if (JS_DefinePropertyValueUint32(cx, result, idx++, ename, 0) < 0) { + JS_FreeValue(cx, ename); + JS_FreeValue(cx, result); + goto done; + } + + } else { + v = qjs_fs_dirent_create(cx, ename, entry); + if (JS_IsException(v)) { + JS_FreeValue(cx, ename); + JS_FreeValue(cx, result); + goto done; + } + + if (JS_DefinePropertyValueUint32(cx, result, idx++, v, 0) < 0) { + JS_FreeValue(cx, ename); + JS_FreeValue(cx, result); + goto done; + } + } + } + +done: + + if (dir != NULL) { + (void) closedir(dir); + } + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, callback); +} + + + +static JSValue +qjs_fs_realpath(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype) +{ + JSValue callback, v, encode, options, result; + njs_str_t str; + const char *path, *enc; + const qjs_buffer_encoding_t *encoding; + char path_buf[NJS_MAX_PATH + 1], + dst_buf[NJS_MAX_PATH + 1]; + + path = qjs_fs_path(cx, path_buf, argv[0], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + options = argv[1]; + encode = JS_UNDEFINED; + callback = JS_UNDEFINED; + + if (calltype == QJS_FS_CALLBACK) { + if (argc > 0) { + callback = argv[njs_min(argc - 1, 2)]; + } + + if (!JS_IsFunction(cx, callback)) { + JS_ThrowTypeError(cx, "\"callback\" must be a function"); + return JS_EXCEPTION; + } + + if (JS_SameValue(cx, options, callback)) { + options = JS_UNDEFINED; + } + } + + if (JS_IsString(options)) { + encode = JS_DupValue(cx, options); + + } else if (!JS_IsUndefined(options)) { + if (!JS_IsObject(options)) { + JS_ThrowTypeError(cx, "Unknown options type (a string or object " + "required)"); + return JS_EXCEPTION; + } + + v = JS_GetPropertyStr(cx, options, "encoding"); + if (!JS_IsUndefined(v) && !JS_IsException(v)) { + encode = v; + } + } + + enc = JS_ToCString(cx, encode); + if (enc == NULL) { + JS_FreeValue(cx, encode); + return JS_EXCEPTION; + } + + encoding = NULL; + if (strncmp(enc, "buffer", 6) != 0) { + encoding = qjs_buffer_encoding(cx, encode, 1); + if (encoding == NULL) { + JS_FreeCString(cx, enc); + JS_FreeValue(cx, encode); + return JS_EXCEPTION; + } + } + + JS_FreeCString(cx, enc); + JS_FreeValue(cx, encode); + + str.start = (u_char *) realpath(path, dst_buf); + if (str.start == NULL) { + result = qjs_fs_error(cx, "realpath", strerror(errno), path, errno); + goto done; + } + + str.length = strlen((const char *) str.start); + + result = qjs_fs_encode(cx, encoding, &str); + +done: + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, callback); +} + + +static JSValue +qjs_fs_rename(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype) +{ + int ret; + JSValue callback, result; + const char *path, *newpath; + char path_buf[NJS_MAX_PATH + 1], + newpath_buf[NJS_MAX_PATH + 1]; + + path = qjs_fs_path(cx, path_buf, argv[0], "oldPath"); + if (path == NULL) { + return JS_EXCEPTION; + } + + newpath = qjs_fs_path(cx, newpath_buf, argv[1], "newPath"); + if (newpath == NULL) { + return JS_EXCEPTION; + } + + callback = JS_UNDEFINED; + + if (calltype == QJS_FS_CALLBACK) { + callback = argv[2]; + + if (!JS_IsFunction(cx, callback)) { + JS_ThrowTypeError(cx, "\"callback\" must be a function"); + return JS_EXCEPTION; + } + } + + result = JS_UNDEFINED; + + ret = rename(path, newpath); + if (ret != 0) { + result = qjs_fs_error(cx, "rename", strerror(errno), NULL, errno); + } + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, callback); +} + + +typedef struct qjs_ftw_trace_s qjs_ftw_trace_t; + +struct qjs_ftw_trace_s { + struct qjs_ftw_trace_s *chain; + dev_t dev; + ino_t ino; +}; + + +static int +qjs_ftw(char *path, qjs_file_tree_walk_cb_t cb, int fd_limit, + qjs_ftw_flags_t flags, qjs_ftw_trace_t *parent) +{ + int type, ret, dfd; + DIR *d; + size_t base, len, length; + const char *d_name; + struct stat st; + struct dirent *entry; + qjs_ftw_trace_t trace, *h; + + ret = (flags & QJS_FTW_PHYS) ? lstat(path, &st) : stat(path, &st); + + if (ret < 0) { + if (!(flags & QJS_FTW_PHYS) && errno == ENOENT && !lstat(path, &st)) { + type = QJS_FTW_SLN; + + } else if (errno != EACCES) { + return -1; + + } else { + type = QJS_FTW_NS; + } + + } else if (S_ISDIR(st.st_mode)) { + type = (flags & QJS_FTW_DEPTH) ? QJS_FTW_DP : QJS_FTW_D; + + } else if (S_ISLNK(st.st_mode)) { + type = (flags & QJS_FTW_PHYS) ? QJS_FTW_SL : QJS_FTW_SLN; + + } else { + type = QJS_FTW_F; + } + + if ((flags & QJS_FTW_MOUNT) && parent != NULL && st.st_dev != parent->dev) { + return 0; + } + + for (h = parent; h != NULL; h = h->chain) { + if (h->dev == st.st_dev && h->ino == st.st_ino) { + return 0; + } + } + + len = strlen(path); + base = len && (path[len - 1] == '/') ? len - 1 : len; + + trace.chain = parent; + trace.dev = st.st_dev; + trace.ino = st.st_ino; + + d = NULL; + dfd = -1; + + if (type == QJS_FTW_D || type == QJS_FTW_DP) { + dfd = open(path, O_RDONLY); + if (dfd < 0) { + if (errno != EACCES) { + return -1; + } + + type = QJS_FTW_DNR; + } + } + + if (!(flags & QJS_FTW_DEPTH)) { + ret = cb(path, &st, type); + if (ret != 0) { + goto done; + } + } + + if (type == QJS_FTW_D || type == QJS_FTW_DP) { + d = fdopendir(dfd); + if (d == NULL) { + ret = -1; + goto done; + } + + for ( ;; ) { + entry = readdir(d); + + if (entry == NULL) { + break; + } + + d_name = entry->d_name; + length = strlen(d_name); + + if ((length == 1 && d_name[0] == '.') + || (length == 2 && (d_name[0] == '.' && d_name[1] == '.'))) + { + continue; + } + + if (length >= (NJS_MAX_PATH - len)) { + errno = ENAMETOOLONG; + ret = -1; + goto done; + } + + path[base] = '/'; + memcpy(&path[base + 1], d_name, length + njs_length("\0")); + + if (fd_limit != 0) { + ret = qjs_ftw(path, cb, fd_limit - 1, flags, &trace); + if (ret != 0) { + goto done; + } + } + } + + (void) closedir(d); + d = NULL; + dfd = -1; + } + + path[len] = '\0'; + + if (flags & QJS_FTW_DEPTH) { + ret = cb(path, &st, type); + if (ret != 0) { + return ret; + } + } + + ret = 0; + +done: + + if (d != NULL) { + /* closedir() also closes underlying dfd. */ + (void) closedir(d); + + } else if (dfd >= 0) { + (void) close(dfd); + } + + return ret; +} + + +static int +qjs_file_tree_walk(const char *path, qjs_file_tree_walk_cb_t cb, int fd_limit, + qjs_ftw_flags_t flags) +{ + size_t len; + char pathbuf[NJS_MAX_PATH + 1]; + + len = strlen(path); + if (len > NJS_MAX_PATH) { + errno = ENAMETOOLONG; + return -1; + } + + memcpy(pathbuf, path, len + 1); + + return qjs_ftw(pathbuf, cb, fd_limit, flags, NULL); +} + + +static int +qjs_fs_rmtree_cb(const char *path, const struct stat *sb, qjs_ftw_type_t type) +{ + njs_int_t ret; + + ret = remove(path); + if (ret != 0) { + return NJS_ERROR; + } + + return NJS_OK; +} + + +static JSValue +qjs_fs_rmtree(JSContext *cx, const char *path, int recursive) +{ + njs_int_t ret; + const char *description; + + ret = rmdir(path); + if (ret == 0) { + return JS_UNDEFINED; + } + + description = strerror(errno); + + if (recursive && (errno == ENOTEMPTY || errno == EEXIST)) { + ret = qjs_file_tree_walk(path, qjs_fs_rmtree_cb, 16, + QJS_FTW_PHYS | QJS_FTW_MOUNT | QJS_FTW_DEPTH); + + if (ret == 0) { + return JS_UNDEFINED; + } + + description = strerror(errno); + } + + return qjs_fs_error(cx, "rmdir", description, path, errno); +} + + +static JSValue +qjs_fs_rmdir(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype) +{ + int recursive; + JSValue callback, v, options, result; + const char *path; + char path_buf[NJS_MAX_PATH + 1]; + + path = qjs_fs_path(cx, path_buf, argv[0], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + recursive = 0; + + options = argv[1]; + callback = JS_UNDEFINED; + + if (calltype == QJS_FS_CALLBACK) { + callback = argv[njs_min(argc - 1, 2)]; + + if (!JS_IsFunction(cx, callback)) { + JS_ThrowTypeError(cx, "\"callback\" must be a function"); + return JS_EXCEPTION; + } + + if (JS_SameValue(cx, options, callback)) { + options = JS_UNDEFINED; + } + } + + if (!JS_IsUndefined(options)) { + if (!JS_IsObject(options)) { + JS_ThrowTypeError(cx, "Unknown options type (an object required)"); + return JS_EXCEPTION; + } + + v = JS_GetPropertyStr(cx, options, "recursive"); + if (!JS_IsUndefined(v) && !JS_IsException(v)) { + recursive = JS_ToBool(cx, v); + } + } + + result = qjs_fs_rmtree(cx, path, recursive); + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, callback); +} + + +static void +qjs_fs_to_stat(qjs_stat_t *dst, struct stat *st) +{ + dst->st_dev = st->st_dev; + dst->st_mode = st->st_mode; + dst->st_nlink = st->st_nlink; + dst->st_uid = st->st_uid; + dst->st_gid = st->st_gid; + dst->st_rdev = st->st_rdev; + dst->st_ino = st->st_ino; + dst->st_size = st->st_size; + dst->st_blksize = st->st_blksize; + dst->st_blocks = st->st_blocks; + +#if (NJS_HAVE_STAT_ATIMESPEC) + + dst->st_atim.tv_sec = st->st_atimespec.tv_sec; + dst->st_atim.tv_nsec = st->st_atimespec.tv_nsec; + dst->st_mtim.tv_sec = st->st_mtimespec.tv_sec; + dst->st_mtim.tv_nsec = st->st_mtimespec.tv_nsec; + dst->st_ctim.tv_sec = st->st_ctimespec.tv_sec; + dst->st_ctim.tv_nsec = st->st_ctimespec.tv_nsec; + +#elif (NJS_HAVE_STAT_ATIM) + + dst->st_atim.tv_sec = st->st_atim.tv_sec; + dst->st_atim.tv_nsec = st->st_atim.tv_nsec; + dst->st_mtim.tv_sec = st->st_mtim.tv_sec; + dst->st_mtim.tv_nsec = st->st_mtim.tv_nsec; + dst->st_ctim.tv_sec = st->st_ctim.tv_sec; + dst->st_ctim.tv_nsec = st->st_ctim.tv_nsec; + +#if (NJS_HAVE_STAT_BIRTHTIM) + dst->st_birthtim.tv_sec = st->st_birthtim.tv_sec; + dst->st_birthtim.tv_nsec = st->st_birthtim.tv_nsec; +#elif (NJS_HAVE__STAT_BIRTHTIM) + dst->st_birthtim.tv_sec = st->__st_birthtim.tv_sec; + dst->st_birthtim.tv_nsec = st->__st_birthtim.tv_nsec; +#else + dst->st_birthtim.tv_sec = st->st_ctim.tv_sec; + dst->st_birthtim.tv_nsec = st->st_ctim.tv_nsec; +#endif + +#else + + dst->st_atim.tv_sec = st->st_atime; + dst->st_atim.tv_nsec = 0; + dst->st_mtim.tv_sec = st->st_mtime; + dst->st_mtim.tv_nsec = 0; + dst->st_ctim.tv_sec = st->st_ctime; + dst->st_ctim.tv_nsec = 0; + dst->st_birthtim.tv_sec = st->st_ctime; + dst->st_birthtim.tv_nsec = 0; + +#endif +} + + +static JSValue +qjs_fs_stats_create(JSContext *cx, struct stat *st) +{ + JSValue obj; + qjs_stat_t *stat; + + stat = js_malloc(cx, sizeof(qjs_stat_t)); + if (stat == NULL) { + JS_ThrowOutOfMemory(cx); + return JS_EXCEPTION; + } + + qjs_fs_to_stat(stat, st); + + obj = JS_NewObjectClass(cx, QJS_CORE_CLASS_ID_FS_STATS); + if (JS_IsException(obj)) { + js_free(cx, stat); + return JS_EXCEPTION; + } + + JS_SetOpaque(obj, stat); + + return obj; +} + + +static JSValue +qjs_fs_stat(JSContext *cx, JSValueConst this_val, int argc, JSValueConst *argv, + int magic) +{ + int ret, fd, fd_offset, throw, calltype; + JSValue callback, result, options, value; + const char *path; + struct stat sb; + char path_buf[NJS_MAX_PATH + 1]; + + fd = -1; + path = NULL; + calltype = magic & 3; + + if ((magic >> 2) != QJS_FS_FSTAT) { + path = qjs_fs_path(cx, path_buf, argv[0], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + options = argv[1]; + + } else { + if (calltype == QJS_FS_DIRECT) { + fd_offset = 0; + if (JS_ToInt32(cx, &fd, argv[fd_offset]) < 0) { + return JS_EXCEPTION; + } + + } else { + fd_offset = -1; + if (JS_ToInt32(cx, &fd, this_val) < 0) { + return JS_EXCEPTION; + } + } + + options = argv[fd_offset + 1]; + } + + callback = JS_UNDEFINED; + + if (calltype == QJS_FS_CALLBACK) { + if (argc > 0) { + callback = argv[njs_min(argc - 1, 2)]; + } + + if (!JS_IsFunction(cx, callback)) { + JS_ThrowTypeError(cx, "\"callback\" must be a function"); + return JS_EXCEPTION; + } + + if (JS_SameValue(cx, options, callback)) { + options = JS_UNDEFINED; + } + } + + throw = 1; + + if (!JS_IsUndefined(options)) { + if (!JS_IsObject(options)) { + JS_ThrowTypeError(cx, "Unknown options type (an object required)"); + return JS_EXCEPTION; + } + + value = JS_GetPropertyStr(cx, options, "bigint"); + if (!JS_IsUndefined(value)) { + JS_ThrowTypeError(cx, "\"bigint\" is not supported"); + return JS_EXCEPTION; + } + + if (calltype == QJS_FS_DIRECT) { + value = JS_GetPropertyStr(cx, options, "throwIfNoEntry"); + if (!JS_IsUndefined(value)) { + throw = JS_ToBool(cx, value); + } + } + } + + switch (magic >> 2) { + case QJS_FS_STAT: + ret = stat(path, &sb); + break; + + case QJS_FS_LSTAT: + ret = lstat(path, &sb); + break; + + case QJS_FS_FSTAT: + default: + ret = fstat(fd, &sb); + break; + } + + if (ret != 0) { + if (errno != ENOENT || throw) { + result = qjs_fs_error(cx, ((magic >> 2) == QJS_FS_STAT) + ? "stat" : "lstat", + strerror(errno), path, errno); + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + } else { + result = JS_UNDEFINED; + } + + return qjs_fs_result(cx, result, calltype, callback); + } + + result = qjs_fs_stats_create(cx, &sb); + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, callback); +} + + +static JSValue +qjs_fs_symlink(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype) +{ + int ret; + JSValue callback, result, type; + const char *target, *path; + char target_buf[NJS_MAX_PATH + 1], + path_buf[NJS_MAX_PATH + 1]; + + target = qjs_fs_path(cx, target_buf, argv[0], "target"); + if (target == NULL) { + return JS_EXCEPTION; + } + + path = qjs_fs_path(cx, path_buf, argv[1], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + callback = JS_UNDEFINED; + type = argv[2]; + + if (calltype == QJS_FS_CALLBACK) { + callback = argv[njs_min(argc - 1, 3)]; + + if (!JS_IsFunction(cx, callback)) { + JS_ThrowTypeError(cx, "\"callback\" must be a function"); + return JS_EXCEPTION; + } + + if (JS_SameValue(cx, type, callback)) { + type = JS_UNDEFINED; + } + } + + if (!JS_IsUndefined(type) && !JS_IsString(type)) { + JS_ThrowTypeError(cx, "\"type\" must be a string"); + return JS_EXCEPTION; + } + + result = JS_UNDEFINED; + + ret = symlink(target, path); + if (ret != 0) { + result = qjs_fs_error(cx, "symlink", strerror(errno), path, errno); + } + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, callback); +} + + +static JSValue +qjs_fs_write(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype) +{ + int fd, fd_offset; + u_char *to_free_content; + int64_t length, pos, offset; + ssize_t n; + JSValue buffer, v, result; + njs_str_t str, content; + const qjs_buffer_encoding_t *encoding; + + if (calltype == QJS_FS_DIRECT) { + fd_offset = 0; + if (JS_ToInt32(cx, &fd, argv[0]) < 0) { + return JS_EXCEPTION; + } + + } else { + fd_offset = -1; + if (JS_ToInt32(cx, &fd, this_val) < 0) { + return JS_EXCEPTION; + } + } + + pos = -1; + encoding = NULL; + str.start = NULL; + to_free_content = NULL; + buffer = argv[fd_offset + 1]; + + /* + * fs.writeSync(fd, string[, position[, encoding]]) + * fh.write(string[, position[, encoding]]) + */ + + if (JS_IsString(buffer)) { + v = argv[fd_offset + 2]; + + if (!JS_IsNullOrUndefined(v)) { + if (JS_ToInt64(cx, &pos, v) < 0) { + return JS_EXCEPTION; + } + } + + encoding = qjs_buffer_encoding(cx, argv[fd_offset + 3], 1); + if (encoding == NULL) { + return JS_EXCEPTION; + } + + str.start = (u_char *) JS_ToCStringLen(cx, &str.length, buffer); + if (str.start == NULL) { + return JS_EXCEPTION; + } + + if (encoding->decode_length != NULL) { + content.length = encoding->decode_length(cx, &str); + content.start = js_malloc(cx, content.length); + if (content.start == NULL) { + JS_FreeCString(cx, (const char *) str.start); + JS_ThrowOutOfMemory(cx); + return JS_EXCEPTION; + } + + to_free_content = content.start; + + if (encoding->decode(cx, &str, &content) != 0) { + JS_FreeCString(cx, (const char *) str.start); + return JS_EXCEPTION; + } + + } else { + content.start = (u_char *) str.start; + content.length = str.length; + } + + goto process; + } + + /* + * fh.write(buffer, offset[, length[, position]]) + * fs.writeSync(fd, buffer, offset[, length[, position]]) + */ + + v = qjs_typed_array_data(cx, buffer, &content); + if (JS_IsException(v)) { + return JS_EXCEPTION; + } + + if (JS_ToInt64(cx, &offset, argv[fd_offset + 2]) < 0) { + return JS_EXCEPTION; + } + + if (offset < 0 || (size_t) offset > content.length) { + JS_ThrowRangeError(cx, "offset is out of range (must be <= %zu)", + content.length); + return JS_EXCEPTION; + } + + content.length -= offset; + content.start += offset; + + v = argv[fd_offset + 3]; + if (!JS_IsNullOrUndefined(v)) { + if (JS_ToInt64(cx, &length, v) < 0) { + return JS_EXCEPTION; + } + + if (length < 0 || (size_t) length > content.length) { + JS_ThrowRangeError(cx, "length is out of range (must be <= %zu)", + content.length); + return JS_EXCEPTION; + } + + content.length = length; + } + + v = argv[fd_offset + 4]; + if (!JS_IsNullOrUndefined(v)) { + if (JS_ToInt64(cx, &pos, v) < 0) { + return JS_EXCEPTION; + } + } + +process: + + if (pos == -1) { + n = write(fd, content.start, content.length); + + } else { + n = pwrite(fd, content.start, content.length, pos); + } + + if (n == -1) { + result = qjs_fs_error(cx, "write", strerror(errno), NULL, errno); + goto done; + } + + if ((size_t) n != content.length) { + result = qjs_fs_error(cx, "write", "failed to write all the data", + NULL, 0); + goto done; + } + + if (calltype == QJS_FS_PROMISE) { + result = JS_NewObject(cx); + if (JS_IsException(result)) { + goto done; + } + + if (JS_DefinePropertyValueStr(cx, result, "bytesWritten", + JS_NewInt32(cx, n), + JS_PROP_C_W_E) < 0) + { + JS_FreeValue(cx, result); + result = JS_EXCEPTION; + goto done; + } + + buffer = JS_DupValue(cx, buffer); + + if (JS_DefinePropertyValueStr(cx, result, "buffer", buffer, + JS_PROP_C_W_E) < 0) + { + JS_FreeValue(cx, result); + JS_FreeValue(cx, buffer); + result = JS_EXCEPTION; + goto done; + } + + } else { + result = JS_NewInt32(cx, n); + } + +done: + + if (str.start != NULL) { + JS_FreeCString(cx, (const char *) str.start); + } + + if (to_free_content != NULL) { + js_free(cx, to_free_content); + } + + return qjs_fs_result(cx, result, calltype, JS_UNDEFINED); +} + + +static JSValue +qjs_fs_write_file(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int magic) +{ + int fd, flags, want_to_free_content; + u_char *p, *end; + mode_t md; + ssize_t n; + JSValue callback, data, v, encode, options, result; + njs_str_t str, content; + const char *path; + qjs_fs_calltype_t calltype; + const qjs_buffer_encoding_t *encoding; + char path_buf[NJS_MAX_PATH + 1]; + + path = qjs_fs_path(cx, path_buf, argv[0], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + md = 0666; + flags = O_CREAT | O_WRONLY; + flags |= ((magic >> 2) == QJS_FS_APPEND) ? O_APPEND : O_TRUNC; + calltype = magic & 3; + + encode = JS_UNDEFINED; + callback = JS_UNDEFINED; + options = argv[2]; + + if (calltype == QJS_FS_CALLBACK) { + if (argc > 0) { + callback = argv[njs_min(argc - 1, 3)]; + } + + if (!JS_IsFunction(cx, callback)) { + JS_ThrowTypeError(cx, "\"callback\" must be a function"); + return JS_EXCEPTION; + } + + if (JS_SameValue(cx, options, callback)) { + options = JS_UNDEFINED; + } + } + + if (JS_IsString(options)) { + encode = JS_DupValue(cx, options); + + } else if (!JS_IsUndefined(options)) { + if (!JS_IsObject(options)) { + JS_ThrowTypeError(cx, "Unknown options type (a string or object " + "required)"); + return JS_EXCEPTION; + } + + v = JS_GetPropertyStr(cx, options, "flag"); + if (!JS_IsUndefined(v) && !JS_IsException(v)) { + flags = qjs_fs_flags(cx, v, O_CREAT | O_WRONLY); + if (flags == -1) { + JS_FreeValue(cx, v); + return JS_EXCEPTION; + } + } + + v = JS_GetPropertyStr(cx, options, "mode"); + if (!JS_IsUndefined(v) && !JS_IsException(v)) { + md = qjs_fs_mode(cx, v, 0666); + if (md == (mode_t) -1) { + JS_FreeValue(cx, v); + return JS_EXCEPTION; + } + } + + v = JS_GetPropertyStr(cx, options, "encoding"); + if (!JS_IsUndefined(v) && !JS_IsException(v)) { + encode = v; + } + } + + encoding = qjs_buffer_encoding(cx, encode, 1); + if (encoding == NULL) { + JS_FreeValue(cx, encode); + return JS_EXCEPTION; + } + + JS_FreeValue(cx, encode); + + data = argv[1]; + str.start = NULL; + want_to_free_content = 0; + + if (JS_IsString(data)) { + goto decode; + } + + v = qjs_typed_array_data(cx, data, &content); + if (JS_IsException(v)) { +decode: + + str.start = (u_char *) JS_ToCStringLen(cx, &str.length, data); + if (str.start == NULL) { + return JS_EXCEPTION; + } + + if (encoding->decode_length != NULL) { + content.length = encoding->decode_length(cx, &str); + content.start = js_malloc(cx, content.length); + if (content.start == NULL) { + JS_FreeCString(cx, (const char *) str.start); + JS_ThrowOutOfMemory(cx); + return JS_EXCEPTION; + } + + want_to_free_content = 1; + + if (encoding->decode(cx, &str, &content) != 0) { + JS_FreeCString(cx, (const char *) str.start); + return JS_EXCEPTION; + } + + } else { + content.start = (u_char *) str.start; + content.length = str.length; + } + } + + fd = open(path, flags, md); + if (fd < 0) { + result = qjs_fs_error(cx, "open", strerror(errno), path, errno); + goto done; + } + + p = content.start; + end = p + content.length; + + while (p < end) { + n = write(fd, p, end - p); + if (n == -1) { + if (errno == EINTR) { + continue; + } + + result = qjs_fs_error(cx, "write", strerror(errno), path, errno); + goto done; + } + + p += n; + } + + result = JS_UNDEFINED; + +done: + + if (fd != -1) { + (void) close(fd); + } + + if (str.start != NULL) { + JS_FreeCString(cx, (const char *) str.start); + } + + if (want_to_free_content) { + js_free(cx, content.start); + } + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, callback); +} + + +static JSValue +qjs_fs_unlink(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int calltype) +{ + int ret; + JSValue callback, result; + const char *path; + char path_buf[NJS_MAX_PATH + 1]; + + path = qjs_fs_path(cx, path_buf, argv[0], "path"); + if (path == NULL) { + return JS_EXCEPTION; + } + + callback = JS_UNDEFINED; + + if (calltype == QJS_FS_CALLBACK) { + callback = argv[1]; + + if (!JS_IsFunction(cx, callback)) { + JS_ThrowTypeError(cx, "\"callback\" must be a function"); + return JS_EXCEPTION; + } + } + + result = JS_UNDEFINED; + + ret = unlink(path); + if (ret != 0) { + result = qjs_fs_error(cx, "unlink", strerror(errno), path, errno); + } + + if (JS_IsException(result)) { + return JS_EXCEPTION; + } + + return qjs_fs_result(cx, result, calltype, callback); +} + + +static JSValue +qjs_fs_stats_to_string_tag(JSContext *cx, JSValueConst this_val) +{ + return JS_NewString(cx, "Stats"); +} + + +static JSValue +qjs_fs_stats_test(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int testtype) +{ + unsigned mask; + qjs_stat_t *st; + + st = JS_GetOpaque2(cx, this_val, QJS_CORE_CLASS_ID_FS_STATS); + if (st == NULL) { + return JS_EXCEPTION; + } + + switch (testtype) { + case DT_DIR: + mask = S_IFDIR; + break; + + case DT_REG: + mask = S_IFREG; + break; + + case DT_CHR: + mask = S_IFCHR; + break; + + case DT_LNK: + mask = S_IFLNK; + break; + + case DT_BLK: + mask = S_IFBLK; + break; + + case DT_FIFO: + mask = S_IFIFO; + break; + + case DT_SOCK: + default: + mask = S_IFSOCK; + } + + return JS_NewBool(cx, (st->st_mode & S_IFMT) == mask); +} + + +static int +qjs_fs_stats_get_own_property(JSContext *cx, JSPropertyDescriptor *pdesc, + JSValueConst obj, JSAtom prop) +{ + JSValue value; + njs_str_t name; + qjs_stat_t *st; + +#define qjs_fs_time_ms(ts) ((ts)->tv_sec * 1000.0 + (ts)->tv_nsec / 1000000.0) + + st = JS_GetOpaque2(cx, obj, QJS_CORE_CLASS_ID_FS_STATS); + if (st == NULL) { + (void) JS_ThrowInternalError(cx, "\"this\" is not a Stats object"); + return -1; + } + + name.start = (u_char *) JS_AtomToCString(cx, prop); + if (name.start == NULL) { + return -1; + } + + name.length = strlen((const char *) name.start); + + if (name.length < 3) { + JS_FreeCString(cx, (const char *) name.start); + return 0; + } + + switch (name.start[0]) { + case 'a': + if (name.length == 5 && memcmp(name.start, "atime", 5) == 0) { + value = JS_NewDate(cx, qjs_fs_time_ms(&st->st_atim)); + goto done; + } + + if (name.length == 7 && memcmp(name.start, "atimeMs", 7) == 0) { + value = JS_NewFloat64(cx, qjs_fs_time_ms(&st->st_atim)); + goto done; + } + + break; + + case 'b': + if (name.length == 6 && memcmp(name.start, "blocks", 6) == 0) { + value = JS_NewFloat64(cx, st->st_blocks); + goto done; + } + + if (name.length == 7 && memcmp(name.start, "blksize", 7) == 0) { + value = JS_NewFloat64(cx, st->st_blksize); + goto done; + } + + if (name.length == 9 && memcmp(name.start, "birthtime", 9) == 0) { + value = JS_NewDate(cx, qjs_fs_time_ms(&st->st_birthtim)); + goto done; + } + + if (name.length == 11 && memcmp(name.start, "birthtimeMs", 11) == 0) { + value = JS_NewFloat64(cx, qjs_fs_time_ms(&st->st_birthtim)); + goto done; + } + + break; + + case 'c': + if (name.length == 5 && memcmp(name.start, "ctime", 5) == 0) { + value = JS_NewDate(cx, qjs_fs_time_ms(&st->st_ctim)); + goto done; + } + + if (name.length == 7 && memcmp(name.start, "ctimeMs", 7) == 0) { + value = JS_NewFloat64(cx, qjs_fs_time_ms(&st->st_ctim)); + goto done; + } + + break; + + case 'd': + if (name.length == 3 && memcmp(name.start, "dev", 3) == 0) { + value = JS_NewFloat64(cx, st->st_dev); + goto done; + } + + break; + + case 'g': + if (name.length == 3 && memcmp(name.start, "gid", 3) == 0) { + value = JS_NewFloat64(cx, st->st_gid); + goto done; + } + + break; + + case 'i': + if (name.length == 3 && memcmp(name.start, "ino", 3) == 0) { + value = JS_NewFloat64(cx, st->st_ino); + goto done; + } + + break; + + case 'm': + if (name.length == 4 && memcmp(name.start, "mode", 4) == 0) { + value = JS_NewFloat64(cx, st->st_mode); + goto done; + } + + if (name.length == 5 && memcmp(name.start, "mtime", 5) == 0) { + value = JS_NewDate(cx, qjs_fs_time_ms(&st->st_mtim)); + goto done; + } + + if (name.length == 7 && memcmp(name.start, "mtimeMs", 7) == 0) { + value = JS_NewFloat64(cx, qjs_fs_time_ms(&st->st_mtim)); + goto done; + } + + break; + + case 'n': + if (name.length == 5 && memcmp(name.start, "nlink", 5) == 0) { + value = JS_NewFloat64(cx, st->st_nlink); + goto done; + } + + break; + + case 'r': + if (name.length == 4 && memcmp(name.start, "rdev", 4) == 0) { + value = JS_NewFloat64(cx, st->st_rdev); + goto done; + } + + break; + + case 's': + if (name.length == 4 && memcmp(name.start, "size", 4) == 0) { + value = JS_NewFloat64(cx, st->st_size); + goto done; + } + + break; + + case 'u': + if (name.length == 3 && memcmp(name.start, "uid", 3) == 0) { + value = JS_NewFloat64(cx, st->st_uid); + goto done; + } + + break; + } + + JS_FreeCString(cx, (const char *) name.start); + + return 0; + +done: + + JS_FreeCString(cx, (const char *) name.start); + + if (pdesc != NULL) { + pdesc->flags = JS_PROP_ENUMERABLE | JS_PROP_CONFIGURABLE; + pdesc->getter = JS_UNDEFINED; + pdesc->setter = JS_UNDEFINED; + pdesc->value = value; + } + + return 1; +} + + +static int +qjs_fs_stats_get_own_property_names(JSContext *cx, JSPropertyEnum **ptab, + uint32_t *plen, JSValueConst obj) +{ + int ret; + JSValue keys; + unsigned i; + + static const char *stat_props[] = { + "atime", + "atimeMs", + "birthtime", + "birthtimeMs", + "blksize", + "blocks", + "ctime", + "ctimeMs", + "dev", + "gid", + "ino", + "mode", + "mtime", + "mtimeMs", + "nlink", + "size", + "rdev", + "uid", + }; + + keys = JS_NewObject(cx); + if (JS_IsException(keys)) { + return -1; + } + + for (i = 0; i < njs_nitems(stat_props); i++) { + if (JS_DefinePropertyValueStr(cx, keys, stat_props[i], + JS_UNDEFINED, JS_PROP_C_W_E) < 0) + { + JS_FreeValue(cx, keys); + return -1; + } + } + + ret = JS_GetOwnPropertyNames(cx, ptab, plen, keys, JS_GPN_STRING_MASK); + + JS_FreeValue(cx, keys); + + return ret; +} + + +static void +qjs_fs_stats_finalizer(JSRuntime *rt, JSValue val) +{ + qjs_stat_t *stat; + + stat = JS_GetOpaque(val, QJS_CORE_CLASS_ID_FS_STATS); + if (stat != NULL) { + js_free_rt(rt, stat); + } +} + + +static JSValue +qjs_fs_dirent_to_string_tag(JSContext *cx, JSValueConst this_val) +{ + return JS_NewString(cx, "Dirent"); +} + + +static JSValue +qjs_fs_dirent_test(JSContext *cx, JSValueConst this_val, int argc, + JSValueConst *argv, int testtype) +{ + int value; + JSValue type; + + type = JS_GetPropertyStr(cx, this_val, "type"); + if (JS_IsException(type)) { + return JS_EXCEPTION; + } + + if (JS_VALUE_GET_TAG(type) != JS_TAG_INT) { + JS_FreeValue(cx, type); + return JS_FALSE; + } + + value = JS_VALUE_GET_INT(type); + JS_FreeValue(cx, type); + + if (value == QJS_DT_INVALID) { + JS_ThrowInternalError(cx, "dentry type is not supported on this " + "platform"); + return JS_EXCEPTION; + } + + return JS_NewBool(cx, testtype == value); +} + + +static JSValue +qjs_fs_filehandle_to_string_tag(JSContext *cx, JSValueConst this_val) +{ + return JS_NewString(cx, "FileHandle"); +} + + +static JSValue +qjs_fs_filehandle_fd(JSContext *cx, JSValueConst thisval) +{ + int fd; + + fd = (intptr_t) JS_GetOpaque2(cx, thisval, QJS_CORE_CLASS_ID_FS_FILEHANDLE); + + if (fd == -1) { + return JS_ThrowTypeError(cx, "file was already closed"); + } + + return JS_NewInt32(cx, fd); +} + + +static JSValue +qjs_fs_filehandle_value_of(JSContext *cx, JSValueConst thisval, int argc, + JSValueConst *argv) +{ + int fd; + + fd = (intptr_t) JS_GetOpaque2(cx, thisval, QJS_CORE_CLASS_ID_FS_FILEHANDLE); + + if (fd == -1) { + return JS_ThrowTypeError(cx, "file was already closed"); + } + + return JS_NewInt32(cx, fd); +} + + +static void +qjs_fs_filehandle_finalizer(JSRuntime *rt, JSValue val) +{ + int fd; + + fd = (intptr_t) JS_GetOpaque(val, QJS_CORE_CLASS_ID_FS_FILEHANDLE); + + (void) close(fd); +} + + +static JSValue +qjs_fs_promise_trampoline(JSContext *cx, int argc, JSValueConst *argv) +{ + return JS_Call(cx, argv[0], JS_UNDEFINED, 1, &argv[1]); +} + + +static JSValue +qjs_fs_result(JSContext *cx, JSValue result, int calltype, JSValue callback) +{ + JS_BOOL is_error; + JSValue promise, callbacks[2], arguments[2]; + + switch (calltype) { + case QJS_FS_DIRECT: + if (JS_IsError(cx, result)) { + JS_Throw(cx, result); + return JS_EXCEPTION; + } + + return result; + + case QJS_FS_PROMISE: + promise = JS_NewPromiseCapability(cx, callbacks); + if (JS_IsException(promise)) { + JS_FreeValue(cx, result); + return JS_EXCEPTION; + } + + is_error = !!JS_IsError(cx, result); + + arguments[0] = callbacks[is_error]; + arguments[1] = result; + JS_FreeValue(cx, callbacks[!is_error]); + + if (JS_EnqueueJob(cx, qjs_fs_promise_trampoline, 2, arguments) < 0) { + JS_FreeValue(cx, promise); + JS_FreeValue(cx, callbacks[is_error]); + JS_FreeValue(cx, result); + return JS_EXCEPTION; + } + + JS_FreeValue(cx, arguments[0]); + JS_FreeValue(cx, arguments[1]); + + return promise; + + case QJS_FS_CALLBACK: + if (JS_IsError(cx, result)) { + arguments[0] = result; + arguments[1] = JS_UNDEFINED; + + } else { + arguments[0] = JS_UNDEFINED; + arguments[1] = result; + } + + promise = JS_Call(cx, callback, JS_UNDEFINED, 2, arguments); + JS_FreeValue(cx, arguments[0]); + JS_FreeValue(cx, arguments[1]); + + if (JS_IsException(promise)) { + return JS_EXCEPTION; + } + + return JS_UNDEFINED; + + default: + return JS_ThrowInternalError(cx, "unexpected calltype %d", calltype); + } +} + + +static int +qjs_fs_flags(JSContext *cx, JSValue value, int default_flags) +{ + JSValue ret; + njs_str_t flags; + qjs_fs_entry_t *fl; + + if (JS_IsUndefined(value)) { + return default_flags; + } + + ret = JS_ToString(cx, value); + if (JS_IsException(ret)) { + return -1; + } + + flags.start = (u_char *) JS_ToCStringLen(cx, &flags.length, ret); + JS_FreeValue(cx, ret); + if (flags.start == NULL) { + return -1; + } + + for (fl = &qjs_flags_table[0]; fl->name.length != 0; fl++) { + if (njs_strstr_eq(&flags, &fl->name)) { + JS_FreeCString(cx, (const char *) flags.start); + return fl->value; + } + } + + JS_ThrowTypeError(cx, "Unknown file open flags: \"%s\"", flags.start); + + JS_FreeCString(cx, (const char *) flags.start); + + return -1; +} + + +static mode_t +qjs_fs_mode(JSContext *cx, JSValue value, mode_t default_mode) +{ + int64_t i64; + + /* GCC complains about uninitialized i64. */ + i64 = 0; + + if (JS_IsUndefined(value)) { + return default_mode; + } + + if (JS_ToInt64(cx, &i64, value) < 0) { + return (mode_t) -1; + } + + return (mode_t) i64; +} + + +static JSValue +qjs_fs_error(JSContext *cx, const char *syscall, const char *description, + const char *path, int errn) +{ + JSValue value; + + value = JS_NewError(cx); + if (JS_IsException(value)) { + return JS_EXCEPTION; + } + + if (JS_SetPropertyStr(cx, value, "message", + JS_NewString(cx, description)) < 0) + { + JS_FreeValue(cx, value); + return JS_EXCEPTION; + } + + if (errn != 0) { + if (JS_SetPropertyStr(cx, value, "errno", JS_NewInt32(cx, errn)) < 0) { + JS_FreeValue(cx, value); + return JS_EXCEPTION; + } + + if (JS_SetPropertyStr(cx, value, "code", + JS_NewString(cx, njs_errno_string(errn))) < 0) + { + JS_FreeValue(cx, value); + return JS_EXCEPTION; + } + } + + if (path != NULL) { + if (JS_SetPropertyStr(cx, value, "path", + JS_NewString(cx, path)) < 0) + { + JS_FreeValue(cx, value); + return JS_EXCEPTION; + } + } + + if (syscall != NULL) { + if (JS_SetPropertyStr(cx, value, "syscall", + JS_NewString(cx, syscall)) < 0) + { + JS_FreeValue(cx, value); + return JS_EXCEPTION; + } + } + + return value; +} + + +static JSValue +qjs_fs_encode(JSContext *cx, const qjs_buffer_encoding_t *encoding, + njs_str_t *str) +{ + JSValue ret; + njs_str_t data; + + if (encoding == NULL) { + return qjs_buffer_create(cx, str->start, str->length); + + } else if (encoding->encode_length != NULL) { + data.length = encoding->encode_length(cx, str); + + data.start = js_malloc(cx, data.length); + if (data.start == NULL) { + JS_ThrowOutOfMemory(cx); + return JS_EXCEPTION; + } + + if (encoding->encode(cx, str, &data) != 0) { + js_free(cx, data.start); + return JS_EXCEPTION; + } + + ret = JS_NewStringLen(cx, (const char *) data.start, data.length); + js_free(cx, data.start); + + return ret; + } + + return JS_NewStringLen(cx, (const char *) str->start, str->length); +} + + +static char * +qjs_fs_path(JSContext *cx, char storage[NJS_MAX_PATH + 1], JSValue src, + const char *prop_name) +{ + u_char *p; + JSValue val; + qjs_bytes_t bytes; + + if (!JS_IsString(src)) { + val = JS_GetTypedArrayBuffer(cx, src, NULL, NULL, NULL); + if (JS_IsException(val)) { + JS_ThrowTypeError(cx, "\"%s\" must be a string or Buffer", + prop_name); + return NULL; + } + + JS_FreeValue(cx, val); + } + + if (qjs_to_bytes(cx, &bytes, src) != 0) { + return NULL; + } + + if (bytes.length > NJS_MAX_PATH - 1) { + qjs_bytes_free(cx, &bytes); + JS_ThrowRangeError(cx, "\"%s\" is too long >= %d", prop_name, + NJS_MAX_PATH); + return NULL; + } + + if (memchr(bytes.start, '\0', bytes.length) != 0) { + qjs_bytes_free(cx, &bytes); + JS_ThrowTypeError(cx, "\"%s\" must be a Buffer without null bytes", + prop_name); + return NULL; + } + + p = njs_cpymem(storage, bytes.start, bytes.length); + *p++ = '\0'; + + qjs_bytes_free(cx, &bytes); + + return storage; +} + + +static int +qjs_fs_module_init(JSContext *cx, JSModuleDef *m) +{ + int rc; + JSValue proto; + + proto = JS_NewObject(cx); + JS_SetPropertyFunctionList(cx, proto, qjs_fs_export, + njs_nitems(qjs_fs_export)); + + rc = JS_SetModuleExport(cx, m, "default", proto); + if (rc != 0) { + return -1; + } + + return JS_SetModuleExportList(cx, m, qjs_fs_export, + njs_nitems(qjs_fs_export)); +} + + +static JSModuleDef * +qjs_fs_init(JSContext *cx, const char *name) +{ + int rc; + JSValue proto; + JSModuleDef *m; + + if (!JS_IsRegisteredClass(JS_GetRuntime(cx), + QJS_CORE_CLASS_ID_FS_STATS)) + { + if (JS_NewClass(JS_GetRuntime(cx), QJS_CORE_CLASS_ID_FS_STATS, + &qjs_fs_stats_class) < 0) + { + return NULL; + } + + proto = JS_NewObject(cx); + if (JS_IsException(proto)) { + return NULL; + } + + JS_SetPropertyFunctionList(cx, proto, qjs_fs_stats_proto, + njs_nitems(qjs_fs_stats_proto)); + + JS_SetClassProto(cx, QJS_CORE_CLASS_ID_FS_STATS, proto); + + proto = JS_NewObject(cx); + if (JS_IsException(proto)) { + return NULL; + } + + JS_SetPropertyFunctionList(cx, proto, qjs_fs_dirent_proto, + njs_nitems(qjs_fs_dirent_proto)); + + JS_SetClassProto(cx, QJS_CORE_CLASS_ID_FS_DIRENT, proto); + + if (JS_NewClass(JS_GetRuntime(cx), QJS_CORE_CLASS_ID_FS_FILEHANDLE, + &qjs_fs_filehandle_class) < 0) + { + return NULL; + } + + proto = JS_NewObject(cx); + if (JS_IsException(proto)) { + return NULL; + } + + JS_SetPropertyFunctionList(cx, proto, qjs_fs_filehandle_proto, + njs_nitems(qjs_fs_filehandle_proto)); + + JS_SetClassProto(cx, QJS_CORE_CLASS_ID_FS_FILEHANDLE, proto); + } + + m = JS_NewCModule(cx, name, qjs_fs_module_init); + if (m == NULL) { + return NULL; + } + + JS_AddModuleExport(cx, m, "default"); + rc = JS_AddModuleExportList(cx, m, qjs_fs_export, + njs_nitems(qjs_fs_export)); + if (rc != 0) { + return NULL; + } + + return m; +} diff --git a/src/qjs.h b/src/qjs.h index 81769abb..dec6419d 100644 --- a/src/qjs.h +++ b/src/qjs.h @@ -33,10 +33,13 @@ #include -#define QJS_CORE_CLASS_ID_OFFSET 64 -#define QJS_CORE_CLASS_ID_BUFFER (QJS_CORE_CLASS_ID_OFFSET) +#define QJS_CORE_CLASS_ID_OFFSET 64 +#define QJS_CORE_CLASS_ID_BUFFER (QJS_CORE_CLASS_ID_OFFSET) #define QJS_CORE_CLASS_ID_UINT8_ARRAY_CTOR (QJS_CORE_CLASS_ID_OFFSET + 1) -#define QJS_CORE_CLASS_ID_LAST (QJS_CORE_CLASS_ID_UINT8_ARRAY_CTOR) +#define QJS_CORE_CLASS_ID_FS_STATS (QJS_CORE_CLASS_ID_OFFSET + 2) +#define QJS_CORE_CLASS_ID_FS_DIRENT (QJS_CORE_CLASS_ID_OFFSET + 3) +#define QJS_CORE_CLASS_ID_FS_FILEHANDLE (QJS_CORE_CLASS_ID_OFFSET + 4) +#define QJS_CORE_CLASS_ID_LAST (QJS_CORE_CLASS_ID_OFFSET + 5) typedef JSModuleDef *(*qjs_addon_init_pt)(JSContext *ctx, const char *name); diff --git a/test/fs/methods.t.mjs b/test/fs/methods.t.mjs index 9b695296..928d1682 100644 --- a/test/fs/methods.t.mjs +++ b/test/fs/methods.t.mjs @@ -116,7 +116,7 @@ let readfile_tests = () => [ return true; } }, - { args: ["test/fs/non_utf8", "utf8"], expected: "��" }, + { args: ["test/fs/non_utf8", "utf8"], expected: "��", skip() { return njs && njs.engine == 'QuickJS'; } }, { args: ["test/fs/non_utf8", {encoding: "hex"}], expected: "8080" }, { args: ["test/fs/non_utf8", "base64"], expected: "gIA=" }, { args: ["test/fs/ascii", "utf8"], expected: "x".repeat(600) }, @@ -219,7 +219,7 @@ let writefile_tests = () => [ { args: ["@", Buffer.from("XYZ"), {encoding: "utf8", mode: 0o666}], expected: Buffer.from("XYZ") }, { args: ["@", new DataView(Buffer.alloc(3).fill(66).buffer)], - expected: Buffer.from("BBB") }, + expected: Buffer.from("BBB"), skip() { return njs && njs.engine == 'QuickJS'; } }, { args: ["@", new Uint8Array(Buffer.from("ABCD"))], expected: Buffer.from("ABCD")}, { args: ["@", "XYZ"], expected: Buffer.from("XYZ")}, @@ -309,7 +309,7 @@ let append_tests = () => [ { args: ["@", Buffer.from("XYZ"), {encoding: "utf8", mode: 0o666}], expected: Buffer.from("XYZXYZ") }, { args: ["@", new DataView(Buffer.alloc(3).fill(66).buffer)], - expected: Buffer.from("BBBBBB") }, + expected: Buffer.from("BBBBBB"), skip() { return njs && njs.engine == 'QuickJS'; } }, { args: ["@", new Uint8Array(Buffer.from("ABCD"))], expected: Buffer.from("ABCDABCD")}, { args: ["@", "XYZ"], expected: Buffer.from("XYZXYZ")}, From noreply at nginx.com Thu Dec 19 20:19:06 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:06 +0000 (UTC) Subject: [unit] .mailmap: Add an entry for Igor Message-ID: <20241219201906.BBBDF489DD@pubserv1.nginx> details: https://github.com/nginx/unit/commit/1b88304fe53a4a414d84548fbfabac2827125485 branches: master commit: 1b88304fe53a4a414d84548fbfabac2827125485 user: Andrew Clayton date: Wed, 18 Dec 2024 19:53:29 +0000 description: .mailmap: Add an entry for Igor You can always see the original names/addresses used by passing --no-mailmap to the various git commands. See gitmailmap(5) Signed-off-by: Andrew Clayton --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 94a14bfa..26377ea2 100644 --- a/.mailmap +++ b/.mailmap @@ -11,6 +11,7 @@ Dan Callahan Danielle De Leo Dylan Arbour Dylan Arbour <7211830+arbourd at users.noreply.github.com> +Igor Ippolitov Konstantin Pavlov Konstantin Pavlov Max Romanov From noreply at nginx.com Thu Dec 19 20:19:06 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:06 +0000 (UTC) Subject: [unit] tools/unitctl: Update for version 1.34.0 Message-ID: <20241219201906.C1973489DE@pubserv1.nginx> details: https://github.com/nginx/unit/commit/fe9be6cdefe9300a845612e3be772f5eee9dcf40 branches: master commit: fe9be6cdefe9300a845612e3be772f5eee9dcf40 user: Andrew Clayton date: Wed, 11 Dec 2024 22:18:47 +0000 description: tools/unitctl: Update for version 1.34.0 Signed-off-by: Andrew Clayton --- tools/unitctl/Cargo.lock | 6 +++--- tools/unitctl/openapi-config.json | 2 +- tools/unitctl/unit-client-rs/Cargo.toml | 2 +- tools/unitctl/unit-openapi/Cargo.toml | 2 +- tools/unitctl/unit-openapi/README.md | 2 +- tools/unitctl/unitctl/Cargo.toml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/unitctl/Cargo.lock b/tools/unitctl/Cargo.lock index 917bb5a1..79fd254b 100644 --- a/tools/unitctl/Cargo.lock +++ b/tools/unitctl/Cargo.lock @@ -2185,7 +2185,7 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unit-client-rs" -version = "1.33.0" +version = "1.34.0" dependencies = [ "bollard", "custom_error", @@ -2208,7 +2208,7 @@ dependencies = [ [[package]] name = "unit-openapi" -version = "1.33.0" +version = "1.34.0" dependencies = [ "base64 0.21.7", "futures", @@ -2222,7 +2222,7 @@ dependencies = [ [[package]] name = "unitctl" -version = "1.33.0" +version = "1.34.0" dependencies = [ "clap", "colored_json", diff --git a/tools/unitctl/openapi-config.json b/tools/unitctl/openapi-config.json index c47caadb..0986624a 100644 --- a/tools/unitctl/openapi-config.json +++ b/tools/unitctl/openapi-config.json @@ -1,6 +1,6 @@ { "packageName": "unit-openapi", - "packageVersion": "1.33.0", + "packageVersion": "1.34.0", "library": "hyper", "preferUnsignedInt": true } diff --git a/tools/unitctl/unit-client-rs/Cargo.toml b/tools/unitctl/unit-client-rs/Cargo.toml index 7cdd0b9f..4fd77036 100644 --- a/tools/unitctl/unit-client-rs/Cargo.toml +++ b/tools/unitctl/unit-client-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "unit-client-rs" -version = "1.33.0" +version = "1.34.0" authors = ["Elijah Zupancic"] edition = "2021" license = "Apache-2.0" diff --git a/tools/unitctl/unit-openapi/Cargo.toml b/tools/unitctl/unit-openapi/Cargo.toml index c7a177f9..94d274c7 100644 --- a/tools/unitctl/unit-openapi/Cargo.toml +++ b/tools/unitctl/unit-openapi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "unit-openapi" -version = "1.33.0" +version = "1.34.0" authors = ["unit-owner at nginx.org"] description = "NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Unit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket." license = "Apache 2.0" diff --git a/tools/unitctl/unit-openapi/README.md b/tools/unitctl/unit-openapi/README.md index d26d6c7f..32728185 100644 --- a/tools/unitctl/unit-openapi/README.md +++ b/tools/unitctl/unit-openapi/README.md @@ -21,7 +21,7 @@ For more information, please visit [https://unit.nginx.org/](https://unit.nginx. This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://openapis.org) from a remote server, you can easily generate an API client. - API version: 0.2.0 -- Package version: 1.33.0 +- Package version: 1.34.0 - Generator version: 7.6.0 - Build package: `org.openapitools.codegen.languages.RustClientCodegen` diff --git a/tools/unitctl/unitctl/Cargo.toml b/tools/unitctl/unitctl/Cargo.toml index ec89c975..82fa4068 100644 --- a/tools/unitctl/unitctl/Cargo.toml +++ b/tools/unitctl/unitctl/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "unitctl" description = "CLI interface to the NGINX Unit Control API" -version = "1.33.0" +version = "1.34.0" authors = ["Elijah Zupancic"] edition = "2021" license = "Apache-2.0" From noreply at nginx.com Thu Dec 19 20:19:06 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:06 +0000 (UTC) Subject: [unit] docs/unit-openapi.yaml: Update version for 1.34.0 Message-ID: <20241219201906.C6E73489DF@pubserv1.nginx> details: https://github.com/nginx/unit/commit/ecb0f21d5d920878b97e0ae41c7eaf09cc796cfd branches: master commit: ecb0f21d5d920878b97e0ae41c7eaf09cc796cfd user: Andrew Clayton date: Wed, 11 Dec 2024 22:19:58 +0000 description: docs/unit-openapi.yaml: Update version for 1.34.0 Signed-off-by: Andrew Clayton --- docs/unit-openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/unit-openapi.yaml b/docs/unit-openapi.yaml index 6147bf40..419b8da2 100644 --- a/docs/unit-openapi.yaml +++ b/docs/unit-openapi.yaml @@ -1,6 +1,6 @@ openapi: 3.0.0 info: - title: "NGINX Unit 1.33.0" + title: "NGINX Unit 1.34.0" description: "NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, From noreply at nginx.com Thu Dec 19 20:19:06 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:06 +0000 (UTC) Subject: [unit] docs/changes.xml: Add 1.34.0 changelog entries Message-ID: <20241219201906.D2B84489E2@pubserv1.nginx> details: https://github.com/nginx/unit/commit/5a28c663a7bc39f0703f5f485d757fd33de360a6 branches: master commit: 5a28c663a7bc39f0703f5f485d757fd33de360a6 user: Andrew Clayton date: Thu, 12 Dec 2024 02:37:52 +0000 description: docs/changes.xml: Add 1.34.0 changelog entries Signed-off-by: Andrew Clayton --- docs/changes.xml | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/docs/changes.xml b/docs/changes.xml index cc5769e5..d8d5ef78 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -9,7 +9,7 @@ unit-python unit-python2.7 unit-python3.4 unit-python3.5 unit-python3.6 unit-python3.7 unit-python3.8 unit-python3.9 unit-python3.10 unit-python3.11 - unit-python3.12 + unit-python3.12 unit-python3.13 unit-go unit-perl unit-ruby @@ -18,7 +18,7 @@ unit-jsc19 unit-jsc20 unit-jsc21 unit-wasm" ver="1.34.0" rev="1" - date="" time="" + date="2024-12-19" time="18:00:00 +0000" packager="Nginx Packaging <nginx-packaging at f5.com>"> @@ -31,9 +31,28 @@ NGINX Unit updated to 1.34.0. + + +initial OpenTelemetry (OTEL) support. (Disabled by default). + + + + + +support for JSON formatted access logs. + + + + + +tweak the Perl language module to avoid breaking scripts in some +circumstances. + + + @@ -63,7 +82,7 @@ NGINX Unit updated to 1.33.0. From noreply at nginx.com Thu Dec 19 20:19:06 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:06 +0000 (UTC) Subject: [unit] Add 1.34.0 CHANGES Message-ID: <20241219201906.D6DF1489E4@pubserv1.nginx> details: https://github.com/nginx/unit/commit/27bde184dedcbf687db2f314c60c037623318a8d branches: master commit: 27bde184dedcbf687db2f314c60c037623318a8d user: Andrew Clayton date: Thu, 12 Dec 2024 02:43:18 +0000 description: Add 1.34.0 CHANGES This is autogenerated from docs/changes.xml by $ make -C docs/ changes && mv build/CHANGES . Signed-off-by: Andrew Clayton --- CHANGES | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGES b/CHANGES index 1babb686..78ea31b9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,14 @@ +Changes with Unit 1.34.0 19 Dec 2024 + + *) Feature: initial OpenTelemetry (OTEL) support. (Disabled by default). + + *) Feature: support for JSON formatted access logs. + + *) Bugfix: tweak the Perl language module to avoid breaking scripts in + some circumstances. + + Changes with Unit 1.33.0 17 Sep 2024 *) Feature: make the number of router threads configurable. From noreply at nginx.com Thu Dec 19 20:19:06 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:06 +0000 (UTC) Subject: [unit] pkg/docker: Update dockerfiles for 1.34.0 Message-ID: <20241219201906.CE202489E0@pubserv1.nginx> details: https://github.com/nginx/unit/commit/962752f57fe268234f29ed287cad4e6582736ca7 branches: master commit: 962752f57fe268234f29ed287cad4e6582736ca7 user: Andrew Clayton date: Wed, 18 Dec 2024 23:03:52 +0000 description: pkg/docker: Update dockerfiles for 1.34.0 Signed-off-by: Andrew Clayton --- pkg/docker/Dockerfile.go1.22 | 29 +++++++++++++++--- pkg/docker/Dockerfile.go1.23 | 29 +++++++++++++++--- pkg/docker/Dockerfile.jsc11 | 29 +++++++++++++++--- pkg/docker/Dockerfile.minimal | 29 +++++++++++++++--- pkg/docker/Dockerfile.node20 | 29 +++++++++++++++--- pkg/docker/Dockerfile.node22 | 29 +++++++++++++++--- pkg/docker/Dockerfile.perl5.38 | 29 +++++++++++++++--- pkg/docker/Dockerfile.perl5.40 | 29 +++++++++++++++--- pkg/docker/Dockerfile.php8.3 | 29 +++++++++++++++--- pkg/docker/Dockerfile.php8.4 | 29 +++++++++++++++--- pkg/docker/Dockerfile.python3.12 | 29 +++++++++++++++--- pkg/docker/Dockerfile.python3.12-slim | 29 +++++++++++++++--- pkg/docker/Dockerfile.python3.13 | 29 +++++++++++++++--- pkg/docker/Dockerfile.python3.13-slim | 29 +++++++++++++++--- pkg/docker/Dockerfile.ruby3.2 | 29 +++++++++++++++--- pkg/docker/Dockerfile.ruby3.3 | 29 +++++++++++++++--- pkg/docker/Dockerfile.wasm | 55 ++++++++++++++++++----------------- 17 files changed, 428 insertions(+), 91 deletions(-) diff --git a/pkg/docker/Dockerfile.go1.22 b/pkg/docker/Dockerfile.go1.22 index 796a6715..6059fc42 100644 --- a/pkg/docker/Dockerfile.go1.22 +++ b/pkg/docker/Dockerfile.go1.22 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.go1.23 b/pkg/docker/Dockerfile.go1.23 index a62be794..a1a64602 100644 --- a/pkg/docker/Dockerfile.go1.23 +++ b/pkg/docker/Dockerfile.go1.23 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.jsc11 b/pkg/docker/Dockerfile.jsc11 index d133d5b2..f97e0e78 100644 --- a/pkg/docker/Dockerfile.jsc11 +++ b/pkg/docker/Dockerfile.jsc11 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.minimal b/pkg/docker/Dockerfile.minimal index 3880de7a..9bff9d4b 100644 --- a/pkg/docker/Dockerfile.minimal +++ b/pkg/docker/Dockerfile.minimal @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.node20 b/pkg/docker/Dockerfile.node20 index 5ae09797..86c3a83b 100644 --- a/pkg/docker/Dockerfile.node20 +++ b/pkg/docker/Dockerfile.node20 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.node22 b/pkg/docker/Dockerfile.node22 index 85f8aaab..208e59fc 100644 --- a/pkg/docker/Dockerfile.node22 +++ b/pkg/docker/Dockerfile.node22 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.perl5.38 b/pkg/docker/Dockerfile.perl5.38 index 88ac4961..d5f34033 100644 --- a/pkg/docker/Dockerfile.perl5.38 +++ b/pkg/docker/Dockerfile.perl5.38 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.perl5.40 b/pkg/docker/Dockerfile.perl5.40 index aa67d7cc..6b88a29b 100644 --- a/pkg/docker/Dockerfile.perl5.40 +++ b/pkg/docker/Dockerfile.perl5.40 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.php8.3 b/pkg/docker/Dockerfile.php8.3 index 98bd3843..3174c02d 100644 --- a/pkg/docker/Dockerfile.php8.3 +++ b/pkg/docker/Dockerfile.php8.3 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.php8.4 b/pkg/docker/Dockerfile.php8.4 index 69cdffe7..c6a36da7 100644 --- a/pkg/docker/Dockerfile.php8.4 +++ b/pkg/docker/Dockerfile.php8.4 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.python3.12 b/pkg/docker/Dockerfile.python3.12 index f32fd45b..8402dae7 100644 --- a/pkg/docker/Dockerfile.python3.12 +++ b/pkg/docker/Dockerfile.python3.12 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.python3.12-slim b/pkg/docker/Dockerfile.python3.12-slim index 65ada57c..f4f957cf 100644 --- a/pkg/docker/Dockerfile.python3.12-slim +++ b/pkg/docker/Dockerfile.python3.12-slim @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.python3.13 b/pkg/docker/Dockerfile.python3.13 index f8de3151..dd6a91d4 100644 --- a/pkg/docker/Dockerfile.python3.13 +++ b/pkg/docker/Dockerfile.python3.13 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.python3.13-slim b/pkg/docker/Dockerfile.python3.13-slim index 0b2d3dc7..6ca77616 100644 --- a/pkg/docker/Dockerfile.python3.13-slim +++ b/pkg/docker/Dockerfile.python3.13-slim @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.ruby3.2 b/pkg/docker/Dockerfile.ruby3.2 index d3ab399c..93302277 100644 --- a/pkg/docker/Dockerfile.ruby3.2 +++ b/pkg/docker/Dockerfile.ruby3.2 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.ruby3.3 b/pkg/docker/Dockerfile.ruby3.3 index b83c754b..45fdc963 100644 --- a/pkg/docker/Dockerfile.ruby3.3 +++ b/pkg/docker/Dockerfile.ruby3.3 @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ diff --git a/pkg/docker/Dockerfile.wasm b/pkg/docker/Dockerfile.wasm index dcdb3672..cb6c51a9 100644 --- a/pkg/docker/Dockerfile.wasm +++ b/pkg/docker/Dockerfile.wasm @@ -6,16 +6,36 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.33.0" +LABEL org.opencontainers.image.version="1.34.0" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config libclang-dev cmake \ + && export RUST_VERSION=1.83.0 \ + && export RUSTUP_HOME=/usr/src/unit/rustup \ + && export CARGO_HOME=/usr/src/unit/cargo \ + && export PATH=/usr/src/unit/cargo/bin:$PATH \ + && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ + arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac \ + && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ + && curl -L -O "$url" \ + && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ + && rm rustup-init \ + && rustup --version \ + && cargo --version \ + && rustc --version \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && git clone --depth 1 -b 1.33.0-1 https://github.com/nginx/unit \ + && git clone --depth 1 -b 1.34.0-1 https://github.com/nginx/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ @@ -34,7 +54,8 @@ RUN set -ex \ --openssl \ --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ + --njs \ + --otel" \ && make -j $NCPU -C pkg/contrib .njs \ && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ @@ -45,34 +66,14 @@ RUN set -ex \ && make -j $NCPU unitd \ && install -pm755 build/sbin/unitd /usr/sbin/unitd \ && make clean \ - && apt-get install --no-install-recommends --no-install-suggests -y libclang-dev \ - && export RUST_VERSION=1.80.1 \ - && export RUSTUP_HOME=/usr/src/unit/rustup \ - && export CARGO_HOME=/usr/src/unit/cargo \ - && export PATH=/usr/src/unit/cargo/bin:$PATH \ - && dpkgArch="$(dpkg --print-architecture)" \ - && case "${dpkgArch##*-}" in \ - amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d" ;; \ - arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="1cffbf51e63e634c746f741de50649bbbcbd9dbe1de363c9ecef64e278dba2b2" ;; \ - *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ - esac \ - && url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" \ - && curl -L -O "$url" \ - && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ - && chmod +x rustup-init \ - && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ - && rm rustup-init \ - && rustup --version \ - && cargo --version \ - && rustc --version \ && make -C pkg/contrib .wasmtime \ - && install -pm 755 pkg/contrib/wasmtime/target/release/libwasmtime.so /usr/lib/$(dpkg-architecture -q DEB_HOST_MULTIARCH)/ \ + && install -pm 755 pkg/contrib/wasmtime/artifacts/lib/libwasmtime.so /usr/lib/$(dpkg-architecture -q DEB_HOST_MULTIARCH)/ \ && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure wasm --include-path=`pwd`/pkg/contrib/wasmtime/crates/c-api/include --lib-path=/usr/lib/$(dpkg-architecture -q DEB_HOST_MULTIARCH)/ && ./configure wasm-wasi-component \ + && ./configure wasm --include-path=`pwd`/pkg/contrib/wasmtime/artifacts/include --lib-path=/usr/lib/$(dpkg-architecture -q DEB_HOST_MULTIARCH)/ && ./configure wasm-wasi-component \ && make -j $NCPU wasm-install wasm-wasi-component-install \ && make clean \ && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure wasm --include-path=`pwd`/pkg/contrib/wasmtime/crates/c-api/include --lib-path=/usr/lib/$(dpkg-architecture -q DEB_HOST_MULTIARCH)/ && ./configure wasm-wasi-component \ + && ./configure wasm --include-path=`pwd`/pkg/contrib/wasmtime/artifacts/include --lib-path=/usr/lib/$(dpkg-architecture -q DEB_HOST_MULTIARCH)/ && ./configure wasm-wasi-component \ && make -j $NCPU wasm-install wasm-wasi-component-install \ && cd \ && rm -rf /usr/src/unit \ From noreply at nginx.com Thu Dec 19 20:19:07 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 19 Dec 2024 20:19:07 +0000 (UTC) Subject: [unit] Annotated tag created: 1.34.0 Message-ID: <20241219201907.A7322489E5@pubserv1.nginx> details: https://github.com/nginx/unit/releases/tag/1.34.0 branches: commit: 27bde184dedcbf687db2f314c60c037623318a8d user: Andrew Clayton date: Thu Dec 19 13:13:44 2024 +0000 description: Unit 1.34.0 release. From thresh at nginx.com Thu Dec 19 20:22:24 2024 From: thresh at nginx.com (Konstantin Pavlov) Date: Thu, 19 Dec 2024 12:22:24 -0800 Subject: [unit] Annotated tag created: 1.34.0 In-Reply-To: <20241219201907.A7322489E5@pubserv1.nginx> References: <20241219201907.A7322489E5@pubserv1.nginx> Message-ID: <63c1a1c5-afcc-4288-8347-ed3ec1e86816@nginx.com> Sorry for the spam from the unrelated repo.  This was a bug in the automated diff sender we have and is now fixed. On 19/12/2024 12:19 PM, noreply at nginx.com wrote: > details: https://github.com/nginx/unit/releases/tag/1.34.0 > branches: > commit: 27bde184dedcbf687db2f314c60c037623318a8d > user: Andrew Clayton > date: Thu Dec 19 13:13:44 2024 +0000 > description: > Unit 1.34.0 release. > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://mailman.nginx.org/mailman/listinfo/nginx-devel From noreply at nginx.com Mon Dec 23 16:37:02 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Mon, 23 Dec 2024 16:37:02 +0000 (UTC) Subject: [nginx] Updated security policy to clarify experimental features. Message-ID: <20241223163702.AC388476B8@pubserv1.nginx> details: https://github.com/nginx/nginx/commit/c73fb273acc31bff7c4e469efda5f3fd66c48557 branches: master commit: c73fb273acc31bff7c4e469efda5f3fd66c48557 user: Jordan Zebor date: Mon, 23 Dec 2024 08:07:01 -0800 description: Updated security policy to clarify experimental features. The original security policy language did not capture the scope as intended for experimental features and availability. --- SECURITY.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index f5cfcd788..8e173ed16 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -69,8 +69,7 @@ limiting, or buffer size configurations, or applying changes is impractical. Availability issues excluded from the security release process: - Local file content or upstream response content resulting only in worker process termination. -- Issues with experimental features which result only in worker process -termination. +- Issues with experimental features which result only in availability impact. ## Trusted Configurations and Misconfigurations From noreply at nginx.com Thu Dec 26 14:59:02 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Thu, 26 Dec 2024 14:59:02 +0000 (UTC) Subject: [nginx] QUIC: ignore version negotiation packets. Message-ID: <20241226145902.24DDF47710@pubserv1.nginx> details: https://github.com/nginx/nginx/commit/a52ba8ba0e349585e49073c168e423c12abcf597 branches: master commit: a52ba8ba0e349585e49073c168e423c12abcf597 user: Roman Arutyunyan date: Fri, 13 Dec 2024 13:25:26 +0400 description: QUIC: ignore version negotiation packets. Previously, such packets were treated as long header packets with unknown version 0, and a version negotiation packet was sent in response. This could be used to set up an infinite traffic reflect loop with another nginx instance. Now version negotiation packets are ignored. As per RFC 9000, Section 6.1: An endpoint MUST NOT send a Version Negotiation packet in response to receiving a Version Negotiation packet. --- src/event/quic/ngx_event_quic_transport.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/event/quic/ngx_event_quic_transport.c b/src/event/quic/ngx_event_quic_transport.c index fba098caa..bb13447b5 100644 --- a/src/event/quic/ngx_event_quic_transport.c +++ b/src/event/quic/ngx_event_quic_transport.c @@ -295,6 +295,11 @@ ngx_quic_parse_packet(ngx_quic_header_t *pkt) return NGX_ERROR; } + if (pkt->version == 0) { + /* version negotiation */ + return NGX_ERROR; + } + if (!ngx_quic_supported_version(pkt->version)) { return NGX_ABORT; } From noreply at nginx.com Fri Dec 27 12:15:02 2024 From: noreply at nginx.com (noreply at nginx.com) Date: Fri, 27 Dec 2024 12:15:02 +0000 (UTC) Subject: [nginx] QUIC: fixed accessing a released stream. Message-ID: <20241227121502.B3FA44770F@pubserv1.nginx> details: https://github.com/nginx/nginx/commit/e3a9b6ad08a86e799a3d77da3f2fc507d3c9699e branches: master commit: e3a9b6ad08a86e799a3d77da3f2fc507d3c9699e user: Roman Arutyunyan date: Tue, 10 Dec 2024 18:19:27 +0400 description: QUIC: fixed accessing a released stream. While trying to close a stream in ngx_quic_close_streams() by calling its read event handler, the next stream saved prior to that could be destroyed recursively. This caused a segfault while trying to access the next stream. The way the next stream could be destroyed in HTTP/3 is the following. A request stream read event handler ngx_http_request_handler() could end up calling ngx_http_v3_send_cancel_stream() to report a cancelled request stream in the decoder stream. If sending stream cancellation decoder instruction fails for any reason, and the decoder stream is the next in order after the request stream, the issue is triggered. The fix is to postpone calling read event handlers for all streams being closed to avoid closing a released stream. --- src/event/quic/ngx_event_quic_streams.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/event/quic/ngx_event_quic_streams.c b/src/event/quic/ngx_event_quic_streams.c index 178b805e4..a9a21f578 100644 --- a/src/event/quic/ngx_event_quic_streams.c +++ b/src/event/quic/ngx_event_quic_streams.c @@ -174,7 +174,7 @@ ngx_int_t ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc) { ngx_pool_t *pool; - ngx_queue_t *q; + ngx_queue_t *q, posted_events; ngx_rbtree_t *tree; ngx_connection_t *sc; ngx_rbtree_node_t *node; @@ -197,6 +197,8 @@ ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc) return NGX_OK; } + ngx_queue_init(&posted_events); + node = ngx_rbtree_min(tree->root, tree->sentinel); while (node) { @@ -213,15 +215,21 @@ ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc) } sc->read->error = 1; + sc->read->ready = 1; sc->write->error = 1; - - ngx_quic_set_event(sc->read); - ngx_quic_set_event(sc->write); + sc->write->ready = 1; sc->close = 1; - sc->read->handler(sc->read); + + if (sc->read->posted) { + ngx_delete_posted_event(sc->read); + } + + ngx_post_event(sc->read, &posted_events); } + ngx_event_process_posted((ngx_cycle_t *) ngx_cycle, &posted_events); + if (tree->root == tree->sentinel) { return NGX_OK; }