diff --git a/.github/workflows/build-tarball.yml b/.github/workflows/build-tarball.yml index 5fae318569f7d0..c5911684070fba 100644 --- a/.github/workflows/build-tarball.yml +++ b/.github/workflows/build-tarball.yml @@ -86,7 +86,7 @@ jobs: - name: Environment Information run: npx envinfo - name: Download tarball - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: tarballs path: tarballs diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index da80832102026e..191cfc5e5dfddc 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -27,15 +27,15 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 with: languages: ${{ matrix.language }} config-file: ./.github/codeql-config.yml - name: Autobuild - uses: github/codeql-action/autobuild@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 with: category: /language:${{matrix.language}} diff --git a/.github/workflows/coverage-linux-without-intl.yml b/.github/workflows/coverage-linux-without-intl.yml index 9cefdcff8754d5..c30ae78e303e07 100644 --- a/.github/workflows/coverage-linux-without-intl.yml +++ b/.github/workflows/coverage-linux-without-intl.yml @@ -79,6 +79,6 @@ jobs: - name: Clean tmp run: rm -rf coverage/tmp && rm -rf out - name: Upload - uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0 + uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 with: directory: ./coverage diff --git a/.github/workflows/coverage-linux.yml b/.github/workflows/coverage-linux.yml index bab1d81ed06c71..6d5afb489762e4 100644 --- a/.github/workflows/coverage-linux.yml +++ b/.github/workflows/coverage-linux.yml @@ -79,6 +79,6 @@ jobs: - name: Clean tmp run: rm -rf coverage/tmp && rm -rf out - name: Upload - uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0 + uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 with: directory: ./coverage diff --git a/.github/workflows/coverage-windows.yml b/.github/workflows/coverage-windows.yml index d014e5e2ed4afa..0e68565e962741 100644 --- a/.github/workflows/coverage-windows.yml +++ b/.github/workflows/coverage-windows.yml @@ -71,6 +71,6 @@ jobs: - name: Clean tmp run: npx rimraf ./coverage/tmp - name: Upload - uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0 + uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 with: directory: ./coverage diff --git a/.github/workflows/notify-on-push.yml b/.github/workflows/notify-on-push.yml index 2b85784d56898b..bdda058f104795 100644 --- a/.github/workflows/notify-on-push.yml +++ b/.github/workflows/notify-on-push.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Slack Notification - uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # 2.3.2 + uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # 2.3.3 env: SLACK_COLOR: '#DE512A' SLACK_ICON: https://github.com/nodejs.png?size=48 @@ -57,7 +57,7 @@ jobs: GH_TOKEN: ${{ github.token }} - name: Slack Notification if: ${{ env.INVALID_COMMIT_MESSAGE }} - uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # 2.3.2 + uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # 2.3.3 env: SLACK_COLOR: '#DE512A' SLACK_ICON: https://github.com/nodejs.png?size=48 diff --git a/.github/workflows/notify-on-review-wanted.yml b/.github/workflows/notify-on-review-wanted.yml index b4e3490f31f3d6..96eee3096d8b69 100644 --- a/.github/workflows/notify-on-review-wanted.yml +++ b/.github/workflows/notify-on-review-wanted.yml @@ -33,7 +33,7 @@ jobs: fi - name: Slack Notification - uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # 2.3.2 + uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # 2.3.3 env: MSG_MINIMAL: actions url SLACK_COLOR: '#3d85c6' diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 82bbdcfe4551bc..574703f4b0227b 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -33,7 +33,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0 + uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -43,7 +43,7 @@ jobs: persist-credentials: false - name: Run analysis - uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1 + uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 with: results_file: results.sarif results_format: sarif @@ -73,6 +73,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: Upload to code-scanning - uses: github/codeql-action/upload-sarif@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 + uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 with: sarif_file: results.sarif diff --git a/BUILDING.md b/BUILDING.md index 78f83873cc1f5b..4c46468139f7da 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -122,6 +122,7 @@ platforms. This is true regardless of entries in the table below. | SmartOS | x64 | >= 18 | Tier 2 | | | AIX | ppc64be >=power8 | >= 7.2 TL04 | Tier 2 | | | FreeBSD | x64 | >= 13.2 | Experimental | | +| OpenHarmony | arm64 | >= 5.0 | Experimental | | diff --git a/CHANGELOG.md b/CHANGELOG.md index bb1b85cf163c9d..260b3cda612e96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,7 +40,8 @@ release. -24.1.0
+24.2.0
+24.1.0
24.0.2
24.0.1
24.0.0
diff --git a/README.md b/README.md index 93964e275e7a10..0a7ff9bb1978b7 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,8 @@ For information about the governance of the Node.js project, see **Matteo Collina** <> (he/him) * [mhdawson](https://github.com/mhdawson) - **Michael Dawson** <> (he/him) +* [panva](https://github.com/panva) - + **Filip Skokan** <> (he/him) * [RafaelGSS](https://github.com/RafaelGSS) - **Rafael Gonzaga** <> (he/him) * [RaisinTen](https://github.com/RaisinTen) - @@ -401,14 +403,12 @@ For information about the governance of the Node.js project, see **Xuguang Mei** <> (he/him) * [mhdawson](https://github.com/mhdawson) - **Michael Dawson** <> (he/him) -* [mildsunrise](https://github.com/mildsunrise) - - **Alba Mendez** <> (she/her) * [MoLow](https://github.com/MoLow) - **Moshe Atlow** <> (he/him) * [MrJithil](https://github.com/MrJithil) - **Jithil P Ponnan** <> (he/him) * [panva](https://github.com/panva) - - **Filip Skokan** <> (he/him) + **Filip Skokan** <> (he/him) - [Support me](https://github.com/sponsors/panva) * [pimterry](https://github.com/pimterry) - **Tim Perry** <> (he/him) * [pmarchini](https://github.com/pmarchini) - @@ -611,6 +611,8 @@ For information about the governance of the Node.js project, see **Mikeal Rogers** <> * [miladfarca](https://github.com/miladfarca) - **Milad Fa** <> (he/him) +* [mildsunrise](https://github.com/mildsunrise) - + **Alba Mendez** <> (she/her) * [misterdjules](https://github.com/misterdjules) - **Julien Gilli** <> * [mmarchini](https://github.com/mmarchini) - diff --git a/benchmark/fs/bench-cpSync.js b/benchmark/fs/bench-cpSync.js index 5ee11689e47a8e..fa6350384c69dd 100644 --- a/benchmark/fs/bench-cpSync.js +++ b/benchmark/fs/bench-cpSync.js @@ -4,20 +4,53 @@ const common = require('../common'); const fs = require('fs'); const path = require('path'); const tmpdir = require('../../test/common/tmpdir'); -tmpdir.refresh(); const bench = common.createBenchmark(main, { n: [1, 100, 10_000], + dereference: ['true', 'false'], + force: ['true', 'false'], }); -function main({ n }) { +function prepareTestDirectory() { + const testDir = tmpdir.resolve(`test-cp-${process.pid}`); + fs.mkdirSync(testDir, { recursive: true }); + + fs.writeFileSync(path.join(testDir, 'source.txt'), 'test content'); + + fs.symlinkSync( + path.join(testDir, 'source.txt'), + path.join(testDir, 'link.txt'), + ); + + return testDir; +} + +function main({ n, dereference, force }) { tmpdir.refresh(); - const options = { recursive: true }; - const src = path.join(__dirname, '../../test/fixtures/copy'); + + const src = prepareTestDirectory(); const dest = tmpdir.resolve(`${process.pid}/subdir/cp-bench-${process.pid}`); + + const options = { + recursive: true, + dereference: dereference === 'true', + force: force === 'true', + }; + + if (options.force) { + fs.cpSync(src, dest, { recursive: true }); + } + bench.start(); for (let i = 0; i < n; i++) { - fs.cpSync(src, dest, options); + if (options.force) { + fs.cpSync(src, dest, options); + } else { + const uniqueDest = tmpdir.resolve( + `${process.pid}/subdir/cp-bench-${process.pid}-${i}`, + ); + fs.cpSync(src, uniqueDest, options); + } } bench.end(n); } diff --git a/benchmark/fs/bench-glob.js b/benchmark/fs/bench-glob.js index 02ecf929269054..74612701e2182a 100644 --- a/benchmark/fs/bench-glob.js +++ b/benchmark/fs/bench-glob.js @@ -1,7 +1,11 @@ 'use strict'; const common = require('../common'); -const fs = require('fs'); +const { + glob, + globSync, + promises: { glob: globAsync }, +} = require('fs'); const path = require('path'); const assert = require('node:assert'); @@ -11,7 +15,7 @@ const configs = { n: [1e3], dir: ['lib'], pattern: ['**/*', '*.js', '**/**.js'], - mode: ['async', 'sync'], + mode: ['sync', 'promise', 'callback'], recursive: ['true', 'false'], }; @@ -20,15 +24,33 @@ const bench = common.createBenchmark(main, configs); async function main(config) { const fullPath = path.resolve(benchmarkDirectory, config.dir); const { pattern, recursive, mode } = config; + const options = { cwd: fullPath, recursive }; + const callback = (resolve, reject) => { + glob(pattern, options, (err, matches) => { + if (err) { + reject(err); + } else { + resolve(matches); + } + }); + }; let noDead; bench.start(); for (let i = 0; i < config.n; i++) { - if (mode === 'async') { - noDead = await fs.promises.glob(pattern, { cwd: fullPath, recursive }); - } else { - noDead = fs.globSync(pattern, { cwd: fullPath, recursive }); + switch (mode) { + case 'sync': + noDead = globSync(pattern, options); + break; + case 'promise': + noDead = await globAsync(pattern, options); + break; + case 'callback': + noDead = await new Promise(callback); + break; + default: + throw new Error(`Unknown mode: ${mode}`); } } diff --git a/benchmark/path/join-posix.js b/benchmark/path/join-posix.js index 2e7836650af455..fe4ea4b4a4724a 100644 --- a/benchmark/path/join-posix.js +++ b/benchmark/path/join-posix.js @@ -16,8 +16,8 @@ function main({ n, paths }) { bench.start(); for (let i = 0; i < n; i++) { - if (i % 3 === 0) { - copy[1] = `${orig}${i}`; + if (i % 5 === 0) { + copy[1] = `${orig}/${i}`; posix.join(...copy); } else { posix.join(...args); diff --git a/benchmark/path/join-win32.js b/benchmark/path/join-win32.js index 3ad1c0c7ba2a61..41899dd9240842 100644 --- a/benchmark/path/join-win32.js +++ b/benchmark/path/join-win32.js @@ -16,8 +16,8 @@ function main({ n, paths }) { bench.start(); for (let i = 0; i < n; i++) { - if (i % 3 === 0) { - copy[1] = `${orig}${i}`; + if (i % 5 === 0) { + copy[1] = `${orig}\\${i}`; win32.join(...copy); } else { win32.join(...args); diff --git a/benchmark/path/normalize-posix.js b/benchmark/path/normalize-posix.js index 3e90bfc21aec46..4318ee0b147eda 100644 --- a/benchmark/path/normalize-posix.js +++ b/benchmark/path/normalize-posix.js @@ -17,7 +17,7 @@ const bench = common.createBenchmark(main, { function main({ n, path }) { bench.start(); for (let i = 0; i < n; i++) { - posix.normalize(i % 3 === 0 ? `${path}${i}` : path); + posix.normalize(i % 5 === 0 ? `${path}/${i}` : path); } bench.end(n); } diff --git a/benchmark/path/normalize-win32.js b/benchmark/path/normalize-win32.js index 33af7953ff547d..289b385d3f65a8 100644 --- a/benchmark/path/normalize-win32.js +++ b/benchmark/path/normalize-win32.js @@ -17,7 +17,7 @@ const bench = common.createBenchmark(main, { function main({ n, path }) { bench.start(); for (let i = 0; i < n; i++) { - win32.normalize(i % 3 === 0 ? `${path}${i}` : path); + win32.normalize(i % 5 === 0 ? `${path}\\${i}` : path); } bench.end(n); } diff --git a/benchmark/path/resolve-posix.js b/benchmark/path/resolve-posix.js index 4881947fe46b6d..edc3593bb7f4d9 100644 --- a/benchmark/path/resolve-posix.js +++ b/benchmark/path/resolve-posix.js @@ -4,23 +4,26 @@ const { posix } = require('path'); const bench = common.createBenchmark(main, { paths: [ + 'empty', '', + '.', ['', ''].join('|'), ['foo/bar', '/tmp/file/', '..', 'a/../subfile'].join('|'), ['a/b/c/', '../../..'].join('|'), + ['/a/b/c/', 'abc'].join('|'), ], n: [1e5], }); function main({ n, paths }) { - const args = paths.split('|'); + const args = paths === 'empty' ? [] : paths.split('|'); const copy = [...args]; - const orig = copy[0]; + const orig = copy[0] ?? ''; bench.start(); for (let i = 0; i < n; i++) { - if (i % 3 === 0) { - copy[0] = `${orig}${i}`; + if (i % 5 === 0) { + copy[0] = `${orig}/${i}`; posix.resolve(...copy); } else { posix.resolve(...args); diff --git a/benchmark/path/resolve-win32.js b/benchmark/path/resolve-win32.js index 822b98c2b86c52..a28f2f43e25314 100644 --- a/benchmark/path/resolve-win32.js +++ b/benchmark/path/resolve-win32.js @@ -4,7 +4,9 @@ const { win32 } = require('path'); const bench = common.createBenchmark(main, { paths: [ + 'empty', '', + '.', ['', ''].join('|'), ['c:/ignore', 'd:\\a/b\\c/d', '\\e.exe'].join('|'), ['c:/blah\\blah', 'd:/games', 'c:../a'].join('|'), @@ -13,14 +15,14 @@ const bench = common.createBenchmark(main, { }); function main({ n, paths }) { - const args = paths.split('|'); + const args = paths === 'empty' ? [] : paths.split('|'); const copy = [...args]; - const orig = copy[0]; + const orig = copy[0] ?? ''; bench.start(); for (let i = 0; i < n; i++) { - if (i % 3 === 0) { - copy[0] = `${orig}${i}`; + if (i % 5 === 0) { + copy[0] = `${orig}\\${i}`; win32.resolve(...copy); } else { win32.resolve(...args); diff --git a/common.gypi b/common.gypi index 162faabcefc3bc..96ec81cd81c912 100644 --- a/common.gypi +++ b/common.gypi @@ -38,7 +38,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.16', + 'v8_embedder_string': '-node.17', ##### V8 defaults for Node.js ##### @@ -82,6 +82,7 @@ 'v8_enable_direct_local%': 0, 'v8_enable_map_packing%': 0, 'v8_enable_pointer_compression_shared_cage%': 0, + 'v8_enable_external_code_space%': 0, 'v8_enable_sandbox%': 0, 'v8_enable_v8_checks%': 0, 'v8_enable_zone_compression%': 0, @@ -115,12 +116,13 @@ ['target_arch in "arm ia32 mips mipsel"', { 'v8_enable_pointer_compression': 0, 'v8_enable_31bit_smis_on_64bit_arch': 0, + 'v8_enable_external_code_space': 0, 'v8_enable_sandbox': 0 }], ['target_arch in "ppc64 s390x"', { 'v8_enable_backtrace': 1, }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'node_section_ordering_info%': '' }], ['OS == "zos"', { @@ -202,7 +204,7 @@ 'LLVM_LTO': 'YES', }, }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'conditions': [ ['node_section_ordering_info!=""', { 'cflags': [ @@ -230,7 +232,7 @@ # frames otherwise, even with --call-graph dwarf. 'cflags': [ '-fno-omit-frame-pointer' ], }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'conditions': [ ['enable_pgo_generate=="true"', { 'cflags': ['<(pgo_generate)'], @@ -458,6 +460,9 @@ ['v8_enable_sandbox == 1', { 'defines': ['V8_ENABLE_SANDBOX',], }], + ['v8_enable_external_code_space == 1', { + 'defines': ['V8_EXTERNAL_CODE_SPACE',], + }], ['v8_deprecation_warnings == 1', { 'defines': ['V8_DEPRECATION_WARNINGS',], }], @@ -498,11 +503,11 @@ 'NOMINMAX', ], }], - [ 'OS in "linux freebsd openbsd solaris aix os400"', { + [ 'OS in "linux freebsd openbsd solaris aix os400 openharmony"', { 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], - [ 'OS in "linux freebsd openbsd solaris android aix os400 cloudabi"', { + [ 'OS in "linux freebsd openbsd solaris android aix os400 cloudabi openharmony"', { 'cflags': [ '-Wall', '-Wextra', '-Wno-unused-parameter', ], 'cflags_cc': [ '-fno-rtti', diff --git a/configure.py b/configure.py index 83f700af4f86b7..a648c21ffe11ed 100755 --- a/configure.py +++ b/configure.py @@ -45,7 +45,7 @@ parser = argparse.ArgumentParser() valid_os = ('win', 'mac', 'solaris', 'freebsd', 'openbsd', 'linux', - 'android', 'aix', 'cloudabi', 'os400', 'ios') + 'android', 'aix', 'cloudabi', 'os400', 'ios', 'openharmony') valid_arch = ('arm', 'arm64', 'ia32', 'mips', 'mipsel', 'mips64el', 'ppc64', 'x64', 'x86', 'x86_64', 's390x', 'riscv64', 'loong64') valid_arm_float_abi = ('soft', 'softfp', 'hard') @@ -277,7 +277,7 @@ shared_optgroup.add_argument('--shared-http-parser-libname', action='store', dest='shared_http_parser_libname', - default='http_parser', + default='llhttp', help='alternative lib name to link to [default: %(default)s]') shared_optgroup.add_argument('--shared-http-parser-libpath', @@ -1718,7 +1718,15 @@ def configure_v8(o, configs): o['variables']['v8_enable_maglev'] = B(not options.v8_disable_maglev and o['variables']['target_arch'] in maglev_enabled_architectures) o['variables']['v8_enable_pointer_compression'] = 1 if options.enable_pointer_compression else 0 - o['variables']['v8_enable_sandbox'] = 1 if options.enable_pointer_compression else 0 + # Using the sandbox requires always allocating array buffer backing stores in the sandbox. + # We currently have many backing stores tied to pointers from C++ land that are not + # even necessarily dynamic (e.g. in static storage) for fast communication between JS and C++. + # Until we manage to get rid of all those, v8_enable_sandbox cannot be used. + # Note that enabling pointer compression without enabling sandbox is unsupported by V8, + # so this can be broken at any time. + o['variables']['v8_enable_sandbox'] = 0 + o['variables']['v8_enable_pointer_compression_shared_cage'] = 1 if options.enable_pointer_compression else 0 + o['variables']['v8_enable_external_code_space'] = 1 if options.enable_pointer_compression else 0 o['variables']['v8_enable_31bit_smis_on_64bit_arch'] = 1 if options.enable_pointer_compression else 0 o['variables']['v8_enable_extensible_ro_snapshot'] = 0 o['variables']['v8_trace_maps'] = 1 if options.trace_maps else 0 @@ -2265,7 +2273,7 @@ def make_bin_override(): configure_node_cctest_sources(output) configure_napi(output) configure_library('zlib', output) -configure_library('http_parser', output) +configure_library('http_parser', output, pkgname='libllhttp') configure_library('libuv', output) configure_library('ada', output) configure_library('simdjson', output) diff --git a/deps/ada/ada.cpp b/deps/ada/ada.cpp index f6704596ced611..d4f228ebfc3f06 100644 --- a/deps/ada/ada.cpp +++ b/deps/ada/ada.cpp @@ -1,4 +1,4 @@ -/* auto-generated on 2025-04-24 20:04:09 -0400. Do not edit! */ +/* auto-generated on 2025-04-28 12:16:36 -0400. Do not edit! */ /* begin file src/ada.cpp */ #include "ada.h" /* begin file src/checkers.cpp */ @@ -56,8 +56,8 @@ ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept { } // We have 0x followed by some characters, we need to check that they are // hexadecimals. - return std::all_of(view.begin() + 2, view.end(), - ada::unicode::is_lowercase_hex); + view.remove_prefix(2); + return std::ranges::all_of(view, ada::unicode::is_lowercase_hex); } // for use with path_signature, we include all characters that need percent @@ -10421,6 +10421,8 @@ ADA_POP_DISABLE_WARNINGS #include #endif +#include + namespace ada::unicode { constexpr bool is_tabs_or_newline(char c) noexcept { @@ -10461,8 +10463,7 @@ ada_really_inline bool has_tabs_or_newline( std::string_view user_input) noexcept { // first check for short strings in which case we do it naively. if (user_input.size() < 16) { // slow path - return std::any_of(user_input.begin(), user_input.end(), - is_tabs_or_newline); + return std::ranges::any_of(user_input, is_tabs_or_newline); } // fast path for long strings (expected to be common) size_t i = 0; @@ -10500,8 +10501,7 @@ ada_really_inline bool has_tabs_or_newline( std::string_view user_input) noexcept { // first check for short strings in which case we do it naively. if (user_input.size() < 16) { // slow path - return std::any_of(user_input.begin(), user_input.end(), - is_tabs_or_newline); + return std::ranges::any_of(user_input, is_tabs_or_newline); } // fast path for long strings (expected to be common) size_t i = 0; @@ -10832,10 +10832,9 @@ bool percent_encode(const std::string_view input, const uint8_t character_set[], std::string& out) { ada_log("percent_encode ", input, " to output string while ", append ? "appending" : "overwriting"); - auto pointer = - std::find_if(input.begin(), input.end(), [character_set](const char c) { - return character_sets::bit_at(character_set, c); - }); + auto pointer = std::ranges::find_if(input, [character_set](const char c) { + return character_sets::bit_at(character_set, c); + }); ada_log("percent_encode done checking, moved to ", std::distance(input.begin(), pointer)); @@ -11850,6 +11849,7 @@ ada_warn_unused std::string to_string(ada::state state) { #include #include +#include #include #include @@ -11857,8 +11857,7 @@ namespace ada { bool url::parse_opaque_host(std::string_view input) { ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]"); - if (std::ranges::any_of(input.begin(), input.end(), - ada::unicode::is_forbidden_host_code_point)) { + if (std::ranges::any_of(input, ada::unicode::is_forbidden_host_code_point)) { return is_valid = false; } @@ -12725,6 +12724,7 @@ bool url::set_href(const std::string_view input) { /* begin file src/parser.cpp */ #include +#include namespace ada::parser { @@ -13344,7 +13344,7 @@ result_type parse_url_impl(std::string_view user_input, // to optimize it. if (view.ends_with(' ')) { std::string modified_view = - std::string(view.begin(), view.end() - 1) + "%20"; + std::string(view.substr(0, view.size() - 1)) + "%20"; url.update_base_pathname(unicode::percent_encode( modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE)); } else { @@ -13694,6 +13694,7 @@ namespace ada { /* end file src/url_components.cpp */ /* begin file src/url_aggregator.cpp */ +#include #include #include @@ -13913,7 +13914,7 @@ bool url_aggregator::set_protocol(const std::string_view input) { if (pointer != view.end() && *pointer == ':') { return parse_scheme_with_colon( - std::string_view(view.data(), pointer - view.begin() + 1)); + view.substr(0, pointer - view.begin() + 1)); } return false; } @@ -14175,8 +14176,8 @@ ada_really_inline bool url_aggregator::parse_host(std::string_view input) { ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(), " bytes]"); - if (std::any_of(host.value().begin(), host.value().end(), - ada::unicode::is_forbidden_domain_code_point)) { + if (std::ranges::any_of(host.value(), + ada::unicode::is_forbidden_domain_code_point)) { return is_valid = false; } @@ -14868,8 +14869,7 @@ bool url_aggregator::parse_opaque_host(std::string_view input) { ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]"); ADA_ASSERT_TRUE(validate()); ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); - if (std::any_of(input.begin(), input.end(), - ada::unicode::is_forbidden_host_code_point)) { + if (std::ranges::any_of(input, ada::unicode::is_forbidden_host_code_point)) { return is_valid = false; } diff --git a/deps/ada/ada.h b/deps/ada/ada.h index 071a54e9fad38d..d1a61501de0815 100644 --- a/deps/ada/ada.h +++ b/deps/ada/ada.h @@ -1,4 +1,4 @@ -/* auto-generated on 2025-04-24 20:04:09 -0400. Do not edit! */ +/* auto-generated on 2025-04-28 12:16:36 -0400. Do not edit! */ /* begin file include/ada.h */ /** * @file ada.h @@ -4115,7 +4115,6 @@ void swap(expected &lhs, #endif /* end file include/ada/expected.h */ -#if ADA_INCLUDE_URL_PATTERN /* begin file include/ada/url_pattern_regex.h */ /** * @file url_search_params.h @@ -4131,6 +4130,7 @@ void swap(expected &lhs, #include #endif // ADA_USE_UNSAFE_STD_REGEX_PROVIDER +#if ADA_INCLUDE_URL_PATTERN namespace ada::url_pattern_regex { template @@ -4175,7 +4175,7 @@ class std_regex_provider final { #endif // ADA_USE_UNSAFE_STD_REGEX_PROVIDER } // namespace ada::url_pattern_regex - +#endif // ADA_INCLUDE_URL_PATTERN #endif // ADA_URL_PATTERN_REGEX_H /* end file include/ada/url_pattern_regex.h */ /* begin file include/ada/url_pattern_init.h */ @@ -4209,6 +4209,7 @@ enum class errors : uint8_t { type_error }; #include #endif // ADA_TESTING +#if ADA_INCLUDE_URL_PATTERN namespace ada { // Important: C++20 allows us to use concept rather than `using` or `typedef @@ -4312,10 +4313,9 @@ struct url_pattern_init { std::optional base_url{}; }; } // namespace ada - +#endif // ADA_INCLUDE_URL_PATTERN #endif // ADA_URL_PATTERN_INIT_H /* end file include/ada/url_pattern_init.h */ -#endif // ADA_INCLUDE_URL_PATTERN /** * @private @@ -4378,7 +4378,6 @@ tl::expected, errors> parse_url_pattern_impl( #ifndef ADA_PARSER_INL_H #define ADA_PARSER_INL_H -#if ADA_INCLUDE_URL_PATTERN /* begin file include/ada/url_pattern.h */ /** * @file url_pattern.h @@ -5014,9 +5013,6 @@ inline std::ostream &operator<<(std::ostream &out, const ada::url &u); #endif // ADA_URL_H /* end file include/ada/url.h */ -#if ADA_INCLUDE_URL_PATTERN -#endif // ADA_INCLUDE_URL_PATTERN - namespace ada { template @@ -5088,6 +5084,7 @@ std::string href_from_file(std::string_view path); #include #endif // ADA_TESTING +#if ADA_INCLUDE_URL_PATTERN namespace ada { enum class url_pattern_part_type : uint8_t { @@ -5420,9 +5417,8 @@ class url_pattern { */ bool ignore_case_ = false; }; - } // namespace ada - +#endif // ADA_INCLUDE_URL_PATTERN #endif /* end file include/ada/url_pattern.h */ /* begin file include/ada/url_pattern_helpers.h */ @@ -5438,6 +5434,7 @@ class url_pattern { #include #include +#if ADA_INCLUDE_URL_PATTERN namespace ada { enum class errors : uint8_t; } @@ -5769,10 +5766,9 @@ std::string generate_segment_wildcard_regexp( url_pattern_compile_component_options options); } // namespace ada::url_pattern_helpers - +#endif // ADA_INCLUDE_URL_PATTERN #endif /* end file include/ada/url_pattern_helpers.h */ -#endif // ADA_INCLUDE_URL_PATTERN #include #include @@ -8915,7 +8911,6 @@ url_search_params_entries_iter::next() { #endif // ADA_URL_SEARCH_PARAMS_INL_H /* end file include/ada/url_search_params-inl.h */ -#if ADA_INCLUDE_URL_PATTERN /* begin file include/ada/url_pattern-inl.h */ /** * @file url_pattern-inl.h @@ -8929,6 +8924,7 @@ url_search_params_entries_iter::next() { #include #include +#if ADA_INCLUDE_URL_PATTERN namespace ada { inline bool url_pattern_init::operator==(const url_pattern_init& other) const { @@ -9397,7 +9393,7 @@ result> url_pattern::match( } } // namespace ada - +#endif // ADA_INCLUDE_URL_PATTERN #endif /* end file include/ada/url_pattern-inl.h */ /* begin file include/ada/url_pattern_helpers-inl.h */ @@ -9412,6 +9408,7 @@ result> url_pattern::match( #include +#if ADA_INCLUDE_URL_PATTERN namespace ada::url_pattern_helpers { #ifdef ADA_TESTING inline std::string to_string(token_type type) { @@ -10488,10 +10485,9 @@ constructor_string_parser::parse(std::string_view input) { } } // namespace ada::url_pattern_helpers - +#endif // ADA_INCLUDE_URL_PATTERN #endif /* end file include/ada/url_pattern_helpers-inl.h */ -#endif // ADA_INCLUDE_URL_PATTERN // Public API /* begin file include/ada/ada_version.h */ @@ -10502,14 +10498,14 @@ constructor_string_parser::parse(std::string_view input) { #ifndef ADA_ADA_VERSION_H #define ADA_ADA_VERSION_H -#define ADA_VERSION "3.2.3" +#define ADA_VERSION "3.2.4" namespace ada { enum { ADA_VERSION_MAJOR = 3, ADA_VERSION_MINOR = 2, - ADA_VERSION_REVISION = 3, + ADA_VERSION_REVISION = 4, }; } // namespace ada @@ -10523,8 +10519,6 @@ enum { #ifndef ADA_IMPLEMENTATION_INL_H #define ADA_IMPLEMENTATION_INL_H -#if ADA_INCLUDE_URL_PATTERN -#endif // ADA_INCLUDE_URL_PATTERN #include diff --git a/deps/cares/cares.gyp b/deps/cares/cares.gyp index c34ad7370ca45a..fee055c079f013 100644 --- a/deps/cares/cares.gyp +++ b/deps/cares/cares.gyp @@ -248,6 +248,10 @@ '-lnsl' ] } + }], + [ 'OS=="openharmony"', { + 'include_dirs': [ 'config/openharmony' ], + 'sources': [ 'config/openharmony/ares_config.h' ], }] ] } diff --git a/deps/cares/config/openharmony/ares_config.h b/deps/cares/config/openharmony/ares_config.h new file mode 100644 index 00000000000000..ec9f81d40e6a1e --- /dev/null +++ b/deps/cares/config/openharmony/ares_config.h @@ -0,0 +1,573 @@ +/* src/lib/ares_config.h. Generated from ares_config.h.in by configure. */ +/* src/lib/ares_config.h.in. Generated from configure.ac by autoheader. */ + +/* a suitable file/device to read random data from */ +#define CARES_RANDOM_FILE "/dev/urandom" + +/* Set to 1 if non-pubilc shared library symbols are hidden */ +#define CARES_SYMBOL_HIDING 1 + +/* Threading enabled */ +#define CARES_THREADS 1 + +/* the signed version of size_t */ +#define CARES_TYPEOF_ARES_SSIZE_T ssize_t + +/* Use resolver library to configure cares */ +/* #undef CARES_USE_LIBRESOLV */ + +/* if a /etc/inet dir is being used */ +/* #undef ETC_INET */ + +/* gethostname() arg2 type */ +#define GETHOSTNAME_TYPE_ARG2 size_t + +/* getnameinfo() arg1 type */ +#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * + +/* getnameinfo() arg2 type */ +#define GETNAMEINFO_TYPE_ARG2 socklen_t + +/* getnameinfo() arg4 and 6 type */ +#define GETNAMEINFO_TYPE_ARG46 socklen_t + +/* getnameinfo() arg7 type */ +#define GETNAMEINFO_TYPE_ARG7 int + +/* number of arguments for getservbyname_r() */ +/* #undef GETSERVBYNAME_R_ARGS */ + +/* number of arguments for getservbyport_r() */ +#define GETSERVBYPORT_R_ARGS 6 + +/* Define to 1 if you have AF_INET6 */ +#define HAVE_AF_INET6 1 + +/* Define to 1 if you have `arc4random_buf` */ +/* #undef HAVE_ARC4RANDOM_BUF */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_COMPAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_AVAILABILITYMACROS_H */ + +/* Define to 1 if you have `clock_gettime` */ +#define HAVE_CLOCK_GETTIME 1 + +/* clock_gettime() with CLOCK_MONOTONIC support */ +#define HAVE_CLOCK_GETTIME_MONOTONIC 1 + +/* Define to 1 if you have `closesocket` */ +/* #undef HAVE_CLOSESOCKET */ + +/* Define to 1 if you have `CloseSocket` */ +/* #undef HAVE_CLOSESOCKET_CAMEL */ + +/* Define to 1 if you have `connect` */ +#define HAVE_CONNECT 1 + +/* Define to 1 if you have `ConvertInterfaceIndexToLuid` */ +/* #undef HAVE_CONVERTINTERFACEINDEXTOLUID */ + +/* Define to 1 if you have `ConvertInterfaceLuidToNameA` */ +/* #undef HAVE_CONVERTINTERFACELUIDTONAMEA */ + +/* define if the compiler supports basic C++14 syntax */ +#define HAVE_CXX14 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have `epoll_{create1,ctl,wait}` */ +#define HAVE_EPOLL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have `fcntl` */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* fcntl() with O_NONBLOCK support */ +#define HAVE_FCNTL_O_NONBLOCK 1 + +/* Define to 1 if you have `getenv` */ +#define HAVE_GETENV 1 + +/* Define to 1 if you have `gethostname` */ +#define HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have `getifaddrs` */ +#define HAVE_GETIFADDRS 1 + +/* Define to 1 if you have `getnameinfo` */ +#define HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have `getrandom` */ +#define HAVE_GETRANDOM 1 + +/* Define to 1 if you have `getservbyport_r` */ +/* #undef HAVE_GETSERVBYPORT_R 1 */ + +/* Define to 1 if you have `gettimeofday` */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IFADDRS_H 1 + +/* Define to 1 if you have `if_indextoname` */ +#define HAVE_IF_INDEXTONAME 1 + +/* Define to 1 if you have `if_nametoindex` */ +#define HAVE_IF_NAMETOINDEX 1 + +/* Define to 1 if you have `inet_net_pton` */ +#define HAVE_INET_NET_PTON 1 + +/* Define to 1 if you have `inet_ntop` */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have `inet_pton` */ +#define HAVE_INET_PTON 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have `ioctl` */ +#define HAVE_IOCTL 1 + +/* Define to 1 if you have `ioctlsocket` */ +/* #undef HAVE_IOCTLSOCKET */ + +/* Define to 1 if you have `IoctlSocket` */ +/* #undef HAVE_IOCTLSOCKET_CAMEL */ + +/* ioctlsocket() with FIONBIO support */ +/* #undef HAVE_IOCTLSOCKET_FIONBIO */ + +/* ioctl() with FIONBIO support */ +#define HAVE_IOCTL_FIONBIO 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IPHLPAPI_H */ + +/* Define to 1 if you have `kqueue` */ +/* #undef HAVE_KQUEUE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#define HAVE_LONGLONG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MALLOC_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MINIX_CONFIG_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MSWSOCK_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETIOAPI_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NTDEF_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NTSTATUS_H */ + +/* Define to 1 if you have PF_INET6 */ +#define HAVE_PF_INET6 1 + +/* Define to 1 if you have `pipe` */ +#define HAVE_PIPE 1 + +/* Define to 1 if you have `pipe2` */ +#define HAVE_PIPE2 1 + +/* Define to 1 if you have `poll` */ +#define HAVE_POLL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_POLL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PTHREAD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PTHREAD_NP_H */ + +/* Have PTHREAD_PRIO_INHERIT. */ +#define HAVE_PTHREAD_PRIO_INHERIT 1 + +/* Define to 1 if you have `recv` */ +#define HAVE_RECV 1 + +/* Define to 1 if you have `recvfrom` */ +#define HAVE_RECVFROM 1 + +/* Define to 1 if you have `send` */ +#define HAVE_SEND 1 + +/* Define to 1 if you have `setsockopt` */ +#define HAVE_SETSOCKOPT 1 + +/* setsockopt() with SO_NONBLOCK support */ +/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ + +/* Define to 1 if you have `socket` */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SOCKET_H */ + +/* socklen_t */ +#define HAVE_SOCKLEN_T /**/ + +/* Define to 1 if you have `stat` */ +#define HAVE_STAT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have `strcasecmp` */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have `strdup` */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have `stricmp` */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have `strncasecmp` */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have `strncmpi` */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have `strnicmp` */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if the system has the type `struct addrinfo'. */ +#define HAVE_STRUCT_ADDRINFO 1 + +/* Define to 1 if `ai_flags' is a member of `struct addrinfo'. */ +#define HAVE_STRUCT_ADDRINFO_AI_FLAGS 1 + +/* Define to 1 if the system has the type `struct in6_addr'. */ +#define HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if the system has the type `struct sockaddr_in6'. */ +#define HAVE_STRUCT_SOCKADDR_IN6 1 + +/* Define to 1 if `sin6_scope_id' is a member of `struct sockaddr_in6'. */ +#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define to 1 if the system has the type `struct sockaddr_storage'. */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if the system has the type `struct timeval'. */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_EPOLL_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EVENT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_FILIO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RANDOM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Whether user namespaces are available */ +#define HAVE_USER_NAMESPACE 1 + +/* Whether UTS namespaces are available */ +#define HAVE_UTS_NAMESPACE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINSOCK2_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINTERNL_H */ + +/* Define to 1 if you have `writev` */ +#define HAVE_WRITEV 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WS2IPDEF_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WS2TCPIP_H */ + +/* Define to 1 if you have `__system_property_get` */ +/* #undef HAVE___SYSTEM_PROPERTY_GET */ + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "c-ares" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "c-ares mailing list: http://lists.haxx.se/listinfo/c-ares" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "c-ares" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "c-ares 1.26.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "c-ares" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.26.0" + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef PTHREAD_CREATE_JOINABLE */ + +/* recvfrom() arg5 qualifier */ +#define RECVFROM_QUAL_ARG5 + +/* recvfrom() arg1 type */ +#define RECVFROM_TYPE_ARG1 int + +/* recvfrom() arg2 type */ +#define RECVFROM_TYPE_ARG2 void * + +/* recvfrom() arg3 type */ +#define RECVFROM_TYPE_ARG3 size_t + +/* recvfrom() arg4 type */ +#define RECVFROM_TYPE_ARG4 int + +/* recvfrom() arg5 type */ +#define RECVFROM_TYPE_ARG5 struct sockaddr * + +/* recvfrom() return value */ +#define RECVFROM_TYPE_RETV ssize_t + +/* recv() arg1 type */ +#define RECV_TYPE_ARG1 int + +/* recv() arg2 type */ +#define RECV_TYPE_ARG2 void * + +/* recv() arg3 type */ +#define RECV_TYPE_ARG3 size_t + +/* recv() arg4 type */ +#define RECV_TYPE_ARG4 int + +/* recv() return value */ +#define RECV_TYPE_RETV ssize_t + +/* send() arg2 qualifier */ +#define SEND_QUAL_ARG2 + +/* send() arg1 type */ +#define SEND_TYPE_ARG1 int + +/* send() arg2 type */ +#define SEND_TYPE_ARG2 void * + +/* send() arg3 type */ +#define SEND_TYPE_ARG3 size_t + +/* send() arg4 type */ +#define SEND_TYPE_ARG4 int + +/* send() return value */ +#define SEND_TYPE_RETV ssize_t + +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#define STDC_HEADERS 1 + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable general extensions on macOS. */ +#ifndef _DARWIN_C_SOURCE +# define _DARWIN_C_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable X/Open compliant socket functions that do not require linking + with -lxnet on HP-UX 11.11. */ +#ifndef _HPUX_ALT_XOPEN_SOCKET_API +# define _HPUX_ALT_XOPEN_SOCKET_API 1 +#endif +/* Identify the host operating system as Minix. + This macro does not affect the system headers' behavior. + A future release of Autoconf may stop defining this macro. */ +#ifndef _MINIX +/* # undef _MINIX */ +#endif +/* Enable general extensions on NetBSD. + Enable NetBSD compatibility extensions on Minix. */ +#ifndef _NETBSD_SOURCE +# define _NETBSD_SOURCE 1 +#endif +/* Enable OpenBSD compatibility extensions on NetBSD. + Oddly enough, this does nothing on OpenBSD. */ +#ifndef _OPENBSD_SOURCE +# define _OPENBSD_SOURCE 1 +#endif +/* Define to 1 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_SOURCE +/* # undef _POSIX_SOURCE */ +#endif +/* Define to 2 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_1_SOURCE +/* # undef _POSIX_1_SOURCE */ +#endif +/* Enable POSIX-compatible threading on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ +#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ +#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ +# define __STDC_WANT_IEC_60559_BFP_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ +#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ +# define __STDC_WANT_IEC_60559_DFP_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ +#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ +# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ +#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ +# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ +#ifndef __STDC_WANT_LIB_EXT2__ +# define __STDC_WANT_LIB_EXT2__ 1 +#endif +/* Enable extensions specified by ISO/IEC 24747:2009. */ +#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ +# define __STDC_WANT_MATH_SPEC_FUNCS__ 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable X/Open extensions. Define to 500 only if necessary + to make mbstate_t available. */ +#ifndef _XOPEN_SOURCE +/* # undef _XOPEN_SOURCE */ +#endif + + +/* Version number of package */ +#define VERSION "1.26.0" + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/deps/corepack/CHANGELOG.md b/deps/corepack/CHANGELOG.md index ad0bba51c6b83f..e4f0b185a73616 100644 --- a/deps/corepack/CHANGELOG.md +++ b/deps/corepack/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [0.33.0](https://github.com/nodejs/corepack/compare/v0.32.0...v0.33.0) (2025-06-02) + + +### Features + +* Adds guard to avoid stepping on Yarn's feet ([#714](https://github.com/nodejs/corepack/issues/714)) ([5fc3691](https://github.com/nodejs/corepack/commit/5fc3691354eb5bdeca17a9495b234584353f0151)) +* update package manager versions ([#671](https://github.com/nodejs/corepack/issues/671)) ([b45b3a3](https://github.com/nodejs/corepack/commit/b45b3a3244bacfbaf65188ae8c04209a1e98307d)) + + +### Bug Fixes + +* debug text typo ([#698](https://github.com/nodejs/corepack/issues/698)) ([0b94797](https://github.com/nodejs/corepack/commit/0b94797f96e30e46e466873fe7d437d0471cd92c)) + ## [0.32.0](https://github.com/nodejs/corepack/compare/v0.31.0...v0.32.0) (2025-02-28) diff --git a/deps/corepack/README.md b/deps/corepack/README.md index 67d396d5ca9642..079746ee796366 100644 --- a/deps/corepack/README.md +++ b/deps/corepack/README.md @@ -286,8 +286,8 @@ same major line. Should you need to upgrade to a new major, use an explicit package manager, and to not update the Last Known Good version when it downloads a new version of the same major line. -- `COREPACK_ENABLE_AUTO_PIN` can be set to `0` to prevent Corepack from - updating the `packageManager` field when it detects that the local package +- `COREPACK_ENABLE_AUTO_PIN` can be set to `1` to instruct Corepack to + update the `packageManager` field when it detects that the local package doesn't list it. In general we recommend to always list a `packageManager` field (which you can easily set through `corepack use [name]@[version]`), as it ensures that your project installs are always deterministic. diff --git a/deps/corepack/dist/lib/corepack.cjs b/deps/corepack/dist/lib/corepack.cjs index 7a098cbe250aab..c6854077d0fa6b 100644 --- a/deps/corepack/dist/lib/corepack.cjs +++ b/deps/corepack/dist/lib/corepack.cjs @@ -21683,7 +21683,7 @@ function String2(descriptor, ...args) { } // package.json -var version = "0.32.0"; +var version = "0.33.0"; // sources/Engine.ts var import_fs9 = __toESM(require("fs")); @@ -21697,7 +21697,7 @@ var import_valid4 = __toESM(require_valid2()); var config_default = { definitions: { npm: { - default: "11.1.0+sha1.dba08f7d0f5301ebedaf968b4f74b2282f97a750", + default: "11.4.1+sha1.80350af543069991de20657ebcd07d9624cfad06", fetchLatestFrom: { type: "npm", package: "npm" @@ -21734,7 +21734,7 @@ var config_default = { } }, pnpm: { - default: "10.5.2+sha1.ca68c0441df195b7e2992f1d1cb12fb731f82d78", + default: "10.11.0+sha1.4048eeefd564ff1ab248fac3e2854d38245fe2f1", fetchLatestFrom: { type: "npm", package: "pnpm" @@ -21798,7 +21798,7 @@ var config_default = { package: "yarn" }, transparent: { - default: "4.6.0+sha224.acd0786f07ffc6c933940eb65fc1d627131ddf5455bddcc295dc90fd", + default: "4.9.1+sha224.4285002185abb91fe2b781f27fd1e078086c37a7b095f6ea4ee25971", commands: [ [ "yarn", @@ -22105,6 +22105,10 @@ async function getProxyAgent(input) { } // sources/corepackUtils.ts +var YARN_SWITCH_REGEX = /[/\\]switch[/\\]bin[/\\]/; +function isYarnSwitchPath(p) { + return YARN_SWITCH_REGEX.test(p); +} function getRegistryFromPackageManagerSpec(spec) { return process.env.COREPACK_NPM_REGISTRY ? spec.npmRegistry ?? spec.registry : spec.registry; } @@ -22896,7 +22900,7 @@ var Engine = class { case `NoSpec`: { if (typeof locator.reference === `function`) fallbackDescriptor.range = await locator.reference(); - if (import_process3.default.env.COREPACK_ENABLE_AUTO_PIN !== `0`) { + if (import_process3.default.env.COREPACK_ENABLE_AUTO_PIN === `1`) { const resolved = await this.resolveDescriptor(fallbackDescriptor, { allowTags: true }); if (resolved === null) throw new UsageError(`Failed to successfully resolve '${fallbackDescriptor.range}' to a valid ${fallbackDescriptor.name} release`); @@ -22906,7 +22910,7 @@ var Engine = class { console.error(); await setLocalPackageManager(import_path9.default.dirname(result.target), installSpec); } - log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} in the absence of "packageManage" field in ${result.target}`); + log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} in the absence of "packageManager" field in ${result.target}`); return fallbackDescriptor; } case `Found`: { @@ -23070,6 +23074,10 @@ var DisableCommand = class extends Command { async removePosixLink(installDirectory, binName) { const file = import_path10.default.join(installDirectory, binName); try { + if (binName.includes(`yarn`) && isYarnSwitchPath(await import_fs11.default.promises.realpath(file))) { + console.warn(`${binName} is already installed in ${file} and points to a Yarn Switch install - skipping`); + return; + } await import_fs11.default.promises.unlink(file); } catch (err) { if (err.code !== `ENOENT`) { @@ -23147,6 +23155,10 @@ var EnableCommand = class extends Command { const symlink = import_path11.default.relative(installDirectory, import_path11.default.join(distFolder, `${binName}.js`)); if (import_fs12.default.existsSync(file)) { const currentSymlink = await import_fs12.default.promises.readlink(file); + if (binName.includes(`yarn`) && isYarnSwitchPath(await import_fs12.default.promises.realpath(file))) { + console.warn(`${binName} is already installed in ${file} and points to a Yarn Switch install - skipping`); + return; + } if (currentSymlink !== symlink) { await import_fs12.default.promises.unlink(file); } else { diff --git a/deps/corepack/package.json b/deps/corepack/package.json index 75f5725328a605..7bf3d9e6604a50 100644 --- a/deps/corepack/package.json +++ b/deps/corepack/package.json @@ -1,6 +1,6 @@ { "name": "corepack", - "version": "0.32.0", + "version": "0.33.0", "homepage": "https://github.com/nodejs/corepack#readme", "bugs": { "url": "https://github.com/nodejs/corepack/issues" @@ -16,21 +16,21 @@ "./package.json": "./package.json" }, "license": "MIT", - "packageManager": "yarn@4.6.0+sha512.5383cc12567a95f1d668fbe762dfe0075c595b4bfff433be478dbbe24e05251a8e8c3eb992a986667c1d53b6c3a9c85b8398c35a960587fbd9fa3a0915406728", + "packageManager": "yarn@4.9.0+sha224.dce6c5df199861784bd9b0eecb2a228df97e3f18a02b1bb75ff98383", "devDependencies": { "@types/debug": "^4.1.5", "@types/node": "^20.4.6", "@types/proxy-from-env": "^1", "@types/semver": "^7.1.0", "@types/which": "^3.0.0", - "@yarnpkg/eslint-config": "^2.0.0", + "@yarnpkg/eslint-config": "^3.0.0", "@yarnpkg/fslib": "^3.0.0-rc.48", "@zkochan/cmd-shim": "^6.0.0", "better-sqlite3": "^11.7.2", "clipanion": "patch:clipanion@npm%3A3.2.1#~/.yarn/patches/clipanion-npm-3.2.1-fc9187f56c.patch", "debug": "^4.1.1", "esbuild": "^0.25.0", - "eslint": "^8.57.0", + "eslint": "^9.22.0", "proxy-from-env": "^1.1.0", "semver": "^7.6.3", "supports-color": "^10.0.0", diff --git a/deps/googletest/include/gtest/gtest-printers.h b/deps/googletest/include/gtest/gtest-printers.h index 198a7693493a33..048c32db2e7c2e 100644 --- a/deps/googletest/include/gtest/gtest-printers.h +++ b/deps/googletest/include/gtest/gtest-printers.h @@ -104,15 +104,19 @@ #ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#include #include #include +#include #include // NOLINT #include #include +#include #include #include #include #include +#include #include #ifdef GTEST_HAS_ABSL @@ -245,8 +249,8 @@ struct StreamPrinter { // ADL (possibly involving implicit conversions). // (Use SFINAE via return type, because it seems GCC < 12 doesn't handle name // lookup properly when we do it in the template parameter list.) - static auto PrintValue(const T& value, - ::std::ostream* os) -> decltype((void)(*os << value)) { + static auto PrintValue(const T& value, ::std::ostream* os) + -> decltype((void)(*os << value)) { // Call streaming operator found by ADL, possibly with implicit conversions // of the arguments. *os << value; @@ -521,11 +525,15 @@ GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); GTEST_API_ void PrintTo(char32_t c, ::std::ostream* os); inline void PrintTo(char16_t c, ::std::ostream* os) { - PrintTo(ImplicitCast_(c), os); + // TODO(b/418738869): Incorrect for values not representing valid codepoints. + // Also see https://github.com/google/googletest/issues/4762. + PrintTo(static_cast(c), os); } #ifdef __cpp_lib_char8_t inline void PrintTo(char8_t c, ::std::ostream* os) { - PrintTo(ImplicitCast_(c), os); + // TODO(b/418738869): Incorrect for values not representing valid codepoints. + // Also see https://github.com/google/googletest/issues/4762. + PrintTo(static_cast(c), os); } #endif @@ -695,44 +703,63 @@ void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { } } -// Overloads for ::std::string. -GTEST_API_ void PrintStringTo(const ::std::string& s, ::std::ostream* os); +// Overloads for ::std::string and ::std::string_view +GTEST_API_ void PrintStringTo(::std::string_view s, ::std::ostream* os); inline void PrintTo(const ::std::string& s, ::std::ostream* os) { PrintStringTo(s, os); } +inline void PrintTo(::std::string_view s, ::std::ostream* os) { + PrintStringTo(s, os); +} -// Overloads for ::std::u8string +// Overloads for ::std::u8string and ::std::u8string_view #ifdef __cpp_lib_char8_t -GTEST_API_ void PrintU8StringTo(const ::std::u8string& s, ::std::ostream* os); +GTEST_API_ void PrintU8StringTo(::std::u8string_view s, ::std::ostream* os); inline void PrintTo(const ::std::u8string& s, ::std::ostream* os) { PrintU8StringTo(s, os); } +inline void PrintTo(::std::u8string_view s, ::std::ostream* os) { + PrintU8StringTo(s, os); +} #endif -// Overloads for ::std::u16string -GTEST_API_ void PrintU16StringTo(const ::std::u16string& s, ::std::ostream* os); +// Overloads for ::std::u16string and ::std::u16string_view +GTEST_API_ void PrintU16StringTo(::std::u16string_view s, ::std::ostream* os); inline void PrintTo(const ::std::u16string& s, ::std::ostream* os) { PrintU16StringTo(s, os); } +inline void PrintTo(::std::u16string_view s, ::std::ostream* os) { + PrintU16StringTo(s, os); +} -// Overloads for ::std::u32string -GTEST_API_ void PrintU32StringTo(const ::std::u32string& s, ::std::ostream* os); +// Overloads for ::std::u32string and ::std::u32string_view +GTEST_API_ void PrintU32StringTo(::std::u32string_view s, ::std::ostream* os); inline void PrintTo(const ::std::u32string& s, ::std::ostream* os) { PrintU32StringTo(s, os); } +inline void PrintTo(::std::u32string_view s, ::std::ostream* os) { + PrintU32StringTo(s, os); +} -// Overloads for ::std::wstring. +// Overloads for ::std::wstring and ::std::wstring_view #if GTEST_HAS_STD_WSTRING -GTEST_API_ void PrintWideStringTo(const ::std::wstring& s, ::std::ostream* os); +GTEST_API_ void PrintWideStringTo(::std::wstring_view s, ::std::ostream* os); inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { PrintWideStringTo(s, os); } +inline void PrintTo(::std::wstring_view s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} #endif // GTEST_HAS_STD_WSTRING #if GTEST_INTERNAL_HAS_STRING_VIEW -// Overload for internal::StringView. +// Overload for internal::StringView. Needed for build configurations where +// internal::StringView is an alias for absl::string_view, but absl::string_view +// is a distinct type from std::string_view. +template , int> = 0> inline void PrintTo(internal::StringView sp, ::std::ostream* os) { - PrintTo(::std::string(sp), os); + PrintStringTo(sp, os); } #endif // GTEST_INTERNAL_HAS_STRING_VIEW @@ -890,14 +917,11 @@ class UniversalPrinter { template class UniversalPrinter : public UniversalPrinter {}; -#if GTEST_INTERNAL_HAS_ANY - -// Printer for std::any / absl::any - +// Printer for std::any template <> -class UniversalPrinter { +class UniversalPrinter { public: - static void Print(const Any& value, ::std::ostream* os) { + static void Print(const std::any& value, ::std::ostream* os) { if (value.has_value()) { *os << "value of type " << GetTypeName(value); } else { @@ -906,7 +930,7 @@ class UniversalPrinter { } private: - static std::string GetTypeName(const Any& value) { + static std::string GetTypeName(const std::any& value) { #if GTEST_HAS_RTTI return internal::GetTypeName(value.type()); #else @@ -916,16 +940,11 @@ class UniversalPrinter { } }; -#endif // GTEST_INTERNAL_HAS_ANY - -#if GTEST_INTERNAL_HAS_OPTIONAL - -// Printer for std::optional / absl::optional - +// Printer for std::optional template -class UniversalPrinter> { +class UniversalPrinter> { public: - static void Print(const Optional& value, ::std::ostream* os) { + static void Print(const std::optional& value, ::std::ostream* os) { *os << '('; if (!value) { *os << "nullopt"; @@ -937,29 +956,18 @@ class UniversalPrinter> { }; template <> -class UniversalPrinter { +class UniversalPrinter { public: - static void Print(decltype(Nullopt()), ::std::ostream* os) { - *os << "(nullopt)"; - } + static void Print(std::nullopt_t, ::std::ostream* os) { *os << "(nullopt)"; } }; -#endif // GTEST_INTERNAL_HAS_OPTIONAL - -#if GTEST_INTERNAL_HAS_VARIANT - -// Printer for std::variant / absl::variant - +// Printer for std::variant template -class UniversalPrinter> { +class UniversalPrinter> { public: - static void Print(const Variant& value, ::std::ostream* os) { + static void Print(const std::variant& value, ::std::ostream* os) { *os << '('; -#ifdef GTEST_HAS_ABSL - absl::visit(Visitor{os, value.index()}, value); -#else std::visit(Visitor{os, value.index()}, value); -#endif // GTEST_HAS_ABSL *os << ')'; } @@ -976,8 +984,6 @@ class UniversalPrinter> { }; }; -#endif // GTEST_INTERNAL_HAS_VARIANT - // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template diff --git a/deps/googletest/include/gtest/gtest.h b/deps/googletest/include/gtest/gtest.h index 7be0caaf515cf8..cbe680c1adb266 100644 --- a/deps/googletest/include/gtest/gtest.h +++ b/deps/googletest/include/gtest/gtest.h @@ -1693,7 +1693,7 @@ class WithParamInterface { // The current parameter value. Is also available in the test fixture's // constructor. - static const ParamType& GetParam() { + [[nodiscard]] static const ParamType& GetParam() { GTEST_CHECK_(parameter_ != nullptr) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?"; diff --git a/deps/googletest/include/gtest/internal/gtest-internal.h b/deps/googletest/include/gtest/internal/gtest-internal.h index dcab397e92320a..808d89be91439a 100644 --- a/deps/googletest/include/gtest/internal/gtest-internal.h +++ b/deps/googletest/include/gtest/internal/gtest-internal.h @@ -290,17 +290,17 @@ class FloatingPoint { // around may change its bits, although the new value is guaranteed // to be also a NAN. Therefore, don't expect this constructor to // preserve the bits in x when x is a NAN. - explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + explicit FloatingPoint(RawType x) { memcpy(&bits_, &x, sizeof(x)); } // Static methods // Reinterprets a bit pattern as a floating-point number. // // This function is needed to test the AlmostEquals() method. - static RawType ReinterpretBits(const Bits bits) { - FloatingPoint fp(0); - fp.u_.bits_ = bits; - return fp.u_.value_; + static RawType ReinterpretBits(Bits bits) { + RawType fp; + memcpy(&fp, &bits, sizeof(fp)); + return fp; } // Returns the floating-point number that represent positive infinity. @@ -309,16 +309,16 @@ class FloatingPoint { // Non-static methods // Returns the bits that represents this number. - const Bits& bits() const { return u_.bits_; } + const Bits& bits() const { return bits_; } // Returns the exponent bits of this number. - Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } + Bits exponent_bits() const { return kExponentBitMask & bits_; } // Returns the fraction bits of this number. - Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } + Bits fraction_bits() const { return kFractionBitMask & bits_; } // Returns the sign bit of this number. - Bits sign_bit() const { return kSignBitMask & u_.bits_; } + Bits sign_bit() const { return kSignBitMask & bits_; } // Returns true if and only if this is NAN (not a number). bool is_nan() const { @@ -332,23 +332,16 @@ class FloatingPoint { // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. - // - thinks +0.0 and -0.0 are 0 DLP's apart. + // - thinks +0.0 and -0.0 are 0 ULP's apart. bool AlmostEquals(const FloatingPoint& rhs) const { // The IEEE standard says that any comparison operation involving // a NAN must return false. if (is_nan() || rhs.is_nan()) return false; - return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <= - kMaxUlps; + return DistanceBetweenSignAndMagnitudeNumbers(bits_, rhs.bits_) <= kMaxUlps; } private: - // The data type used to store the actual floating-point number. - union FloatingPointUnion { - RawType value_; // The raw floating-point number. - Bits bits_; // The bits that represent the number. - }; - // Converts an integer from the sign-and-magnitude representation to // the biased representation. More precisely, let N be 2 to the // power of (kBitCount - 1), an integer x is represented by the @@ -364,7 +357,7 @@ class FloatingPoint { // // Read https://en.wikipedia.org/wiki/Signed_number_representations // for more details on signed number representations. - static Bits SignAndMagnitudeToBiased(const Bits& sam) { + static Bits SignAndMagnitudeToBiased(Bits sam) { if (kSignBitMask & sam) { // sam represents a negative number. return ~sam + 1; @@ -376,14 +369,13 @@ class FloatingPoint { // Given two numbers in the sign-and-magnitude representation, // returns the distance between them as an unsigned number. - static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits& sam1, - const Bits& sam2) { + static Bits DistanceBetweenSignAndMagnitudeNumbers(Bits sam1, Bits sam2) { const Bits biased1 = SignAndMagnitudeToBiased(sam1); const Bits biased2 = SignAndMagnitudeToBiased(sam2); return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); } - FloatingPointUnion u_; + Bits bits_; // The bits that represent the number. }; // Typedefs the instances of the FloatingPoint template class that we diff --git a/deps/googletest/include/gtest/internal/gtest-port.h b/deps/googletest/include/gtest/internal/gtest-port.h index 4cfc16c03e9d38..06a5a8e6f31935 100644 --- a/deps/googletest/include/gtest/internal/gtest-port.h +++ b/deps/googletest/include/gtest/internal/gtest-port.h @@ -198,21 +198,8 @@ // suppressed (constant conditional). // GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 // is suppressed. -// GTEST_INTERNAL_HAS_ANY - for enabling UniversalPrinter or -// UniversalPrinter specializations. -// Always defined to 0 or 1. -// GTEST_INTERNAL_HAS_OPTIONAL - for enabling UniversalPrinter -// or -// UniversalPrinter -// specializations. Always defined to 0 or 1. // GTEST_INTERNAL_HAS_STD_SPAN - for enabling UniversalPrinter // specializations. Always defined to 0 or 1 -// GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher or -// Matcher -// specializations. Always defined to 0 or 1. -// GTEST_INTERNAL_HAS_VARIANT - for enabling UniversalPrinter or -// UniversalPrinter -// specializations. Always defined to 0 or 1. // GTEST_USE_OWN_FLAGFILE_FLAG_ - Always defined to 0 or 1. // GTEST_HAS_CXXABI_H_ - Always defined to 0 or 1. // GTEST_CAN_STREAM_RESULTS_ - Always defined to 0 or 1. @@ -282,10 +269,14 @@ // Detect C++ feature test macros as gracefully as possible. // MSVC >= 19.15, Clang >= 3.4.1, and GCC >= 4.1.2 support feature test macros. -#if GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L && \ - (!defined(__has_include) || GTEST_INTERNAL_HAS_INCLUDE()) -#include // C++20 and later -#elif (!defined(__has_include) || GTEST_INTERNAL_HAS_INCLUDE()) +// +// GCC15 warns that is deprecated in C++17 and suggests using +// instead, even though is not available in C++17 mode prior +// to GCC9. +#if GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L || \ + GTEST_INTERNAL_HAS_INCLUDE() +#include // C++20 or support. +#else #include // Pre-C++20 #endif @@ -2331,73 +2322,6 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing -#ifdef GTEST_HAS_ABSL -// Always use absl::any for UniversalPrinter<> specializations if googletest -// is built with absl support. -#define GTEST_INTERNAL_HAS_ANY 1 -#include "absl/types/any.h" -namespace testing { -namespace internal { -using Any = ::absl::any; -} // namespace internal -} // namespace testing -#else -#if defined(__cpp_lib_any) || (GTEST_INTERNAL_HAS_INCLUDE() && \ - GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L && \ - (!defined(_MSC_VER) || GTEST_HAS_RTTI)) -// Otherwise for C++17 and higher use std::any for UniversalPrinter<> -// specializations. -#define GTEST_INTERNAL_HAS_ANY 1 -#include -namespace testing { -namespace internal { -using Any = ::std::any; -} // namespace internal -} // namespace testing -// The case where absl is configured NOT to alias std::any is not -// supported. -#endif // __cpp_lib_any -#endif // GTEST_HAS_ABSL - -#ifndef GTEST_INTERNAL_HAS_ANY -#define GTEST_INTERNAL_HAS_ANY 0 -#endif - -#ifdef GTEST_HAS_ABSL -// Always use absl::optional for UniversalPrinter<> specializations if -// googletest is built with absl support. -#define GTEST_INTERNAL_HAS_OPTIONAL 1 -#include "absl/types/optional.h" -namespace testing { -namespace internal { -template -using Optional = ::absl::optional; -inline ::absl::nullopt_t Nullopt() { return ::absl::nullopt; } -} // namespace internal -} // namespace testing -#else -#if defined(__cpp_lib_optional) || (GTEST_INTERNAL_HAS_INCLUDE() && \ - GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L) -// Otherwise for C++17 and higher use std::optional for UniversalPrinter<> -// specializations. -#define GTEST_INTERNAL_HAS_OPTIONAL 1 -#include -namespace testing { -namespace internal { -template -using Optional = ::std::optional; -inline ::std::nullopt_t Nullopt() { return ::std::nullopt; } -} // namespace internal -} // namespace testing -// The case where absl is configured NOT to alias std::optional is not -// supported. -#endif // __cpp_lib_optional -#endif // GTEST_HAS_ABSL - -#ifndef GTEST_INTERNAL_HAS_OPTIONAL -#define GTEST_INTERNAL_HAS_OPTIONAL 0 -#endif - #if defined(__cpp_lib_span) || (GTEST_INTERNAL_HAS_INCLUDE() && \ GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L) #define GTEST_INTERNAL_HAS_STD_SPAN 1 @@ -2439,38 +2363,6 @@ using StringView = ::std::string_view; #define GTEST_INTERNAL_HAS_STRING_VIEW 0 #endif -#ifdef GTEST_HAS_ABSL -// Always use absl::variant for UniversalPrinter<> specializations if googletest -// is built with absl support. -#define GTEST_INTERNAL_HAS_VARIANT 1 -#include "absl/types/variant.h" -namespace testing { -namespace internal { -template -using Variant = ::absl::variant; -} // namespace internal -} // namespace testing -#else -#if defined(__cpp_lib_variant) || (GTEST_INTERNAL_HAS_INCLUDE() && \ - GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L) -// Otherwise for C++17 and higher use std::variant for UniversalPrinter<> -// specializations. -#define GTEST_INTERNAL_HAS_VARIANT 1 -#include -namespace testing { -namespace internal { -template -using Variant = ::std::variant; -} // namespace internal -} // namespace testing -// The case where absl is configured NOT to alias std::variant is not supported. -#endif // __cpp_lib_variant -#endif // GTEST_HAS_ABSL - -#ifndef GTEST_INTERNAL_HAS_VARIANT -#define GTEST_INTERNAL_HAS_VARIANT 0 -#endif - #if (defined(__cpp_lib_three_way_comparison) || \ (GTEST_INTERNAL_HAS_INCLUDE() && \ GTEST_INTERNAL_CPLUSPLUS_LANG >= 201907L)) diff --git a/deps/googletest/src/gtest-printers.cc b/deps/googletest/src/gtest-printers.cc index e3acecba8e4dec..f65573077861b4 100644 --- a/deps/googletest/src/gtest-printers.cc +++ b/deps/googletest/src/gtest-printers.cc @@ -50,7 +50,7 @@ #include #include #include // NOLINT -#include +#include #include #include "gtest/internal/gtest-port.h" @@ -333,14 +333,14 @@ void PrintTo(__int128_t v, ::std::ostream* os) { // Prints the given array of characters to the ostream. CharType must be either // char, char8_t, char16_t, char32_t, or wchar_t. -// The array starts at begin, the length is len, it may include '\0' characters -// and may not be NUL-terminated. +// The array starts at begin (which may be nullptr) and contains len characters. +// The array may include '\0' characters and may not be NUL-terminated. template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static CharFormat PrintCharsAsStringTo(const CharType* begin, size_t len, ostream* os) { - const char* const quote_prefix = GetCharWidthPrefix(*begin); + const char* const quote_prefix = GetCharWidthPrefix(CharType()); *os << quote_prefix << "\""; bool is_previous_hex = false; CharFormat print_format = kAsIs; @@ -516,13 +516,13 @@ bool IsValidUTF8(const char* str, size_t length) { void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { if (!ContainsUnprintableControlCodes(str, length) && IsValidUTF8(str, length)) { - *os << "\n As Text: \"" << str << "\""; + *os << "\n As Text: \"" << ::std::string_view(str, length) << "\""; } } } // anonymous namespace -void PrintStringTo(const ::std::string& s, ostream* os) { +void PrintStringTo(::std::string_view s, ostream* os) { if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { if (GTEST_FLAG_GET(print_utf8)) { ConditionalPrintAsText(s.data(), s.size(), os); @@ -531,21 +531,21 @@ void PrintStringTo(const ::std::string& s, ostream* os) { } #ifdef __cpp_lib_char8_t -void PrintU8StringTo(const ::std::u8string& s, ostream* os) { +void PrintU8StringTo(::std::u8string_view s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif -void PrintU16StringTo(const ::std::u16string& s, ostream* os) { +void PrintU16StringTo(::std::u16string_view s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } -void PrintU32StringTo(const ::std::u32string& s, ostream* os) { +void PrintU32StringTo(::std::u32string_view s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #if GTEST_HAS_STD_WSTRING -void PrintWideStringTo(const ::std::wstring& s, ostream* os) { +void PrintWideStringTo(::std::wstring_view s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_STD_WSTRING diff --git a/deps/googletest/src/gtest.cc b/deps/googletest/src/gtest.cc index 09af15179f1f9f..6be9300e09d1d4 100644 --- a/deps/googletest/src/gtest.cc +++ b/deps/googletest/src/gtest.cc @@ -1488,17 +1488,17 @@ class Hunk { // Print a unified diff header for one hunk. // The format is // "@@ -, +, @@" - // where the left/right parts are omitted if unnecessary. + // where the left/right lengths are omitted if unnecessary. void PrintHeader(std::ostream* ss) const { - *ss << "@@ "; - if (removes_) { - *ss << "-" << left_start_ << "," << (removes_ + common_); + size_t left_length = removes_ + common_; + size_t right_length = adds_ + common_; + *ss << "@@ " << "-" << left_start_; + if (left_length != 1) { + *ss << "," << left_length; } - if (removes_ && adds_) { - *ss << " "; - } - if (adds_) { - *ss << "+" << right_start_ << "," << (adds_ + common_); + *ss << " " << "+" << right_start_; + if (right_length != 1) { + *ss << "," << right_length; } *ss << " @@\n"; } diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h index 2ef49b8d68f4ed..3d91af55109cc8 100644 --- a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h +++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h @@ -3133,14 +3133,12 @@ nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option, /** * @function * - * This option prevents the library from retaining closed streams to - * maintain the priority tree. If this option is set to nonzero, - * applications can discard closed stream completely to save memory. + * .. warning:: * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is submitted via `nghttp2_submit_settings()`, any - * closed streams are not retained regardless of this option. + * Deprecated. Closed streams are not retained anymore. + * + * This function works as before, but it does not take any effect + * against :type:`nghttp2_session`. */ NGHTTP2_EXTERN void nghttp2_option_set_no_closed_streams(nghttp2_option *option, int val); @@ -3170,16 +3168,11 @@ NGHTTP2_EXTERN void nghttp2_option_set_max_settings(nghttp2_option *option, /** * @function * - * This option, if set to nonzero, allows server to fallback to - * :rfc:`7540` priorities if SETTINGS_NO_RFC7540_PRIORITIES was not - * received from client, and server submitted - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * = 1 via `nghttp2_submit_settings()`. Most of the advanced - * functionality for RFC 7540 priorities are still disabled. This - * fallback only enables the minimal feature set of RFC 7540 - * priorities to deal with priority signaling from client. + * .. warning:: + * Deprecated. :rfc:`7540` priorities have been removed. * - * Client session ignores this option. + * This function works as before, but it does not take any effect + * against :type:`nghttp2_session`. */ NGHTTP2_EXTERN void nghttp2_option_set_server_fallback_rfc7540_priorities(nghttp2_option *option, @@ -4179,39 +4172,9 @@ NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session, * * Deprecated. :rfc:`7540` priorities are deprecated by * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return 0 without doing anything. - * - * Changes priority of existing stream denoted by |stream_id|. The - * new priority specification is |pri_spec|. - * - * The priority is changed silently and instantly, and no PRIORITY - * frame will be sent to notify the peer of this change. This - * function may be useful for server to change the priority of pushed - * stream. - * - * If |session| is initialized as server, and ``pri_spec->stream_id`` - * points to the idle stream, the idle stream is created if it does - * not exist. The created idle stream will depend on root stream - * (stream 0) with weight 16. - * - * Otherwise, if stream denoted by ``pri_spec->stream_id`` is not - * found, we use default priority instead of given |pri_spec|. That - * is make stream depend on root stream with weight 16. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is submitted via `nghttp2_submit_settings()`, this - * function does nothing and returns 0. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: + * prioritization scheme. * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * Attempted to depend on itself; or no stream exist for the given - * |stream_id|; or |stream_id| is 0 + * This function is noop. It always returns 0. */ NGHTTP2_EXTERN int nghttp2_session_change_stream_priority(nghttp2_session *session, @@ -4225,51 +4188,9 @@ nghttp2_session_change_stream_priority(nghttp2_session *session, * * Deprecated. :rfc:`7540` priorities are deprecated by * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return 0 without doing anything. - * - * Creates idle stream with the given |stream_id|, and priority - * |pri_spec|. - * - * The stream creation is done without sending PRIORITY frame, which - * means that peer does not know about the existence of this idle - * stream in the local endpoint. - * - * RFC 7540 does not disallow the use of creation of idle stream with - * odd or even stream ID regardless of client or server. So this - * function can create odd or even stream ID regardless of client or - * server. But probably it is a bit safer to use the stream ID the - * local endpoint can initiate (in other words, use odd stream ID for - * client, and even stream ID for server), to avoid potential - * collision from peer's instruction. Also we can use - * `nghttp2_session_set_next_stream_id()` to avoid to open created - * idle streams accidentally if we follow this recommendation. - * - * If |session| is initialized as server, and ``pri_spec->stream_id`` - * points to the idle stream, the idle stream is created if it does - * not exist. The created idle stream will depend on root stream - * (stream 0) with weight 16. - * - * Otherwise, if stream denoted by ``pri_spec->stream_id`` is not - * found, we use default priority instead of given |pri_spec|. That - * is make stream depend on root stream with weight 16. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is submitted via `nghttp2_submit_settings()`, this - * function does nothing and returns 0. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: + * prioritization scheme. * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * Attempted to depend on itself; or stream denoted by |stream_id| - * already exists; or |stream_id| cannot be used to create idle - * stream (in other words, local endpoint has already opened - * stream ID greater than or equal to the given stream ID; or - * |stream_id| is 0 + * This function is noop. It always returns 0. */ NGHTTP2_EXTERN int nghttp2_session_create_idle_stream(nghttp2_session *session, int32_t stream_id, @@ -4505,23 +4426,7 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); * * Submits HEADERS frame and optionally one or more DATA frames. * - * The |pri_spec| is a deprecated priority specification of this - * request. ``NULL`` means the default priority (see - * `nghttp2_priority_spec_default_init()`). To specify the priority, - * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, - * this function will copy its data members. - * - * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`, - * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` - * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes - * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than - * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes - * :macro:`NGHTTP2_MAX_WEIGHT`. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is received by a remote endpoint, |pri_spec| is - * ignored, and treated as if ``NULL`` is specified. + * The |pri_spec| is ignored. * * The |nva| is an array of name/value pair :type:`nghttp2_nv` with * |nvlen| elements. The application is responsible to include @@ -4564,9 +4469,6 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` * No stream ID is available because maximum stream ID was * reached. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * Trying to depend on itself (new stream ID equals - * ``pri_spec->stream_id``). * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` * The |session| is server session. * @@ -4594,25 +4496,7 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_request( * * Submits HEADERS frame and optionally one or more DATA frames. * - * The |pri_spec| is a deprecated priority specification of this - * request. ``NULL`` means the default priority (see - * `nghttp2_priority_spec_default_init()`). To specify the priority, - * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, - * this function will copy its data members. In the future release - * after the end of 2024, this function will ignore |pri_spec| and - * behave as if ``NULL`` is given. - * - * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`, - * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` - * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes - * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than - * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes - * :macro:`NGHTTP2_MAX_WEIGHT`. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is received by a remote endpoint, |pri_spec| is - * ignored, and treated as if ``NULL`` is specified. + * The |pri_spec| is ignored. * * The |nva| is an array of name/value pair :type:`nghttp2_nv` with * |nvlen| elements. The application is responsible to include @@ -4655,9 +4539,6 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_request( * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` * No stream ID is available because maximum stream ID was * reached. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * Trying to depend on itself (new stream ID equals - * ``pri_spec->stream_id``). * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` * The |session| is server session. * @@ -4899,24 +4780,7 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, * assigned stream ID will be returned. Otherwise, specify stream ID * in |stream_id|. * - * The |pri_spec| is a deprecated priority specification of this - * request. ``NULL`` means the default priority (see - * `nghttp2_priority_spec_default_init()`). To specify the priority, - * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, - * this function will copy its data members. In the future release - * after the end of 2024, this function will ignore |pri_spec| and - * behave as if ``NULL`` is given. - * - * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`, - * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` - * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes - * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than - * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes :macro:`NGHTTP2_MAX_WEIGHT`. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is received by a remote endpoint, |pri_spec| is - * ignored, and treated as if ``NULL`` is specified. + * The |pri_spec| is ignored. * * The |nva| is an array of name/value pair :type:`nghttp2_nv` with * |nvlen| elements. The application is responsible to include @@ -4956,8 +4820,7 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, * No stream ID is available because maximum stream ID was * reached. * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0; or trying to depend on itself (stream ID - * equals ``pri_spec->stream_id``). + * The |stream_id| is 0. * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` * DATA or HEADERS has been already submitted and not fully * processed yet. This happens if stream denoted by |stream_id| @@ -5083,40 +4946,9 @@ NGHTTP2_EXTERN int nghttp2_submit_data2(nghttp2_session *session, uint8_t flags, * * Deprecated. :rfc:`7540` priorities are deprecated by * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return 0 without doing anything. - * - * Submits PRIORITY frame to change the priority of stream |stream_id| - * to the priority specification |pri_spec|. - * - * The |flags| is currently ignored and should be - * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. - * - * The |pri_spec| is a deprecated priority specification of this - * request. ``NULL`` is not allowed for this function. To specify the - * priority, use `nghttp2_priority_spec_init()`. This function will - * copy its data members. - * - * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`, - * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` - * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes - * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than - * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes - * :macro:`NGHTTP2_MAX_WEIGHT`. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is received by a remote endpoint, this function does - * nothing and returns 0. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: + * prioritization scheme. * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0; or the |pri_spec| is NULL; or trying to - * depend on itself. + * This function is noop. It always returns 0. */ NGHTTP2_EXTERN int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, @@ -6885,11 +6717,9 @@ nghttp2_session_get_root_stream(nghttp2_session *session); * * Deprecated. :rfc:`7540` priorities are deprecated by * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return NULL. + * prioritization scheme. * - * Returns the parent stream of |stream| in dependency tree. Returns - * NULL if there is no such stream. + * This function always returns NULL. */ NGHTTP2_EXTERN nghttp2_stream * nghttp2_stream_get_parent(nghttp2_stream *stream); @@ -6903,11 +6733,9 @@ NGHTTP2_EXTERN int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream); * * Deprecated. :rfc:`7540` priorities are deprecated by * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return NULL. + * prioritization scheme. * - * Returns the next sibling stream of |stream| in dependency tree. - * Returns NULL if there is no such stream. + * This function always returns NULL. */ NGHTTP2_EXTERN nghttp2_stream * nghttp2_stream_get_next_sibling(nghttp2_stream *stream); @@ -6919,11 +6747,9 @@ nghttp2_stream_get_next_sibling(nghttp2_stream *stream); * * Deprecated. :rfc:`7540` priorities are deprecated by * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return NULL. + * prioritization scheme. * - * Returns the previous sibling stream of |stream| in dependency tree. - * Returns NULL if there is no such stream. + * This function always returns NULL. */ NGHTTP2_EXTERN nghttp2_stream * nghttp2_stream_get_previous_sibling(nghttp2_stream *stream); @@ -6935,11 +6761,9 @@ nghttp2_stream_get_previous_sibling(nghttp2_stream *stream); * * Deprecated. :rfc:`7540` priorities are deprecated by * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return NULL. + * prioritization scheme. * - * Returns the first child stream of |stream| in dependency tree. - * Returns NULL if there is no such stream. + * This function always returns NULL. */ NGHTTP2_EXTERN nghttp2_stream * nghttp2_stream_get_first_child(nghttp2_stream *stream); @@ -6951,11 +6775,9 @@ nghttp2_stream_get_first_child(nghttp2_stream *stream); * * Deprecated. :rfc:`7540` priorities are deprecated by * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return - * :macro:`NGHTTP2_DEFAULT_WEIGHT`. + * prioritization scheme. * - * Returns dependency weight to the parent stream of |stream|. + * This function always returns :macro:`NGHTTP2_DEFAULT_WEIGHT`. */ NGHTTP2_EXTERN int32_t nghttp2_stream_get_weight(nghttp2_stream *stream); @@ -6966,10 +6788,9 @@ NGHTTP2_EXTERN int32_t nghttp2_stream_get_weight(nghttp2_stream *stream); * * Deprecated. :rfc:`7540` priorities are deprecated by * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return 0. + * prioritization scheme. * - * Returns the sum of the weight for |stream|'s children. + * This function always returns 0. */ NGHTTP2_EXTERN int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream); diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h index 827c99896846e3..1302eb57bc58d8 100644 --- a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h +++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h @@ -29,7 +29,7 @@ * @macro * Version number of the nghttp2 library release */ -#define NGHTTP2_VERSION "1.64.0" +#define NGHTTP2_VERSION "1.65.0" /** * @macro @@ -37,6 +37,6 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define NGHTTP2_VERSION_NUM 0x014000 +#define NGHTTP2_VERSION_NUM 0x014100 #endif /* NGHTTP2VER_H */ diff --git a/deps/nghttp2/lib/nghttp2_hd.c b/deps/nghttp2/lib/nghttp2_hd.c index 55fc2cc6bfea3d..ad85eed1e13e7b 100644 --- a/deps/nghttp2/lib/nghttp2_hd.c +++ b/deps/nghttp2/lib/nghttp2_hd.c @@ -594,8 +594,19 @@ static void hd_map_remove(nghttp2_hd_map *map, nghttp2_hd_entry *ent) { static int hd_ringbuf_init(nghttp2_hd_ringbuf *ringbuf, size_t bufsize, nghttp2_mem *mem) { size_t size; + const size_t max_size = SIZE_MAX / sizeof(nghttp2_hd_entry *); + + if (bufsize > max_size) { + return NGHTTP2_ERR_NOMEM; + } + for (size = 1; size < bufsize; size <<= 1) ; + + if (size > max_size) { + return NGHTTP2_ERR_NOMEM; + } + ringbuf->buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size); if (ringbuf->buffer == NULL) { return NGHTTP2_ERR_NOMEM; diff --git a/deps/nghttp2/lib/nghttp2_http.c b/deps/nghttp2/lib/nghttp2_http.c index f222fe5e3fbe3c..60a0b01e66c1c8 100644 --- a/deps/nghttp2/lib/nghttp2_http.c +++ b/deps/nghttp2/lib/nghttp2_http.c @@ -207,7 +207,6 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, if (!trailer && /* Do not parse the header field in PUSH_PROMISE. */ (stream->stream_id & 1) && - (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) && !(stream->http_flags & NGHTTP2_HTTP_FLAG_BAD_PRIORITY)) { nghttp2_extpri_from_uint8(&extpri, stream->http_extpri); if (nghttp2_http_parse_priority(&extpri, nv->value->base, @@ -660,17 +659,17 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream, int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value, size_t valuelen) { nghttp2_extpri pri = *dest; - sf_parser sfp; - sf_vec key; - sf_value val; + sfparse_parser sfp; + sfparse_vec key; + sfparse_value val; int rv; - sf_parser_init(&sfp, value, valuelen); + sfparse_parser_init(&sfp, value, valuelen); for (;;) { - rv = sf_parser_dict(&sfp, &key, &val); + rv = sfparse_parser_dict(&sfp, &key, &val); if (rv != 0) { - if (rv == SF_ERR_EOF) { + if (rv == SFPARSE_ERR_EOF) { break; } @@ -683,7 +682,7 @@ int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value, switch (key.base[0]) { case 'i': - if (val.type != SF_TYPE_BOOLEAN) { + if (val.type != SFPARSE_TYPE_BOOLEAN) { return NGHTTP2_ERR_INVALID_ARGUMENT; } @@ -691,7 +690,7 @@ int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value, break; case 'u': - if (val.type != SF_TYPE_INTEGER || + if (val.type != SFPARSE_TYPE_INTEGER || val.integer < NGHTTP2_EXTPRI_URGENCY_HIGH || NGHTTP2_EXTPRI_URGENCY_LOW < val.integer) { return NGHTTP2_ERR_INVALID_ARGUMENT; diff --git a/deps/nghttp2/lib/nghttp2_session.c b/deps/nghttp2/lib/nghttp2_session.c index df33a89efdc1d3..f5bda333f83d15 100644 --- a/deps/nghttp2/lib/nghttp2_session.c +++ b/deps/nghttp2/lib/nghttp2_session.c @@ -41,6 +41,8 @@ #include "nghttp2_debug.h" #include "nghttp2_submit.h" +nghttp2_stream root; + /* * Returns non-zero if the number of outgoing opened streams is larger * than or equal to @@ -146,11 +148,6 @@ static int session_detect_idle_stream(nghttp2_session *session, return 0; } -static int session_no_rfc7540_pri_no_fallback(nghttp2_session *session) { - return session->pending_no_rfc7540_priorities == 1 && - !session->fallback_rfc7540_priorities; -} - static int check_ext_type_set(const uint8_t *ext_types, uint8_t type) { return (ext_types[type / 8] & (1 << (type & 0x7))) > 0; } @@ -458,10 +455,6 @@ static int session_new(nghttp2_session **session_ptr, /* next_stream_id is initialized in either nghttp2_session_client_new2 or nghttp2_session_server_new2 */ - nghttp2_stream_init(&(*session_ptr)->root, 0, NGHTTP2_STREAM_FLAG_NONE, - NGHTTP2_STREAM_IDLE, NGHTTP2_DEFAULT_WEIGHT, 0, 0, NULL, - mem); - (*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; (*session_ptr)->recv_window_size = 0; (*session_ptr)->consumed_size = 0; @@ -548,11 +541,6 @@ static int session_new(nghttp2_session **session_ptr, max_deflate_dynamic_table_size = option->max_deflate_dynamic_table_size; } - if ((option->opt_set_mask & NGHTTP2_OPT_NO_CLOSED_STREAMS) && - option->no_closed_streams) { - (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_CLOSED_STREAMS; - } - if (option->opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_ACK) { (*session_ptr)->max_outbound_ack = option->max_outbound_ack; } @@ -562,13 +550,6 @@ static int session_new(nghttp2_session **session_ptr, (*session_ptr)->max_settings = option->max_settings; } - if ((option->opt_set_mask & - NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES) && - option->server_fallback_rfc7540_priorities) { - (*session_ptr)->opt_flags |= - NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES; - } - if ((option->opt_set_mask & NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) && option->no_rfc9113_leading_and_trailing_ws_validation) { @@ -810,7 +791,6 @@ void nghttp2_session_del(nghttp2_session *session) { for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) { nghttp2_pq_free(&session->sched[i].ob_data); } - nghttp2_stream_free(&session->root); /* Have to free streams first, so that we can check stream->item->queued */ @@ -829,82 +809,6 @@ void nghttp2_session_del(nghttp2_session *session) { nghttp2_mem_free(mem, session); } -int nghttp2_session_reprioritize_stream( - nghttp2_session *session, nghttp2_stream *stream, - const nghttp2_priority_spec *pri_spec_in) { - int rv; - nghttp2_stream *dep_stream = NULL; - nghttp2_priority_spec pri_spec_default; - const nghttp2_priority_spec *pri_spec = pri_spec_in; - - assert((!session->server && session->pending_no_rfc7540_priorities != 1) || - (session->server && !session_no_rfc7540_pri_no_fallback(session))); - assert(pri_spec->stream_id != stream->stream_id); - - if (!nghttp2_stream_in_dep_tree(stream)) { - return 0; - } - - if (pri_spec->stream_id != 0) { - dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); - - if (!dep_stream && - session_detect_idle_stream(session, pri_spec->stream_id)) { - nghttp2_priority_spec_default_init(&pri_spec_default); - - dep_stream = nghttp2_session_open_stream( - session, pri_spec->stream_id, NGHTTP2_FLAG_NONE, &pri_spec_default, - NGHTTP2_STREAM_IDLE, NULL); - - if (dep_stream == NULL) { - return NGHTTP2_ERR_NOMEM; - } - } else if (!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) { - nghttp2_priority_spec_default_init(&pri_spec_default); - pri_spec = &pri_spec_default; - } - } - - if (pri_spec->stream_id == 0) { - dep_stream = &session->root; - } else if (nghttp2_stream_dep_find_ancestor(dep_stream, stream)) { - DEBUGF("stream: cycle detected, dep_stream(%p)=%d stream(%p)=%d\n", - dep_stream, dep_stream->stream_id, stream, stream->stream_id); - - nghttp2_stream_dep_remove_subtree(dep_stream); - rv = nghttp2_stream_dep_add_subtree(stream->dep_prev, dep_stream); - if (rv != 0) { - return rv; - } - } - - assert(dep_stream); - - if (dep_stream == stream->dep_prev && !pri_spec->exclusive) { - /* This is minor optimization when just weight is changed. */ - nghttp2_stream_change_weight(stream, pri_spec->weight); - - return 0; - } - - nghttp2_stream_dep_remove_subtree(stream); - - /* We have to update weight after removing stream from tree */ - stream->weight = pri_spec->weight; - - if (pri_spec->exclusive) { - rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream); - } else { - rv = nghttp2_stream_dep_add_subtree(dep_stream, stream); - } - - if (rv != 0) { - return rv; - } - - return 0; -} - static uint64_t pq_get_first_cycle(nghttp2_pq *pq) { nghttp2_stream *stream; @@ -923,7 +827,6 @@ static int session_ob_data_push(nghttp2_session *session, int inc; nghttp2_pq *pq; - assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES); assert(stream->queued == 0); urgency = nghttp2_extpri_uint8_urgency(stream->extpri); @@ -952,7 +855,6 @@ static void session_ob_data_remove(nghttp2_session *session, nghttp2_stream *stream) { uint32_t urgency; - assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES); assert(stream->queued == 1); urgency = nghttp2_extpri_uint8_urgency(stream->extpri); @@ -969,14 +871,7 @@ static int session_attach_stream_item(nghttp2_session *session, nghttp2_outbound_item *item) { int rv; - rv = nghttp2_stream_attach_item(stream, item); - if (rv != 0) { - return rv; - } - - if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) { - return 0; - } + nghttp2_stream_attach_item(stream, item); rv = session_ob_data_push(session, stream); if (rv != 0) { @@ -992,8 +887,7 @@ static void session_detach_stream_item(nghttp2_session *session, nghttp2_stream *stream) { nghttp2_stream_detach_item(stream); - if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || - !stream->queued) { + if (!stream->queued) { return; } @@ -1004,8 +898,7 @@ static void session_defer_stream_item(nghttp2_session *session, nghttp2_stream *stream, uint8_t flags) { nghttp2_stream_defer_item(stream, flags); - if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || - !stream->queued) { + if (!stream->queued) { return; } @@ -1015,15 +908,9 @@ static void session_defer_stream_item(nghttp2_session *session, static int session_resume_deferred_stream_item(nghttp2_session *session, nghttp2_stream *stream, uint8_t flags) { - int rv; - - rv = nghttp2_stream_resume_deferred_item(stream, flags); - if (rv != 0) { - return rv; - } + nghttp2_stream_resume_deferred_item(stream, flags); - if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || - (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL)) { + if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) { return 0; } @@ -1168,7 +1055,6 @@ int nghttp2_session_add_item(nghttp2_session *session, return 0; case NGHTTP2_PUSH_PROMISE: { nghttp2_headers_aux_data *aux_data; - nghttp2_priority_spec pri_spec; aux_data = &item->aux_data.headers; @@ -1176,20 +1062,13 @@ int nghttp2_session_add_item(nghttp2_session *session, return NGHTTP2_ERR_STREAM_CLOSED; } - nghttp2_priority_spec_init(&pri_spec, stream->stream_id, - NGHTTP2_DEFAULT_WEIGHT, 0); - if (!nghttp2_session_open_stream( session, frame->push_promise.promised_stream_id, - NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_RESERVED, + NGHTTP2_STREAM_FLAG_NONE, NGHTTP2_STREAM_RESERVED, aux_data->stream_user_data)) { return NGHTTP2_ERR_NOMEM; } - /* We don't have to call nghttp2_session_adjust_closed_stream() - here, since stream->stream_id is local stream_id, and it does - not affect closed stream count. */ - nghttp2_outbound_queue_push(&session->ob_reg, item); item->queued = 1; @@ -1290,15 +1169,11 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id, nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, int32_t stream_id, uint8_t flags, - nghttp2_priority_spec *pri_spec_in, nghttp2_stream_state initial_state, void *stream_user_data) { int rv; nghttp2_stream *stream; - nghttp2_stream *dep_stream = NULL; int stream_alloc = 0; - nghttp2_priority_spec pri_spec_default; - nghttp2_priority_spec *pri_spec = pri_spec_in; nghttp2_mem *mem; mem = &session->mem; @@ -1311,23 +1186,9 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, if (stream) { assert(stream->state == NGHTTP2_STREAM_IDLE); - assert((stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || - nghttp2_stream_in_dep_tree(stream)); - - nghttp2_session_detach_idle_stream(session, stream); - - if (nghttp2_stream_in_dep_tree(stream)) { - assert(!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)); - - rv = nghttp2_stream_dep_remove(stream); - if (rv != 0) { - return NULL; - } + assert(initial_state != NGHTTP2_STREAM_IDLE); - if (session_no_rfc7540_pri_no_fallback(session)) { - stream->flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES; - } - } + --session->num_idle_streams; } else { stream = nghttp2_mem_malloc(mem, sizeof(nghttp2_stream)); if (stream == NULL) { @@ -1337,69 +1198,16 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, stream_alloc = 1; } - if (session_no_rfc7540_pri_no_fallback(session) || - session->remote_settings.no_rfc7540_priorities == 1) { - /* For client which has not received server - SETTINGS_NO_RFC7540_PRIORITIES = 1, send a priority signal - opportunistically. */ - if (session->server || - session->remote_settings.no_rfc7540_priorities == 1) { - nghttp2_priority_spec_default_init(&pri_spec_default); - pri_spec = &pri_spec_default; - } - - if (session->pending_no_rfc7540_priorities == 1) { - flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES; - } - } else if (pri_spec->stream_id != 0) { - dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); - - if (!dep_stream && - session_detect_idle_stream(session, pri_spec->stream_id)) { - /* Depends on idle stream, which does not exist in memory. - Assign default priority for it. */ - nghttp2_priority_spec_default_init(&pri_spec_default); - - dep_stream = nghttp2_session_open_stream( - session, pri_spec->stream_id, NGHTTP2_FLAG_NONE, &pri_spec_default, - NGHTTP2_STREAM_IDLE, NULL); - - if (dep_stream == NULL) { - if (stream_alloc) { - nghttp2_mem_free(mem, stream); - } - - return NULL; - } - } else if (!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) { - /* If dep_stream is not part of dependency tree, stream will get - default priority. This handles the case when - pri_spec->stream_id == stream_id. This happens because we - don't check pri_spec->stream_id against new stream ID in - nghttp2_submit_request. This also handles the case when idle - stream created by PRIORITY frame was opened. Somehow we - first remove the idle stream from dependency tree. This is - done to simplify code base, but ideally we should retain old - dependency. But I'm not sure this adds values. */ - nghttp2_priority_spec_default_init(&pri_spec_default); - pri_spec = &pri_spec_default; - } - } - if (initial_state == NGHTTP2_STREAM_RESERVED) { flags |= NGHTTP2_STREAM_FLAG_PUSH; } if (stream_alloc) { nghttp2_stream_init(stream, stream_id, flags, initial_state, - pri_spec->weight, (int32_t)session->remote_settings.initial_window_size, (int32_t)session->local_settings.initial_window_size, - stream_user_data, mem); - - if (session_no_rfc7540_pri_no_fallback(session)) { - stream->seq = session->stream_seq++; - } + stream_user_data); + stream->seq = session->stream_seq++; rv = nghttp2_map_insert(&session->streams, stream_id, stream); if (rv != 0) { @@ -1410,7 +1218,6 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, } else { stream->flags = flags; stream->state = initial_state; - stream->weight = pri_spec->weight; stream->stream_user_data = stream_user_data; } @@ -1428,9 +1235,7 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, limit. That is one of the DOS vector. */ break; case NGHTTP2_STREAM_IDLE: - /* Idle stream does not count toward the concurrent streams limit. - This is used as anchor node in dependency tree. */ - nghttp2_session_keep_idle_stream(session, stream); + ++session->num_idle_streams; break; default: if (nghttp2_session_is_my_stream_id(session, stream_id)) { @@ -1440,31 +1245,11 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, } } - if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { - return stream; - } - - if (pri_spec->stream_id == 0) { - dep_stream = &session->root; - } - - assert(dep_stream); - - if (pri_spec->exclusive) { - rv = nghttp2_stream_dep_insert(dep_stream, stream); - if (rv != 0) { - return NULL; - } - } else { - nghttp2_stream_dep_add(dep_stream, stream); - } - return stream; } int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, uint32_t error_code) { - int rv; nghttp2_stream *stream; nghttp2_mem *mem; int is_my_stream_id; @@ -1528,207 +1313,26 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, /* Closes both directions just in case they are not closed yet */ stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED; - if (session->pending_no_rfc7540_priorities == 1) { - return nghttp2_session_destroy_stream(session, stream); - } - - if ((session->opt_flags & NGHTTP2_OPTMASK_NO_CLOSED_STREAMS) == 0 && - session->server && !is_my_stream_id && - nghttp2_stream_in_dep_tree(stream)) { - /* On server side, retain stream at most MAX_CONCURRENT_STREAMS - combined with the current active incoming streams to make - dependency tree work better. */ - nghttp2_session_keep_closed_stream(session, stream); - } else { - rv = nghttp2_session_destroy_stream(session, stream); - if (rv != 0) { - return rv; - } - } + nghttp2_session_destroy_stream(session, stream); return 0; } -int nghttp2_session_destroy_stream(nghttp2_session *session, - nghttp2_stream *stream) { +void nghttp2_session_destroy_stream(nghttp2_session *session, + nghttp2_stream *stream) { nghttp2_mem *mem; - int rv; DEBUGF("stream: destroy closed stream(%p)=%d\n", stream, stream->stream_id); mem = &session->mem; - if (nghttp2_stream_in_dep_tree(stream)) { - rv = nghttp2_stream_dep_remove(stream); - if (rv != 0) { - return rv; - } - } - - if (stream->queued && - (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) { + if (stream->queued) { session_ob_data_remove(session, stream); } nghttp2_map_remove(&session->streams, stream->stream_id); nghttp2_stream_free(stream); nghttp2_mem_free(mem, stream); - - return 0; -} - -void nghttp2_session_keep_closed_stream(nghttp2_session *session, - nghttp2_stream *stream) { - DEBUGF("stream: keep closed stream(%p)=%d, state=%d\n", stream, - stream->stream_id, stream->state); - - if (session->closed_stream_tail) { - session->closed_stream_tail->closed_next = stream; - stream->closed_prev = session->closed_stream_tail; - } else { - session->closed_stream_head = stream; - } - session->closed_stream_tail = stream; - - ++session->num_closed_streams; -} - -void nghttp2_session_keep_idle_stream(nghttp2_session *session, - nghttp2_stream *stream) { - DEBUGF("stream: keep idle stream(%p)=%d, state=%d\n", stream, - stream->stream_id, stream->state); - - if (session->idle_stream_tail) { - session->idle_stream_tail->closed_next = stream; - stream->closed_prev = session->idle_stream_tail; - } else { - session->idle_stream_head = stream; - } - session->idle_stream_tail = stream; - - ++session->num_idle_streams; -} - -void nghttp2_session_detach_idle_stream(nghttp2_session *session, - nghttp2_stream *stream) { - nghttp2_stream *prev_stream, *next_stream; - - DEBUGF("stream: detach idle stream(%p)=%d, state=%d\n", stream, - stream->stream_id, stream->state); - - prev_stream = stream->closed_prev; - next_stream = stream->closed_next; - - if (prev_stream) { - prev_stream->closed_next = next_stream; - } else { - session->idle_stream_head = next_stream; - } - - if (next_stream) { - next_stream->closed_prev = prev_stream; - } else { - session->idle_stream_tail = prev_stream; - } - - stream->closed_prev = NULL; - stream->closed_next = NULL; - - --session->num_idle_streams; -} - -int nghttp2_session_adjust_closed_stream(nghttp2_session *session) { - size_t num_stream_max; - int rv; - - if (session->local_settings.max_concurrent_streams == - NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS) { - num_stream_max = session->pending_local_max_concurrent_stream; - } else { - num_stream_max = session->local_settings.max_concurrent_streams; - } - - DEBUGF("stream: adjusting kept closed streams num_closed_streams=%zu, " - "num_incoming_streams=%zu, max_concurrent_streams=%zu\n", - session->num_closed_streams, session->num_incoming_streams, - num_stream_max); - - while (session->num_closed_streams > 0 && - session->num_closed_streams + session->num_incoming_streams > - num_stream_max) { - nghttp2_stream *head_stream; - nghttp2_stream *next; - - head_stream = session->closed_stream_head; - - assert(head_stream); - - next = head_stream->closed_next; - - rv = nghttp2_session_destroy_stream(session, head_stream); - if (rv != 0) { - return rv; - } - - /* head_stream is now freed */ - - session->closed_stream_head = next; - - if (session->closed_stream_head) { - session->closed_stream_head->closed_prev = NULL; - } else { - session->closed_stream_tail = NULL; - } - - --session->num_closed_streams; - } - - return 0; -} - -int nghttp2_session_adjust_idle_stream(nghttp2_session *session) { - size_t max; - int rv; - - /* Make minimum number of idle streams 16, and maximum 100, which - are arbitrary chosen numbers. */ - max = nghttp2_min_uint32( - 100, - nghttp2_max_uint32( - 16, nghttp2_min_uint32(session->local_settings.max_concurrent_streams, - session->pending_local_max_concurrent_stream))); - - DEBUGF("stream: adjusting kept idle streams num_idle_streams=%zu, max=%zu\n", - session->num_idle_streams, max); - - while (session->num_idle_streams > max) { - nghttp2_stream *head; - nghttp2_stream *next; - - head = session->idle_stream_head; - assert(head); - - next = head->closed_next; - - rv = nghttp2_session_destroy_stream(session, head); - if (rv != 0) { - return rv; - } - - /* head is now destroyed */ - - session->idle_stream_head = next; - - if (session->idle_stream_head) { - session->idle_stream_head->closed_prev = NULL; - } else { - session->idle_stream_tail = NULL; - } - - --session->num_idle_streams; - } - - return 0; } /* @@ -2411,16 +2015,12 @@ static int session_prep_frame(nghttp2_session *session, stream = nghttp2_session_open_stream( session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, - &frame->headers.pri_spec, NGHTTP2_STREAM_INITIAL, - aux_data->stream_user_data); + NGHTTP2_STREAM_INITIAL, aux_data->stream_user_data); if (stream == NULL) { return NGHTTP2_ERR_NOMEM; } - /* We don't call nghttp2_session_adjust_closed_stream() here, - since we don't keep closed stream in client side */ - rv = session_predicate_request_headers_send(session, item); if (rv != 0) { return rv; @@ -2662,8 +2262,6 @@ static int session_prep_frame(nghttp2_session *session, nghttp2_outbound_item * nghttp2_session_get_next_ob_item(nghttp2_session *session) { - nghttp2_outbound_item *item; - if (nghttp2_outbound_queue_top(&session->ob_urgent)) { return nghttp2_outbound_queue_top(&session->ob_urgent); } @@ -2679,11 +2277,6 @@ nghttp2_session_get_next_ob_item(nghttp2_session *session) { } if (session->remote_window_size > 0) { - item = nghttp2_stream_next_outbound_item(&session->root); - if (item) { - return item; - } - return session_sched_get_next_outbound_item(session); } @@ -2718,11 +2311,6 @@ nghttp2_session_pop_next_ob_item(nghttp2_session *session) { } if (session->remote_window_size > 0) { - item = nghttp2_stream_next_outbound_item(&session->root); - if (item) { - return item; - } - return session_sched_get_next_outbound_item(session); } @@ -2781,7 +2369,6 @@ static int find_stream_on_goaway_func(void *entry, void *ptr) { nghttp2_session_close_stream() inside nghttp2_map_each(). Reuse closed_next member.. bad choice? */ assert(stream->closed_next == NULL); - assert(stream->closed_prev == NULL); if (arg->head) { stream->closed_next = arg->head; @@ -2837,11 +2424,6 @@ static void session_reschedule_stream(nghttp2_session *session, nghttp2_stream *stream) { stream->last_writelen = stream->item->frame.hd.length; - if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) { - nghttp2_stream_reschedule(stream); - return; - } - if (!session->server) { return; } @@ -3020,37 +2602,6 @@ static int session_after_frame_sent1(nghttp2_session *session) { } } case NGHTTP2_PRIORITY: - if (session->server || session->pending_no_rfc7540_priorities == 1) { - return 0; - } - - stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); - - if (!stream) { - if (!session_detect_idle_stream(session, frame->hd.stream_id)) { - return 0; - } - - stream = nghttp2_session_open_stream( - session, frame->hd.stream_id, NGHTTP2_FLAG_NONE, - &frame->priority.pri_spec, NGHTTP2_STREAM_IDLE, NULL); - if (!stream) { - return NGHTTP2_ERR_NOMEM; - } - } else { - rv = nghttp2_session_reprioritize_stream(session, stream, - &frame->priority.pri_spec); - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - - rv = nghttp2_session_adjust_idle_stream(session); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - return 0; case NGHTTP2_RST_STREAM: rv = nghttp2_session_close_stream(session, frame->hd.stream_id, @@ -3239,14 +2790,6 @@ static nghttp2_ssize nghttp2_session_mem_send_internal(nghttp2_session *session, aob = &session->aob; framebufs = &aob->framebufs; - /* We may have idle streams more than we expect (e.g., - nghttp2_session_change_stream_priority() or - nghttp2_session_create_idle_stream()). Adjust them here. */ - rv = nghttp2_session_adjust_idle_stream(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - for (;;) { switch (aob->state) { case NGHTTP2_OB_POP_ITEM: { @@ -4064,7 +3607,6 @@ static int session_end_stream_headers_received(nghttp2_session *session, if (session->server && session_enforce_http_messaging(session) && frame->headers.cat == NGHTTP2_HCAT_REQUEST && - (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) && !(stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) && (stream->http_flags & NGHTTP2_HTTP_FLAG_PRIORITY)) { rv = session_update_stream_priority(session, stream, stream->http_extpri); @@ -4253,18 +3795,13 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session, NGHTTP2_ERR_REFUSED_STREAM); } - stream = nghttp2_session_open_stream( - session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, - &frame->headers.pri_spec, NGHTTP2_STREAM_OPENING, NULL); + stream = nghttp2_session_open_stream(session, frame->hd.stream_id, + NGHTTP2_STREAM_FLAG_NONE, + NGHTTP2_STREAM_OPENING, NULL); if (!stream) { return NGHTTP2_ERR_NOMEM; } - rv = nghttp2_session_adjust_closed_stream(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - session->last_proc_stream_id = session->last_recv_stream_id; rv = session_call_on_begin_headers(session, frame); @@ -4425,77 +3962,6 @@ static int session_process_headers_frame(nghttp2_session *session) { return nghttp2_session_on_headers_received(session, frame, stream); } -int nghttp2_session_on_priority_received(nghttp2_session *session, - nghttp2_frame *frame) { - int rv; - nghttp2_stream *stream; - - assert(!session_no_rfc7540_pri_no_fallback(session)); - - if (frame->hd.stream_id == 0) { - return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, - "PRIORITY: stream_id == 0"); - } - - if (frame->priority.pri_spec.stream_id == frame->hd.stream_id) { - return nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, "depend on itself"); - } - - if (!session->server) { - /* Re-prioritization works only in server */ - return session_call_on_frame_received(session, frame); - } - - stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); - - if (!stream) { - /* PRIORITY against idle stream can create anchor node in - dependency tree. */ - if (!session_detect_idle_stream(session, frame->hd.stream_id)) { - return 0; - } - - stream = nghttp2_session_open_stream( - session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, - &frame->priority.pri_spec, NGHTTP2_STREAM_IDLE, NULL); - - if (stream == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - rv = nghttp2_session_adjust_idle_stream(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - } else { - rv = nghttp2_session_reprioritize_stream(session, stream, - &frame->priority.pri_spec); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - rv = nghttp2_session_adjust_idle_stream(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - - return session_call_on_frame_received(session, frame); -} - -static int session_process_priority_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - - assert(!session_no_rfc7540_pri_no_fallback(session)); - - nghttp2_frame_unpack_priority_payload(&frame->priority, iframe->sbuf.pos); - - return nghttp2_session_on_priority_received(session, frame); -} - static int session_update_stream_reset_ratelim(nghttp2_session *session) { if (!session->server || (session->goaway_flags & NGHTTP2_GOAWAY_SUBMITTED)) { return 0; @@ -4934,12 +4400,6 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, if (session->remote_settings.no_rfc7540_priorities == UINT32_MAX) { session->remote_settings.no_rfc7540_priorities = 0; - - if (session->server && session->pending_no_rfc7540_priorities && - (session->opt_flags & - NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES)) { - session->fallback_rfc7540_priorities = 1; - } } if (!noack && !session_is_closing(session)) { @@ -5000,7 +4460,6 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, int rv; nghttp2_stream *stream; nghttp2_stream *promised_stream; - nghttp2_priority_spec pri_spec; if (frame->hd.stream_id == 0) { return session_inflate_handle_invalid_connection( @@ -5058,20 +4517,14 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, session, frame, NGHTTP2_ERR_STREAM_CLOSED, "PUSH_PROMISE: stream closed"); } - nghttp2_priority_spec_init(&pri_spec, stream->stream_id, - NGHTTP2_DEFAULT_WEIGHT, 0); - promised_stream = nghttp2_session_open_stream( session, frame->push_promise.promised_stream_id, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec, NGHTTP2_STREAM_RESERVED, NULL); + NGHTTP2_STREAM_RESERVED, NULL); if (!promised_stream) { return NGHTTP2_ERR_NOMEM; } - /* We don't call nghttp2_session_adjust_closed_stream(), since we - don't keep closed stream in client side */ - session->last_proc_stream_id = session->last_recv_stream_id; rv = session_call_on_begin_headers(session, frame); if (rv != 0) { @@ -5292,7 +4745,6 @@ int nghttp2_session_on_priority_update_received(nghttp2_session *session, nghttp2_frame *frame) { nghttp2_ext_priority_update *priority_update; nghttp2_stream *stream; - nghttp2_priority_spec pri_spec; nghttp2_extpri extpri; int rv; @@ -5330,10 +4782,9 @@ int nghttp2_session_on_priority_update_received(nghttp2_session *session, "PRIORITY_UPDATE: max concurrent streams exceeded"); } - nghttp2_priority_spec_default_init(&pri_spec); - stream = nghttp2_session_open_stream(session, priority_update->stream_id, - NGHTTP2_FLAG_NONE, &pri_spec, - NGHTTP2_STREAM_IDLE, NULL); + stream = + nghttp2_session_open_stream(session, priority_update->stream_id, + NGHTTP2_FLAG_NONE, NGHTTP2_STREAM_IDLE, NULL); if (!stream) { return NGHTTP2_ERR_NOMEM; } @@ -5869,14 +5320,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, mem = &session->mem; - /* We may have idle streams more than we expect (e.g., - nghttp2_session_change_stream_priority() or - nghttp2_session_create_idle_stream()). Adjust them here. */ - rv = nghttp2_session_adjust_idle_stream(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - if (!nghttp2_session_want_read(session)) { return (nghttp2_ssize)inlen; } @@ -6392,8 +5835,7 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, break; } - if (!session_no_rfc7540_pri_no_fallback(session) || - iframe->payloadleft > sizeof(iframe->raw_sbuf)) { + if (iframe->payloadleft > sizeof(iframe->raw_sbuf)) { busy = 1; iframe->state = NGHTTP2_IB_IGN_PAYLOAD; break; @@ -6510,18 +5952,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, break; case NGHTTP2_PRIORITY: - if (!session_no_rfc7540_pri_no_fallback(session) && - session->remote_settings.no_rfc7540_priorities != 1) { - rv = session_process_priority_frame(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - } - session_inbound_frame_reset(session); break; @@ -7404,9 +6834,7 @@ int nghttp2_session_want_write(nghttp2_session *session) { */ return session->aob.item || nghttp2_outbound_queue_top(&session->ob_urgent) || nghttp2_outbound_queue_top(&session->ob_reg) || - ((!nghttp2_pq_empty(&session->root.obq) || - !session_sched_empty(session)) && - session->remote_window_size > 0) || + (!session_sched_empty(session) && session->remote_window_size > 0) || (nghttp2_outbound_queue_top(&session->ob_syn) && !session_is_outgoing_concurrent_streams_max(session)); } @@ -8046,7 +7474,6 @@ static int nghttp2_session_upgrade_internal(nghttp2_session *session, nghttp2_settings_entry *iv; size_t niv; int rv; - nghttp2_priority_spec pri_spec; nghttp2_mem *mem; mem = &session->mem; @@ -8083,18 +7510,13 @@ static int nghttp2_session_upgrade_internal(nghttp2_session *session, return rv; } - nghttp2_priority_spec_default_init(&pri_spec); - stream = nghttp2_session_open_stream( - session, 1, NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_OPENING, + session, 1, NGHTTP2_STREAM_FLAG_NONE, NGHTTP2_STREAM_OPENING, session->server ? NULL : stream_user_data); if (stream == NULL) { return NGHTTP2_ERR_NOMEM; } - /* We don't call nghttp2_session_adjust_closed_stream(), since this - should be the first stream open. */ - if (session->server) { nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); session->last_recv_stream_id = 1; @@ -8293,14 +7715,16 @@ int32_t nghttp2_session_get_last_proc_stream_id(nghttp2_session *session) { nghttp2_stream *nghttp2_session_find_stream(nghttp2_session *session, int32_t stream_id) { if (stream_id == 0) { - return &session->root; + return &root; } return nghttp2_session_get_stream_raw(session, stream_id); } nghttp2_stream *nghttp2_session_get_root_stream(nghttp2_session *session) { - return &session->root; + (void)session; + + return &root; } int nghttp2_session_check_server_session(nghttp2_session *session) { @@ -8310,75 +7734,20 @@ int nghttp2_session_check_server_session(nghttp2_session *session) { int nghttp2_session_change_stream_priority( nghttp2_session *session, int32_t stream_id, const nghttp2_priority_spec *pri_spec) { - int rv; - nghttp2_stream *stream; - nghttp2_priority_spec pri_spec_copy; - - if (session->pending_no_rfc7540_priorities == 1) { - return 0; - } - - if (stream_id == 0 || stream_id == pri_spec->stream_id) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - stream = nghttp2_session_get_stream_raw(session, stream_id); - if (!stream) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - pri_spec_copy = *pri_spec; - nghttp2_priority_spec_normalize_weight(&pri_spec_copy); - - rv = nghttp2_session_reprioritize_stream(session, stream, &pri_spec_copy); + (void)session; + (void)stream_id; + (void)pri_spec; - if (nghttp2_is_fatal(rv)) { - return rv; - } - - /* We don't intentionally call nghttp2_session_adjust_idle_stream() - so that idle stream created by this function, and existing ones - are kept for application. We will adjust number of idle stream - in nghttp2_session_mem_send2 or nghttp2_session_mem_recv2 is - called. */ return 0; } int nghttp2_session_create_idle_stream(nghttp2_session *session, int32_t stream_id, const nghttp2_priority_spec *pri_spec) { - nghttp2_stream *stream; - nghttp2_priority_spec pri_spec_copy; - - if (session->pending_no_rfc7540_priorities == 1) { - return 0; - } - - if (stream_id == 0 || stream_id == pri_spec->stream_id || - !session_detect_idle_stream(session, stream_id)) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - stream = nghttp2_session_get_stream_raw(session, stream_id); - if (stream) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - pri_spec_copy = *pri_spec; - nghttp2_priority_spec_normalize_weight(&pri_spec_copy); - - stream = - nghttp2_session_open_stream(session, stream_id, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_copy, NGHTTP2_STREAM_IDLE, NULL); - if (!stream) { - return NGHTTP2_ERR_NOMEM; - } + (void)session; + (void)stream_id; + (void)pri_spec; - /* We don't intentionally call nghttp2_session_adjust_idle_stream() - so that idle stream created by this function, and existing ones - are kept for application. We will adjust number of idle stream - in nghttp2_session_mem_send2 or nghttp2_session_mem_recv2 is - called. */ return 0; } diff --git a/deps/nghttp2/lib/nghttp2_session.h b/deps/nghttp2/lib/nghttp2_session.h index ef8f7b27d67261..6a54d35fcab7fa 100644 --- a/deps/nghttp2/lib/nghttp2_session.h +++ b/deps/nghttp2/lib/nghttp2_session.h @@ -45,6 +45,8 @@ preface handling. */ extern int nghttp2_enable_strict_preface; +extern nghttp2_stream root; + /* * Option flags. */ @@ -53,8 +55,6 @@ typedef enum { NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1, NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2, NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3, - NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4, - NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 5, NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 6, } nghttp2_optmask; @@ -89,10 +89,6 @@ typedef struct { /* The default maximum number of incoming reserved streams */ #define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200 -/* Even if we have less SETTINGS_MAX_CONCURRENT_STREAMS than this - number, we keep NGHTTP2_MIN_IDLE_STREAMS streams in idle state */ -#define NGHTTP2_MIN_IDLE_STREAMS 16 - /* The maximum number of items in outbound queue, which is considered as flooding caused by peer. All frames are not considered here. We only consider PING + ACK and SETTINGS + ACK. This is because @@ -205,8 +201,6 @@ typedef struct nghttp2_inflight_settings nghttp2_inflight_settings; struct nghttp2_session { nghttp2_map /* */ streams; - /* root of dependency tree*/ - nghttp2_stream root; /* Queue for outbound urgent frames (PING and SETTINGS) */ nghttp2_outbound_queue ob_urgent; /* Queue for non-DATA frames */ @@ -229,20 +223,6 @@ struct nghttp2_session { /* Memory allocator */ nghttp2_mem mem; void *user_data; - /* Points to the latest incoming closed stream. NULL if there is no - closed stream. Only used when session is initialized as - server. */ - nghttp2_stream *closed_stream_head; - /* Points to the oldest incoming closed stream. NULL if there is no - closed stream. Only used when session is initialized as - server. */ - nghttp2_stream *closed_stream_tail; - /* Points to the latest idle stream. NULL if there is no idle - stream. Only used when session is initialized as server .*/ - nghttp2_stream *idle_stream_head; - /* Points to the oldest idle stream. NULL if there is no idle - stream. Only used when session is initialized as erver. */ - nghttp2_stream *idle_stream_tail; /* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not considered as in-flight. */ nghttp2_inflight_settings *inflight_settings_head; @@ -276,10 +256,9 @@ struct nghttp2_session { |closed_stream_head|. The current implementation only keeps incoming streams and session is initialized as server. */ size_t num_closed_streams; - /* The number of idle streams kept in |streams| hash. The idle - streams can be accessed through doubly linked list - |idle_stream_head|. The current implementation only keeps idle - streams if session is initialized as server. */ + /* The number of idle streams kept in |streams| hash. The current + implementation only keeps idle streams if session is initialized + as server. */ size_t num_idle_streams; /* The number of bytes allocated for nvbuf */ size_t nvbuflen; @@ -362,8 +341,6 @@ struct nghttp2_session { /* Unacked local SETTINGS_NO_RFC7540_PRIORITIES value, which is effective before it is acknowledged. */ uint8_t pending_no_rfc7540_priorities; - /* Turn on fallback to RFC 7540 priorities; for server use only. */ - uint8_t fallback_rfc7540_priorities; /* Nonzero if the session is server side. */ uint8_t server; /* Flags indicating GOAWAY is sent and/or received. The flags are @@ -527,15 +504,9 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags, * * This function returns a pointer to created new stream object, or * NULL. - * - * This function adjusts neither the number of closed streams or idle - * streams. The caller should manually call - * nghttp2_session_adjust_closed_stream() or - * nghttp2_session_adjust_idle_stream() respectively. */ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, int32_t stream_id, uint8_t flags, - nghttp2_priority_spec *pri_spec, nghttp2_stream_state initial_state, void *stream_user_data); @@ -544,11 +515,6 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, * is indicated by the |error_code|. When closing the stream, * on_stream_close_callback will be called. * - * If the session is initialized as server and |stream| is incoming - * stream, stream is just marked closed and this function calls - * nghttp2_session_keep_closed_stream() with |stream|. Otherwise, - * |stream| will be deleted from memory. - * * This function returns 0 if it succeeds, or one the following * negative error codes: * @@ -565,63 +531,9 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, /* * Deletes |stream| from memory. After this function returns, stream * cannot be accessed. - * - * This function returns 0 if it succeeds, or one the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory */ -int nghttp2_session_destroy_stream(nghttp2_session *session, - nghttp2_stream *stream); - -/* - * Tries to keep incoming closed stream |stream|. Due to the - * limitation of maximum number of streams in memory, |stream| is not - * closed and just deleted from memory (see - * nghttp2_session_destroy_stream). - */ -void nghttp2_session_keep_closed_stream(nghttp2_session *session, - nghttp2_stream *stream); - -/* - * Appends |stream| to linked list |session->idle_stream_head|. We - * apply fixed limit for list size. To fit into that limit, one or - * more oldest streams are removed from list as necessary. - */ -void nghttp2_session_keep_idle_stream(nghttp2_session *session, - nghttp2_stream *stream); - -/* - * Detaches |stream| from idle streams linked list. - */ -void nghttp2_session_detach_idle_stream(nghttp2_session *session, - nghttp2_stream *stream); - -/* - * Deletes closed stream to ensure that number of incoming streams - * including active and closed is in the maximum number of allowed - * stream. - * - * This function returns 0 if it succeeds, or one the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_session_adjust_closed_stream(nghttp2_session *session); - -/* - * Deletes idle stream to ensure that number of idle streams is in - * certain limit. - * - * This function returns 0 if it succeeds, or one the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_session_adjust_idle_stream(nghttp2_session *session); +void nghttp2_session_destroy_stream(nghttp2_session *session, + nghttp2_stream *stream); /* * If further receptions and transmissions over the stream |stream_id| @@ -915,24 +827,6 @@ int nghttp2_session_update_local_settings(nghttp2_session *session, nghttp2_settings_entry *iv, size_t niv); -/* - * Re-prioritize |stream|. The new priority specification is - * |pri_spec|. Caller must ensure that stream->hd.stream_id != - * pri_spec->stream_id. - * - * This function does not adjust the number of idle streams. The - * caller should call nghttp2_session_adjust_idle_stream() later. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_session_reprioritize_stream(nghttp2_session *session, - nghttp2_stream *stream, - const nghttp2_priority_spec *pri_spec); - /* * Terminates current |session| with the |error_code|. The |reason| * is NULL-terminated debug string. diff --git a/deps/nghttp2/lib/nghttp2_stream.c b/deps/nghttp2/lib/nghttp2_stream.c index f2362447903755..afbd7c2d9e0a77 100644 --- a/deps/nghttp2/lib/nghttp2_stream.c +++ b/deps/nghttp2/lib/nghttp2_stream.c @@ -25,45 +25,17 @@ #include "nghttp2_stream.h" #include -#include #include "nghttp2_session.h" #include "nghttp2_helper.h" #include "nghttp2_debug.h" #include "nghttp2_frame.h" -/* Maximum distance between any two stream's cycle in the same - priority queue. Imagine stream A's cycle is A, and stream B's - cycle is B, and A < B. The cycle is unsigned 32 bit integer, it - may get overflow. Because of how we calculate the next cycle - value, if B - A is less than or equals to - NGHTTP2_MAX_CYCLE_DISTANCE, A and B are in the same scale, in other - words, B is really greater than or equal to A. Otherwise, A is a - result of overflow, and it is actually A > B if we consider that - fact. */ -#define NGHTTP2_MAX_CYCLE_DISTANCE \ - ((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX * 256 + 255) - -static int stream_less(const void *lhsx, const void *rhsx) { - const nghttp2_stream *lhs, *rhs; - - lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry); - rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry); - - if (lhs->cycle == rhs->cycle) { - return lhs->seq < rhs->seq; - } - - return rhs->cycle - lhs->cycle <= NGHTTP2_MAX_CYCLE_DISTANCE; -} - void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, uint8_t flags, nghttp2_stream_state initial_state, - int32_t weight, int32_t remote_initial_window_size, + int32_t remote_initial_window_size, int32_t local_initial_window_size, - void *stream_user_data, nghttp2_mem *mem) { - nghttp2_pq_init(&stream->obq, stream_less, mem); - + void *stream_user_data) { stream->stream_id = stream_id; stream->flags = flags; stream->state = initial_state; @@ -77,428 +49,36 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, stream->recv_reduction = 0; stream->window_update_queued = 0; - stream->dep_prev = NULL; - stream->dep_next = NULL; - stream->sib_prev = NULL; - stream->sib_next = NULL; - - stream->closed_prev = NULL; stream->closed_next = NULL; - stream->weight = weight; - stream->sum_dep_weight = 0; - stream->http_flags = NGHTTP2_HTTP_FLAG_NONE; stream->content_length = -1; stream->recv_content_length = 0; stream->status_code = -1; stream->queued = 0; - stream->descendant_last_cycle = 0; stream->cycle = 0; stream->pending_penalty = 0; - stream->descendant_next_seq = 0; stream->seq = 0; stream->last_writelen = 0; stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY; } -void nghttp2_stream_free(nghttp2_stream *stream) { - nghttp2_pq_free(&stream->obq); - /* We don't free stream->item. If it is assigned to aob, then - active_outbound_item_reset() will delete it. Otherwise, - nghttp2_stream_close() or session_del() will delete it. */ -} +void nghttp2_stream_free(nghttp2_stream *stream) { (void)stream; } void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) { stream->shut_flags = (uint8_t)(stream->shut_flags | flag); } -/* - * Returns nonzero if |stream| is active. This function does not take - * into account its descendants. - */ -static int stream_active(nghttp2_stream *stream) { - return stream->item && - (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0; -} - -/* - * Returns nonzero if |stream| or one of its descendants is active - */ -static int stream_subtree_active(nghttp2_stream *stream) { - return stream_active(stream) || !nghttp2_pq_empty(&stream->obq); -} - -/* - * Returns next cycle for |stream|. - */ -static void stream_next_cycle(nghttp2_stream *stream, uint64_t last_cycle) { - uint64_t penalty; - - penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT + - stream->pending_penalty; - - stream->cycle = last_cycle + penalty / (uint32_t)stream->weight; - stream->pending_penalty = (uint32_t)(penalty % (uint32_t)stream->weight); -} - -static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) { - int rv; - - for (; dep_stream && !stream->queued; - stream = dep_stream, dep_stream = dep_stream->dep_prev) { - stream_next_cycle(stream, dep_stream->descendant_last_cycle); - stream->seq = dep_stream->descendant_next_seq++; - - DEBUGF("stream: stream=%d obq push cycle=%lu\n", stream->stream_id, - stream->cycle); - - DEBUGF("stream: push stream %d to stream %d\n", stream->stream_id, - dep_stream->stream_id); - - rv = nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); - if (rv != 0) { - return rv; - } - stream->queued = 1; - } - - return 0; -} - -/* - * Removes |stream| from parent's obq. If removal of |stream| makes - * parent's obq empty, and parent is not active, then parent is also - * removed. This process is repeated recursively. - */ -static void stream_obq_remove(nghttp2_stream *stream) { - nghttp2_stream *dep_stream; - - dep_stream = stream->dep_prev; - - if (!stream->queued) { - return; - } - - for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) { - DEBUGF("stream: remove stream %d from stream %d\n", stream->stream_id, - dep_stream->stream_id); - - nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); - - assert(stream->queued); - - stream->queued = 0; - stream->cycle = 0; - stream->pending_penalty = 0; - stream->descendant_last_cycle = 0; - stream->last_writelen = 0; - - if (stream_subtree_active(dep_stream)) { - return; - } - } -} - -/* - * Moves |stream| from |src|'s obq to |dest|'s obq. Removal from - * |src|'s obq is just done calling nghttp2_pq_remove(), so it does - * not recursively remove |src| and ancestors, like - * stream_obq_remove(). - */ -static int stream_obq_move(nghttp2_stream *dest, nghttp2_stream *src, - nghttp2_stream *stream) { - if (!stream->queued) { - return 0; - } - - DEBUGF("stream: remove stream %d from stream %d (move)\n", stream->stream_id, - src->stream_id); - - nghttp2_pq_remove(&src->obq, &stream->pq_entry); - stream->queued = 0; - - return stream_obq_push(dest, stream); -} - -void nghttp2_stream_reschedule(nghttp2_stream *stream) { - nghttp2_stream *dep_stream; - - assert(stream->queued); - - dep_stream = stream->dep_prev; - - for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) { - nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); - - stream_next_cycle(stream, dep_stream->descendant_last_cycle); - stream->seq = dep_stream->descendant_next_seq++; - - nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); - - DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id, - stream->cycle); - - dep_stream->last_writelen = stream->last_writelen; - } -} - -void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) { - nghttp2_stream *dep_stream; - uint64_t last_cycle; - int32_t old_weight; - uint64_t wlen_penalty; - - if (stream->weight == weight) { - return; - } - - old_weight = stream->weight; - stream->weight = weight; - - dep_stream = stream->dep_prev; - - if (!dep_stream) { - return; - } - - dep_stream->sum_dep_weight += weight - old_weight; - - if (!stream->queued) { - return; - } - - nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); - - wlen_penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT; - - /* Compute old stream->pending_penalty we used to calculate - stream->cycle */ - stream->pending_penalty = - (uint32_t)((stream->pending_penalty + (uint32_t)old_weight - - (wlen_penalty % (uint32_t)old_weight)) % - (uint32_t)old_weight); - - last_cycle = stream->cycle - - (wlen_penalty + stream->pending_penalty) / (uint32_t)old_weight; - - /* Now we have old stream->pending_penalty and new stream->weight in - place */ - stream_next_cycle(stream, last_cycle); - - if (dep_stream->descendant_last_cycle - stream->cycle <= - NGHTTP2_MAX_CYCLE_DISTANCE) { - stream->cycle = dep_stream->descendant_last_cycle; - } - - /* Continue to use same stream->seq */ - - nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); - - DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id, - stream->cycle); -} - -static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) { - for (; stream->sib_next; stream = stream->sib_next) - ; - - return stream; -} - -int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, - int32_t weight) { - weight = stream->weight * weight / stream->sum_dep_weight; - - return nghttp2_max_int32(1, weight); -} - -#ifdef STREAM_DEP_DEBUG - -static void ensure_inactive(nghttp2_stream *stream) { - nghttp2_stream *si; - - if (stream->queued) { - fprintf(stderr, "stream(%p)=%d, stream->queued = 1; want 0\n", stream, - stream->stream_id); - assert(0); - } - - if (stream_active(stream)) { - fprintf(stderr, "stream(%p)=%d, stream_active(stream) = 1; want 0\n", - stream, stream->stream_id); - assert(0); - } - - if (!nghttp2_pq_empty(&stream->obq)) { - fprintf(stderr, "stream(%p)=%d, nghttp2_pq_size() = %zu; want 0\n", stream, - stream->stream_id, nghttp2_pq_size(&stream->obq)); - assert(0); - } - - for (si = stream->dep_next; si; si = si->sib_next) { - ensure_inactive(si); - } -} - -static void check_queued(nghttp2_stream *stream) { - nghttp2_stream *si; - int queued; - - if (stream->queued) { - if (!stream_subtree_active(stream)) { - fprintf(stderr, - "stream(%p)=%d, stream->queued == 1, but " - "stream_active() == %d and nghttp2_pq_size(&stream->obq) = %zu\n", - stream, stream->stream_id, stream_active(stream), - nghttp2_pq_size(&stream->obq)); - assert(0); - } - if (!stream_active(stream)) { - queued = 0; - for (si = stream->dep_next; si; si = si->sib_next) { - if (si->queued) { - ++queued; - } - } - if (queued == 0) { - fprintf(stderr, - "stream(%p)=%d, stream->queued == 1, and " - "!stream_active(), but no descendants is queued\n", - stream, stream->stream_id); - assert(0); - } - } - - for (si = stream->dep_next; si; si = si->sib_next) { - check_queued(si); - } - } else { - if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) { - fprintf(stderr, - "stream(%p) = %d, stream->queued == 0, but " - "stream_active(stream) == %d and " - "nghttp2_pq_size(&stream->obq) = %zu\n", - stream, stream->stream_id, stream_active(stream), - nghttp2_pq_size(&stream->obq)); - assert(0); - } - for (si = stream->dep_next; si; si = si->sib_next) { - ensure_inactive(si); - } - } -} - -static void check_sum_dep(nghttp2_stream *stream) { - nghttp2_stream *si; - int32_t n = 0; - for (si = stream->dep_next; si; si = si->sib_next) { - n += si->weight; - } - if (n != stream->sum_dep_weight) { - fprintf(stderr, "stream(%p)=%d, sum_dep_weight = %d; want %d\n", stream, - stream->stream_id, n, stream->sum_dep_weight); - assert(0); - } - for (si = stream->dep_next; si; si = si->sib_next) { - check_sum_dep(si); - } -} - -static void check_dep_prev(nghttp2_stream *stream) { - nghttp2_stream *si; - for (si = stream->dep_next; si; si = si->sib_next) { - if (si->dep_prev != stream) { - fprintf(stderr, "si->dep_prev = %p; want %p\n", si->dep_prev, stream); - assert(0); - } - check_dep_prev(si); - } -} - -#endif /* STREAM_DEP_DEBUG */ - -#ifdef STREAM_DEP_DEBUG -static void validate_tree(nghttp2_stream *stream) { - nghttp2_stream *si; - - if (!stream) { - return; - } - - for (; stream->dep_prev; stream = stream->dep_prev) - ; - - assert(stream->stream_id == 0); - assert(!stream->queued); - - fprintf(stderr, "checking...\n"); - if (nghttp2_pq_empty(&stream->obq)) { - fprintf(stderr, "root obq empty\n"); - for (si = stream->dep_next; si; si = si->sib_next) { - ensure_inactive(si); - } - } else { - for (si = stream->dep_next; si; si = si->sib_next) { - check_queued(si); - } - } - - check_sum_dep(stream); - check_dep_prev(stream); -} -#else /* !STREAM_DEP_DEBUG */ -static void validate_tree(nghttp2_stream *stream) { (void)stream; } -#endif /* !STREAM_DEP_DEBUG*/ - -static int stream_update_dep_on_attach_item(nghttp2_stream *stream) { - int rv; - - rv = stream_obq_push(stream->dep_prev, stream); - if (rv != 0) { - return rv; - } - - validate_tree(stream); - return 0; -} - -static void stream_update_dep_on_detach_item(nghttp2_stream *stream) { - if (nghttp2_pq_empty(&stream->obq)) { - stream_obq_remove(stream); - } - - validate_tree(stream); -} - -int nghttp2_stream_attach_item(nghttp2_stream *stream, - nghttp2_outbound_item *item) { - int rv; - +void nghttp2_stream_attach_item(nghttp2_stream *stream, + nghttp2_outbound_item *item) { assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0); assert(stream->item == NULL); DEBUGF("stream: stream=%d attach item=%p\n", stream->stream_id, item); stream->item = item; - - if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { - return 0; - } - - rv = stream_update_dep_on_attach_item(stream); - if (rv != 0) { - /* This may relave stream->queued == 1, but stream->item == NULL. - But only consequence of this error is fatal one, and session - destruction. In that execution path, these inconsistency does - not matter. */ - stream->item = NULL; - return rv; - } - - return 0; } void nghttp2_stream_detach_item(nghttp2_stream *stream) { @@ -506,12 +86,6 @@ void nghttp2_stream_detach_item(nghttp2_stream *stream) { stream->item = NULL; stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL); - - if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { - return; - } - - stream_update_dep_on_detach_item(stream); } void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) { @@ -521,31 +95,16 @@ void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) { stream->item, flags); stream->flags |= flags; - - if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { - return; - } - - stream_update_dep_on_detach_item(stream); } -int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) { +void nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, + uint8_t flags) { assert(stream->item); DEBUGF("stream: stream=%d resume item=%p flags=%02x\n", stream->stream_id, stream->item, flags); stream->flags = (uint8_t)(stream->flags & ~flags); - - if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) { - return 0; - } - - if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { - return 0; - } - - return stream_update_dep_on_attach_item(stream); } int nghttp2_stream_check_deferred_item(nghttp2_stream *stream) { @@ -591,373 +150,11 @@ void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) { stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH); } -int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream, - nghttp2_stream *target) { - for (; stream; stream = stream->dep_prev) { - if (stream == target) { - return 1; - } - } - return 0; -} - -int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, - nghttp2_stream *stream) { - nghttp2_stream *si; - int rv; - - DEBUGF("stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream, - dep_stream->stream_id, stream, stream->stream_id); - - stream->sum_dep_weight = dep_stream->sum_dep_weight; - dep_stream->sum_dep_weight = stream->weight; - - if (dep_stream->dep_next) { - for (si = dep_stream->dep_next; si; si = si->sib_next) { - si->dep_prev = stream; - if (si->queued) { - rv = stream_obq_move(stream, dep_stream, si); - if (rv != 0) { - return rv; - } - } - } - - if (stream_subtree_active(stream)) { - rv = stream_obq_push(dep_stream, stream); - if (rv != 0) { - return rv; - } - } - - stream->dep_next = dep_stream->dep_next; - } - - dep_stream->dep_next = stream; - stream->dep_prev = dep_stream; - - validate_tree(stream); - - return 0; -} - -static void set_dep_prev(nghttp2_stream *stream, nghttp2_stream *dep) { - for (; stream; stream = stream->sib_next) { - stream->dep_prev = dep; - } -} - -static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) { - dep_stream->dep_next = stream; - if (stream) { - stream->dep_prev = dep_stream; - } -} - -static void link_sib(nghttp2_stream *a, nghttp2_stream *b) { - a->sib_next = b; - if (b) { - b->sib_prev = a; - } -} - -static void insert_link_dep(nghttp2_stream *dep_stream, - nghttp2_stream *stream) { - nghttp2_stream *sib_next; - - assert(stream->sib_prev == NULL); - - sib_next = dep_stream->dep_next; - - link_sib(stream, sib_next); - - link_dep(dep_stream, stream); -} - -static void unlink_sib(nghttp2_stream *stream) { - nghttp2_stream *prev, *next, *dep_next; - - prev = stream->sib_prev; - dep_next = stream->dep_next; - - assert(prev); - - if (dep_next) { - /* - * prev--stream(--sib_next--...) - * | - * dep_next - */ - - link_sib(prev, dep_next); - - set_dep_prev(dep_next, stream->dep_prev); - - if (stream->sib_next) { - link_sib(stream_last_sib(dep_next), stream->sib_next); - } - } else { - /* - * prev--stream(--sib_next--...) - */ - next = stream->sib_next; - - prev->sib_next = next; - - if (next) { - next->sib_prev = prev; - } - } -} - -static void unlink_dep(nghttp2_stream *stream) { - nghttp2_stream *prev, *next, *dep_next; - - prev = stream->dep_prev; - dep_next = stream->dep_next; - - assert(prev); - - if (dep_next) { - /* - * prev - * | - * stream(--sib_next--...) - * | - * dep_next - */ - link_dep(prev, dep_next); - - set_dep_prev(dep_next, stream->dep_prev); - - if (stream->sib_next) { - link_sib(stream_last_sib(dep_next), stream->sib_next); - } - - } else if (stream->sib_next) { - /* - * prev - * | - * stream--sib_next - */ - next = stream->sib_next; - - next->sib_prev = NULL; - - link_dep(prev, next); - } else { - prev->dep_next = NULL; - } -} - -void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, - nghttp2_stream *stream) { - DEBUGF("stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream, - dep_stream->stream_id, stream, stream->stream_id); - - dep_stream->sum_dep_weight += stream->weight; - - if (dep_stream->dep_next == NULL) { - link_dep(dep_stream, stream); - } else { - insert_link_dep(dep_stream, stream); - } - - validate_tree(stream); -} - -int nghttp2_stream_dep_remove(nghttp2_stream *stream) { - nghttp2_stream *dep_prev, *si; - int32_t sum_dep_weight_delta; - int rv; - - DEBUGF("stream: dep_remove stream(%p)=%d\n", stream, stream->stream_id); - - /* Distribute weight of |stream| to direct descendants */ - sum_dep_weight_delta = -stream->weight; - - for (si = stream->dep_next; si; si = si->sib_next) { - si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight); - - sum_dep_weight_delta += si->weight; - - if (si->queued) { - rv = stream_obq_move(stream->dep_prev, stream, si); - if (rv != 0) { - return rv; - } - } - } - - assert(stream->dep_prev); - - dep_prev = stream->dep_prev; - - dep_prev->sum_dep_weight += sum_dep_weight_delta; - - if (stream->queued) { - stream_obq_remove(stream); - } - - if (stream->sib_prev) { - unlink_sib(stream); - } else { - unlink_dep(stream); - } - - stream->sum_dep_weight = 0; - - stream->dep_prev = NULL; - stream->dep_next = NULL; - stream->sib_prev = NULL; - stream->sib_next = NULL; - - validate_tree(dep_prev); - - return 0; -} - -int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, - nghttp2_stream *stream) { - nghttp2_stream *last_sib; - nghttp2_stream *dep_next; - nghttp2_stream *si; - int rv; - - DEBUGF("stream: dep_insert_subtree dep_stream(%p)=%d stream(%p)=%d\n", - dep_stream, dep_stream->stream_id, stream, stream->stream_id); - - stream->sum_dep_weight += dep_stream->sum_dep_weight; - dep_stream->sum_dep_weight = stream->weight; - - if (dep_stream->dep_next) { - dep_next = dep_stream->dep_next; - - link_dep(dep_stream, stream); - - if (stream->dep_next) { - last_sib = stream_last_sib(stream->dep_next); - - link_sib(last_sib, dep_next); - } else { - link_dep(stream, dep_next); - } - - for (si = dep_next; si; si = si->sib_next) { - si->dep_prev = stream; - if (si->queued) { - rv = stream_obq_move(stream, dep_stream, si); - if (rv != 0) { - return rv; - } - } - } - } else { - link_dep(dep_stream, stream); - } - - if (stream_subtree_active(stream)) { - rv = stream_obq_push(dep_stream, stream); - if (rv != 0) { - return rv; - } - } - - validate_tree(dep_stream); - - return 0; -} - -int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, - nghttp2_stream *stream) { - int rv; - - DEBUGF("stream: dep_add_subtree dep_stream(%p)=%d stream(%p)=%d\n", - dep_stream, dep_stream->stream_id, stream, stream->stream_id); - - dep_stream->sum_dep_weight += stream->weight; - - if (dep_stream->dep_next) { - insert_link_dep(dep_stream, stream); - } else { - link_dep(dep_stream, stream); - } - - if (stream_subtree_active(stream)) { - rv = stream_obq_push(dep_stream, stream); - if (rv != 0) { - return rv; - } - } - - validate_tree(dep_stream); - - return 0; -} - -void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) { - nghttp2_stream *next, *dep_prev; - - DEBUGF("stream: dep_remove_subtree stream(%p)=%d\n", stream, - stream->stream_id); - - assert(stream->dep_prev); - - dep_prev = stream->dep_prev; - - if (stream->sib_prev) { - link_sib(stream->sib_prev, stream->sib_next); - } else { - next = stream->sib_next; - - link_dep(dep_prev, next); - - if (next) { - next->sib_prev = NULL; - } - } - - dep_prev->sum_dep_weight -= stream->weight; - - if (stream->queued) { - stream_obq_remove(stream); - } - - validate_tree(dep_prev); - - stream->sib_prev = NULL; - stream->sib_next = NULL; - stream->dep_prev = NULL; -} - -int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) { - return stream->dep_prev || stream->dep_next || stream->sib_prev || - stream->sib_next; -} - -nghttp2_outbound_item * -nghttp2_stream_next_outbound_item(nghttp2_stream *stream) { - nghttp2_pq_entry *ent; - nghttp2_stream *si; - - for (;;) { - if (stream_active(stream)) { - /* Update ascendant's descendant_last_cycle here, so that we can - assure that new stream is scheduled based on it. */ - for (si = stream; si->dep_prev; si = si->dep_prev) { - si->dep_prev->descendant_last_cycle = si->cycle; - } - return stream->item; - } - ent = nghttp2_pq_top(&stream->obq); - if (!ent) { - return NULL; - } - stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry); +nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) { + if (stream == &root) { + return NGHTTP2_STREAM_STATE_IDLE; } -} -nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) { if (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) { return NGHTTP2_STREAM_STATE_CLOSED; } @@ -988,27 +185,39 @@ nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) { } nghttp2_stream *nghttp2_stream_get_parent(nghttp2_stream *stream) { - return stream->dep_prev; + (void)stream; + + return NULL; } nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream) { - return stream->sib_next; + (void)stream; + + return NULL; } nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream) { - return stream->sib_prev; + (void)stream; + + return NULL; } nghttp2_stream *nghttp2_stream_get_first_child(nghttp2_stream *stream) { - return stream->dep_next; + (void)stream; + + return NULL; } int32_t nghttp2_stream_get_weight(nghttp2_stream *stream) { - return stream->weight; + (void)stream; + + return NGHTTP2_DEFAULT_WEIGHT; } int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream) { - return stream->sum_dep_weight; + (void)stream; + + return 0; } int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream) { diff --git a/deps/nghttp2/lib/nghttp2_stream.h b/deps/nghttp2/lib/nghttp2_stream.h index 28add165469d94..e73cd283b1dca4 100644 --- a/deps/nghttp2/lib/nghttp2_stream.h +++ b/deps/nghttp2/lib/nghttp2_stream.h @@ -91,9 +91,6 @@ typedef enum { /* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and NGHTTP2_STREAM_FLAG_DEFERRED_USER. */ NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c, - /* Indicates that this stream is not subject to RFC7540 - priorities scheme. */ - NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES = 0x10, /* Ignore client RFC 9218 priority signal. */ NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES = 0x20, /* Indicates that RFC 9113 leading and trailing white spaces @@ -146,39 +143,18 @@ typedef enum { } nghttp2_http_flag; struct nghttp2_stream { - /* Entry for dep_prev->obq */ + nghttp2_stream_state state; nghttp2_pq_entry pq_entry; - /* Priority Queue storing direct descendant (nghttp2_stream). Only - streams which itself has some data to send, or has a descendant - which has some data to sent. */ - nghttp2_pq obq; /* Content-Length of request/response body. -1 if unknown. */ int64_t content_length; /* Received body so far */ int64_t recv_content_length; - /* Base last_cycle for direct descendent streams. */ - uint64_t descendant_last_cycle; /* Next scheduled time to sent item */ uint64_t cycle; - /* Next seq used for direct descendant streams */ - uint64_t descendant_next_seq; /* Secondary key for prioritization to break a tie for cycle. This value is monotonically increased for single parent stream. */ uint64_t seq; - /* pointers to form dependency tree. If multiple streams depend on - a stream, only one stream (left most) has non-NULL dep_prev which - points to the stream it depends on. The remaining streams are - linked using sib_prev and sib_next. The stream which has - non-NULL dep_prev always NULL sib_prev. The right most stream - has NULL sib_next. If this stream is a root of dependency tree, - dep_prev and sib_prev are NULL. */ - nghttp2_stream *dep_prev, *dep_next; - nghttp2_stream *sib_prev, *sib_next; - /* When stream is kept after closure, it may be kept in doubly - linked list pointed by nghttp2_session closed_stream_head. - closed_next points to the next stream object if it is the element - of the list. */ - nghttp2_stream *closed_prev, *closed_next; + nghttp2_stream *closed_next; /* The arbitrary data provided by user for this stream. */ void *stream_user_data; /* Item to send */ @@ -205,13 +181,8 @@ struct nghttp2_stream { NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */ int32_t local_window_size; - /* weight of this stream */ - int32_t weight; /* This is unpaid penalty (offset) when calculating cycle. */ uint32_t pending_penalty; - /* sum of weight of direct descendants */ - int32_t sum_dep_weight; - nghttp2_stream_state state; /* status code from remote server */ int16_t status_code; /* Bitwise OR of zero or more nghttp2_http_flag values */ @@ -239,9 +210,9 @@ struct nghttp2_stream { void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, uint8_t flags, nghttp2_stream_state initial_state, - int32_t weight, int32_t remote_initial_window_size, + int32_t remote_initial_window_size, int32_t local_initial_window_size, - void *stream_user_data, nghttp2_mem *mem); + void *stream_user_data); void nghttp2_stream_free(nghttp2_stream *stream); @@ -267,14 +238,8 @@ void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags); * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are * cleared if they are set. So even if this function is called, if * one of flag is still set, data does not become active. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory */ -int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags); +void nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags); /* * Returns nonzero if item is deferred by whatever reason. @@ -317,57 +282,11 @@ int nghttp2_stream_update_local_initial_window_size( */ void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream); -/* - * Returns nonzero if |target| is an ancestor of |stream|. - */ -int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream, - nghttp2_stream *target); - -/* - * Computes distributed weight of a stream of the |weight| under the - * |stream| if |stream| is removed from a dependency tree. - */ -int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, - int32_t weight); - -/* - * Makes the |stream| depend on the |dep_stream|. This dependency is - * exclusive. All existing direct descendants of |dep_stream| become - * the descendants of the |stream|. This function assumes - * |stream->item| is NULL. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, - nghttp2_stream *stream); - -/* - * Makes the |stream| depend on the |dep_stream|. This dependency is - * not exclusive. This function assumes |stream->item| is NULL. - */ -void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream); - -/* - * Removes the |stream| from the current dependency tree. This - * function assumes |stream->item| is NULL. - */ -int nghttp2_stream_dep_remove(nghttp2_stream *stream); - /* * Attaches |item| to |stream|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory */ -int nghttp2_stream_attach_item(nghttp2_stream *stream, - nghttp2_outbound_item *item); +void nghttp2_stream_attach_item(nghttp2_stream *stream, + nghttp2_outbound_item *item); /* * Detaches |stream->item|. This function does not free @@ -375,66 +294,4 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream, */ void nghttp2_stream_detach_item(nghttp2_stream *stream); -/* - * Makes the |stream| depend on the |dep_stream|. This dependency is - * exclusive. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, - nghttp2_stream *stream); - -/* - * Makes the |stream| depend on the |dep_stream|. This dependency is - * not exclusive. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, - nghttp2_stream *stream); - -/* - * Removes subtree whose root stream is |stream|. The - * effective_weight of streams in removed subtree is not updated. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream); - -/* - * Returns nonzero if |stream| is in any dependency tree. - */ -int nghttp2_stream_in_dep_tree(nghttp2_stream *stream); - -/* - * Schedules transmission of |stream|'s item, assuming stream->item is - * attached, and stream->last_writelen was updated. - */ -void nghttp2_stream_reschedule(nghttp2_stream *stream); - -/* - * Changes |stream|'s weight to |weight|. If |stream| is queued, it - * will be rescheduled based on new weight. - */ -void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight); - -/* - * Returns a stream which has highest priority, updating - * descendant_last_cycle of selected stream's ancestors. - */ -nghttp2_outbound_item * -nghttp2_stream_next_outbound_item(nghttp2_stream *stream); - #endif /* NGHTTP2_STREAM */ diff --git a/deps/nghttp2/lib/nghttp2_submit.c b/deps/nghttp2/lib/nghttp2_submit.c index 81c1ab7046bc33..d481aebde221fd 100644 --- a/deps/nghttp2/lib/nghttp2_submit.c +++ b/deps/nghttp2/lib/nghttp2_submit.c @@ -32,42 +32,12 @@ #include "nghttp2_helper.h" #include "nghttp2_priority_spec.h" -/* - * Detects the dependency error, that is stream attempted to depend on - * itself. If |stream_id| is -1, we use session->next_stream_id as - * stream ID. - * - * This function returns 0 if it succeeds, or one of the following - * error codes: - * - * NGHTTP2_ERR_INVALID_ARGUMENT - * Stream attempted to depend on itself. - */ -static int detect_self_dependency(nghttp2_session *session, int32_t stream_id, - const nghttp2_priority_spec *pri_spec) { - assert(pri_spec); - - if (stream_id == -1) { - if ((int32_t)session->next_stream_id == pri_spec->stream_id) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - return 0; - } - - if (stream_id == pri_spec->stream_id) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - return 0; -} - /* This function takes ownership of |nva_copy|. Regardless of the return value, the caller must not free |nva_copy| after this function returns. */ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_priority_spec *pri_spec, - nghttp2_nv *nva_copy, size_t nvlen, + int32_t stream_id, nghttp2_nv *nva_copy, + size_t nvlen, const nghttp2_data_provider_wrap *dpw, void *stream_user_data) { int rv; @@ -114,8 +84,8 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags, frame = &item->frame; - nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, hcat, - pri_spec, nva_copy, nvlen); + nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, hcat, NULL, + nva_copy, nvlen); rv = nghttp2_session_add_item(session, item); @@ -141,31 +111,22 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags, static int32_t submit_headers_shared_nva(nghttp2_session *session, uint8_t flags, int32_t stream_id, - const nghttp2_priority_spec *pri_spec, const nghttp2_nv *nva, size_t nvlen, const nghttp2_data_provider_wrap *dpw, void *stream_user_data) { int rv; nghttp2_nv *nva_copy; - nghttp2_priority_spec copy_pri_spec; nghttp2_mem *mem; mem = &session->mem; - if (pri_spec) { - copy_pri_spec = *pri_spec; - nghttp2_priority_spec_normalize_weight(©_pri_spec); - } else { - nghttp2_priority_spec_default_init(©_pri_spec); - } - rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem); if (rv < 0) { return rv; } - return submit_headers_shared(session, flags, stream_id, ©_pri_spec, - nva_copy, nvlen, dpw, stream_user_data); + return submit_headers_shared(session, flags, stream_id, nva_copy, nvlen, dpw, + stream_user_data); } int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id, @@ -174,8 +135,8 @@ int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id, return NGHTTP2_ERR_INVALID_ARGUMENT; } - return (int)submit_headers_shared_nva( - session, NGHTTP2_FLAG_END_STREAM, stream_id, NULL, nva, nvlen, NULL, NULL); + return (int)submit_headers_shared_nva(session, NGHTTP2_FLAG_END_STREAM, + stream_id, nva, nvlen, NULL, NULL); } int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, @@ -183,7 +144,7 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, const nghttp2_priority_spec *pri_spec, const nghttp2_nv *nva, size_t nvlen, void *stream_user_data) { - int rv; + (void)pri_spec; if (stream_id == -1) { if (session->server) { @@ -195,20 +156,8 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, flags &= NGHTTP2_FLAG_END_STREAM; - if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) && - session->remote_settings.no_rfc7540_priorities != 1) { - rv = detect_self_dependency(session, stream_id, pri_spec); - if (rv != 0) { - return rv; - } - - flags |= NGHTTP2_FLAG_PRIORITY; - } else { - pri_spec = NULL; - } - - return submit_headers_shared_nva(session, flags, stream_id, pri_spec, nva, - nvlen, NULL, stream_user_data); + return submit_headers_shared_nva(session, flags, stream_id, nva, nvlen, NULL, + stream_user_data); } int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags, @@ -220,51 +169,10 @@ int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags, int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, int32_t stream_id, const nghttp2_priority_spec *pri_spec) { - int rv; - nghttp2_outbound_item *item; - nghttp2_frame *frame; - nghttp2_priority_spec copy_pri_spec; - nghttp2_mem *mem; + (void)session; (void)flags; - - mem = &session->mem; - - if (session->remote_settings.no_rfc7540_priorities == 1) { - return 0; - } - - if (stream_id == 0 || pri_spec == NULL) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (stream_id == pri_spec->stream_id) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - copy_pri_spec = *pri_spec; - - nghttp2_priority_spec_normalize_weight(©_pri_spec); - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - - if (item == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_outbound_item_init(item); - - frame = &item->frame; - - nghttp2_frame_priority_init(&frame->priority, stream_id, ©_pri_spec); - - rv = nghttp2_session_add_item(session, item); - - if (rv != 0) { - nghttp2_frame_priority_free(&frame->priority); - nghttp2_mem_free(mem, item); - - return rv; - } + (void)stream_id; + (void)pri_spec; return 0; } @@ -738,46 +646,29 @@ int nghttp2_submit_priority_update(nghttp2_session *session, uint8_t flags, return rv; } -static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec, - const nghttp2_data_provider_wrap *dpw) { +static uint8_t set_request_flags(const nghttp2_data_provider_wrap *dpw) { uint8_t flags = NGHTTP2_FLAG_NONE; if (dpw == NULL || dpw->data_prd.read_callback == NULL) { flags |= NGHTTP2_FLAG_END_STREAM; } - if (pri_spec) { - flags |= NGHTTP2_FLAG_PRIORITY; - } - return flags; } static int32_t submit_request_shared(nghttp2_session *session, - const nghttp2_priority_spec *pri_spec, const nghttp2_nv *nva, size_t nvlen, const nghttp2_data_provider_wrap *dpw, void *stream_user_data) { uint8_t flags; - int rv; if (session->server) { return NGHTTP2_ERR_PROTO; } - if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) && - session->remote_settings.no_rfc7540_priorities != 1) { - rv = detect_self_dependency(session, -1, pri_spec); - if (rv != 0) { - return rv; - } - } else { - pri_spec = NULL; - } - - flags = set_request_flags(pri_spec, dpw); + flags = set_request_flags(dpw); - return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen, - dpw, stream_user_data); + return submit_headers_shared_nva(session, flags, -1, nva, nvlen, dpw, + stream_user_data); } int32_t nghttp2_submit_request(nghttp2_session *session, @@ -786,8 +677,9 @@ int32_t nghttp2_submit_request(nghttp2_session *session, const nghttp2_data_provider *data_prd, void *stream_user_data) { nghttp2_data_provider_wrap dpw; + (void)pri_spec; - return submit_request_shared(session, pri_spec, nva, nvlen, + return submit_request_shared(session, nva, nvlen, nghttp2_data_provider_wrap_v1(&dpw, data_prd), stream_user_data); } @@ -798,8 +690,9 @@ int32_t nghttp2_submit_request2(nghttp2_session *session, const nghttp2_data_provider2 *data_prd, void *stream_user_data) { nghttp2_data_provider_wrap dpw; + (void)pri_spec; - return submit_request_shared(session, pri_spec, nva, nvlen, + return submit_request_shared(session, nva, nvlen, nghttp2_data_provider_wrap_v2(&dpw, data_prd), stream_user_data); } @@ -826,8 +719,8 @@ static int submit_response_shared(nghttp2_session *session, int32_t stream_id, } flags = set_response_flags(dpw); - return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen, - dpw, NULL); + return submit_headers_shared_nva(session, flags, stream_id, nva, nvlen, dpw, + NULL); } int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, diff --git a/deps/nghttp2/lib/sfparse.c b/deps/nghttp2/lib/sfparse.c index b5e94cc281533b..cee089d3944d18 100644 --- a/deps/nghttp2/lib/sfparse.c +++ b/deps/nghttp2/lib/sfparse.c @@ -30,38 +30,46 @@ #include #include -#define SF_STATE_DICT 0x08u -#define SF_STATE_LIST 0x10u -#define SF_STATE_ITEM 0x18u +#ifdef __AVX2__ +# include +#endif /* __AVX2__ */ -#define SF_STATE_INNER_LIST 0x04u +#define SFPARSE_STATE_DICT 0x08u +#define SFPARSE_STATE_LIST 0x10u +#define SFPARSE_STATE_ITEM 0x18u -#define SF_STATE_BEFORE 0x00u -#define SF_STATE_BEFORE_PARAMS 0x01u -#define SF_STATE_PARAMS 0x02u -#define SF_STATE_AFTER 0x03u +#define SFPARSE_STATE_INNER_LIST 0x04u -#define SF_STATE_OP_MASK 0x03u +#define SFPARSE_STATE_BEFORE 0x00u +#define SFPARSE_STATE_BEFORE_PARAMS 0x01u +#define SFPARSE_STATE_PARAMS 0x02u +#define SFPARSE_STATE_AFTER 0x03u -#define SF_SET_STATE_AFTER(NAME) (SF_STATE_##NAME | SF_STATE_AFTER) -#define SF_SET_STATE_BEFORE_PARAMS(NAME) \ - (SF_STATE_##NAME | SF_STATE_BEFORE_PARAMS) -#define SF_SET_STATE_INNER_LIST_BEFORE(NAME) \ - (SF_STATE_##NAME | SF_STATE_INNER_LIST | SF_STATE_BEFORE) +#define SFPARSE_STATE_OP_MASK 0x03u -#define SF_STATE_DICT_AFTER SF_SET_STATE_AFTER(DICT) -#define SF_STATE_DICT_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(DICT) -#define SF_STATE_DICT_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(DICT) +#define SFPARSE_SET_STATE_AFTER(NAME) \ + (SFPARSE_STATE_##NAME | SFPARSE_STATE_AFTER) +#define SFPARSE_SET_STATE_BEFORE_PARAMS(NAME) \ + (SFPARSE_STATE_##NAME | SFPARSE_STATE_BEFORE_PARAMS) +#define SFPARSE_SET_STATE_INNER_LIST_BEFORE(NAME) \ + (SFPARSE_STATE_##NAME | SFPARSE_STATE_INNER_LIST | SFPARSE_STATE_BEFORE) -#define SF_STATE_LIST_AFTER SF_SET_STATE_AFTER(LIST) -#define SF_STATE_LIST_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(LIST) -#define SF_STATE_LIST_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(LIST) +#define SFPARSE_STATE_DICT_AFTER SFPARSE_SET_STATE_AFTER(DICT) +#define SFPARSE_STATE_DICT_BEFORE_PARAMS SFPARSE_SET_STATE_BEFORE_PARAMS(DICT) +#define SFPARSE_STATE_DICT_INNER_LIST_BEFORE \ + SFPARSE_SET_STATE_INNER_LIST_BEFORE(DICT) -#define SF_STATE_ITEM_AFTER SF_SET_STATE_AFTER(ITEM) -#define SF_STATE_ITEM_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(ITEM) -#define SF_STATE_ITEM_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(ITEM) +#define SFPARSE_STATE_LIST_AFTER SFPARSE_SET_STATE_AFTER(LIST) +#define SFPARSE_STATE_LIST_BEFORE_PARAMS SFPARSE_SET_STATE_BEFORE_PARAMS(LIST) +#define SFPARSE_STATE_LIST_INNER_LIST_BEFORE \ + SFPARSE_SET_STATE_INNER_LIST_BEFORE(LIST) -#define SF_STATE_INITIAL 0x00u +#define SFPARSE_STATE_ITEM_AFTER SFPARSE_SET_STATE_AFTER(ITEM) +#define SFPARSE_STATE_ITEM_BEFORE_PARAMS SFPARSE_SET_STATE_BEFORE_PARAMS(ITEM) +#define SFPARSE_STATE_ITEM_INNER_LIST_BEFORE \ + SFPARSE_SET_STATE_INNER_LIST_BEFORE(ITEM) + +#define SFPARSE_STATE_INITIAL 0x00u #define DIGIT_CASES \ case '0': \ @@ -135,6 +143,70 @@ UCALPHA_CASES: \ LCALPHA_CASES +#define TOKEN_CASES \ + case '!': \ + case '#': \ + case '$': \ + case '%': \ + case '&': \ + case '\'': \ + case '*': \ + case '+': \ + case '-': \ + case '.': \ + case '/': \ + DIGIT_CASES: \ + case ':': \ + UCALPHA_CASES: \ + case '^': \ + case '_': \ + case '`': \ + LCALPHA_CASES: \ + case '|': \ + case '~' + +#define LCHEXALPHA_CASES \ + case 'a': \ + case 'b': \ + case 'c': \ + case 'd': \ + case 'e': \ + case 'f' + +#define X00_1F_CASES \ + case 0x00: \ + case 0x01: \ + case 0x02: \ + case 0x03: \ + case 0x04: \ + case 0x05: \ + case 0x06: \ + case 0x07: \ + case 0x08: \ + case 0x09: \ + case 0x0a: \ + case 0x0b: \ + case 0x0c: \ + case 0x0d: \ + case 0x0e: \ + case 0x0f: \ + case 0x10: \ + case 0x11: \ + case 0x12: \ + case 0x13: \ + case 0x14: \ + case 0x15: \ + case 0x16: \ + case 0x17: \ + case 0x18: \ + case 0x19: \ + case 0x1a: \ + case 0x1b: \ + case 0x1c: \ + case 0x1d: \ + case 0x1e: \ + case 0x1f + #define X20_21_CASES \ case ' ': \ case '!' @@ -175,6 +247,137 @@ case '}': \ case '~' +#define X7F_FF_CASES \ + case 0x7f: \ + case 0x80: \ + case 0x81: \ + case 0x82: \ + case 0x83: \ + case 0x84: \ + case 0x85: \ + case 0x86: \ + case 0x87: \ + case 0x88: \ + case 0x89: \ + case 0x8a: \ + case 0x8b: \ + case 0x8c: \ + case 0x8d: \ + case 0x8e: \ + case 0x8f: \ + case 0x90: \ + case 0x91: \ + case 0x92: \ + case 0x93: \ + case 0x94: \ + case 0x95: \ + case 0x96: \ + case 0x97: \ + case 0x98: \ + case 0x99: \ + case 0x9a: \ + case 0x9b: \ + case 0x9c: \ + case 0x9d: \ + case 0x9e: \ + case 0x9f: \ + case 0xa0: \ + case 0xa1: \ + case 0xa2: \ + case 0xa3: \ + case 0xa4: \ + case 0xa5: \ + case 0xa6: \ + case 0xa7: \ + case 0xa8: \ + case 0xa9: \ + case 0xaa: \ + case 0xab: \ + case 0xac: \ + case 0xad: \ + case 0xae: \ + case 0xaf: \ + case 0xb0: \ + case 0xb1: \ + case 0xb2: \ + case 0xb3: \ + case 0xb4: \ + case 0xb5: \ + case 0xb6: \ + case 0xb7: \ + case 0xb8: \ + case 0xb9: \ + case 0xba: \ + case 0xbb: \ + case 0xbc: \ + case 0xbd: \ + case 0xbe: \ + case 0xbf: \ + case 0xc0: \ + case 0xc1: \ + case 0xc2: \ + case 0xc3: \ + case 0xc4: \ + case 0xc5: \ + case 0xc6: \ + case 0xc7: \ + case 0xc8: \ + case 0xc9: \ + case 0xca: \ + case 0xcb: \ + case 0xcc: \ + case 0xcd: \ + case 0xce: \ + case 0xcf: \ + case 0xd0: \ + case 0xd1: \ + case 0xd2: \ + case 0xd3: \ + case 0xd4: \ + case 0xd5: \ + case 0xd6: \ + case 0xd7: \ + case 0xd8: \ + case 0xd9: \ + case 0xda: \ + case 0xdb: \ + case 0xdc: \ + case 0xdd: \ + case 0xde: \ + case 0xdf: \ + case 0xe0: \ + case 0xe1: \ + case 0xe2: \ + case 0xe3: \ + case 0xe4: \ + case 0xe5: \ + case 0xe6: \ + case 0xe7: \ + case 0xe8: \ + case 0xe9: \ + case 0xea: \ + case 0xeb: \ + case 0xec: \ + case 0xed: \ + case 0xee: \ + case 0xef: \ + case 0xf0: \ + case 0xf1: \ + case 0xf2: \ + case 0xf3: \ + case 0xf4: \ + case 0xf5: \ + case 0xf6: \ + case 0xf7: \ + case 0xf8: \ + case 0xf9: \ + case 0xfa: \ + case 0xfb: \ + case 0xfc: \ + case 0xfd: \ + case 0xfe: \ + case 0xff + static int is_ws(uint8_t c) { switch (c) { case ' ': @@ -185,40 +388,108 @@ static int is_ws(uint8_t c) { } } -static int parser_eof(sf_parser *sfp) { return sfp->pos == sfp->end; } +#ifdef __AVX2__ +# ifdef _MSC_VER +# include + +static int ctz(unsigned int v) { + unsigned long n; + + /* Assume that v is not 0. */ + _BitScanForward(&n, v); + + return (int)n; +} +# else /* !_MSC_VER */ +# define ctz __builtin_ctz +# endif /* !_MSC_VER */ +#endif /* __AVX2__ */ + +static int parser_eof(sfparse_parser *sfp) { return sfp->pos == sfp->end; } -static void parser_discard_ows(sf_parser *sfp) { +static void parser_discard_ows(sfparse_parser *sfp) { for (; !parser_eof(sfp) && is_ws(*sfp->pos); ++sfp->pos) ; } -static void parser_discard_sp(sf_parser *sfp) { +static void parser_discard_sp(sfparse_parser *sfp) { for (; !parser_eof(sfp) && *sfp->pos == ' '; ++sfp->pos) ; } -static void parser_set_op_state(sf_parser *sfp, uint32_t op) { - sfp->state &= ~SF_STATE_OP_MASK; +static void parser_set_op_state(sfparse_parser *sfp, uint32_t op) { + sfp->state &= ~SFPARSE_STATE_OP_MASK; sfp->state |= op; } -static void parser_unset_inner_list_state(sf_parser *sfp) { - sfp->state &= ~SF_STATE_INNER_LIST; +static void parser_unset_inner_list_state(sfparse_parser *sfp) { + sfp->state &= ~SFPARSE_STATE_INNER_LIST; } -static int parser_key(sf_parser *sfp, sf_vec *dest) { +#ifdef __AVX2__ +static const uint8_t *find_char_key(const uint8_t *first, const uint8_t *last) { + const __m256i us = _mm256_set1_epi8('_'); + const __m256i ds = _mm256_set1_epi8('-'); + const __m256i dot = _mm256_set1_epi8('.'); + const __m256i ast = _mm256_set1_epi8('*'); + const __m256i r0l = _mm256_set1_epi8('0' - 1); + const __m256i r0r = _mm256_set1_epi8('9' + 1); + const __m256i r1l = _mm256_set1_epi8('a' - 1); + const __m256i r1r = _mm256_set1_epi8('z' + 1); + __m256i s, x; + uint32_t m; + + for (; first != last; first += 32) { + s = _mm256_loadu_si256((void *)first); + + x = _mm256_cmpeq_epi8(s, us); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, ds), x); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, dot), x); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, ast), x); + x = _mm256_or_si256( + _mm256_and_si256(_mm256_cmpgt_epi8(s, r0l), _mm256_cmpgt_epi8(r0r, s)), + x); + x = _mm256_or_si256( + _mm256_and_si256(_mm256_cmpgt_epi8(s, r1l), _mm256_cmpgt_epi8(r1r, s)), + x); + + m = ~(uint32_t)_mm256_movemask_epi8(x); + if (m) { + return first + ctz(m); + } + } + + return last; +} +#endif /* __AVX2__ */ + +static int parser_key(sfparse_parser *sfp, sfparse_vec *dest) { const uint8_t *base; +#ifdef __AVX2__ + const uint8_t *last; +#endif /* __AVX2__ */ switch (*sfp->pos) { case '*': LCALPHA_CASES: break; default: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } base = sfp->pos++; +#ifdef __AVX2__ + if (sfp->end - sfp->pos >= 32) { + last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); + + sfp->pos = find_char_key(sfp->pos, last); + if (sfp->pos != last) { + goto fin; + } + } +#endif /* __AVX2__ */ + for (; !parser_eof(sfp); ++sfp->pos) { switch (*sfp->pos) { case '_': @@ -233,6 +504,9 @@ static int parser_key(sf_parser *sfp, sf_vec *dest) { break; } +#ifdef __AVX2__ +fin: +#endif /* __AVX2__ */ if (dest) { dest->base = (uint8_t *)base; dest->len = (size_t)(sfp->pos - dest->base); @@ -241,7 +515,7 @@ static int parser_key(sf_parser *sfp, sf_vec *dest) { return 0; } -static int parser_number(sf_parser *sfp, sf_value *dest) { +static int parser_number(sfparse_parser *sfp, sfparse_value *dest) { int sign = 1; int64_t value = 0; size_t len = 0; @@ -250,7 +524,7 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { if (*sfp->pos == '-') { ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } sign = -1; @@ -262,7 +536,7 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { switch (*sfp->pos) { DIGIT_CASES: if (++len > 15) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } value *= 10; @@ -275,13 +549,13 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { } if (len == 0) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } if (parser_eof(sfp) || *sfp->pos != '.') { if (dest) { - dest->type = SF_TYPE_INTEGER; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_INTEGER; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->integer = value * sign; } @@ -291,7 +565,7 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { /* decimal */ if (len > 12) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } fpos = len; @@ -302,7 +576,7 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { switch (*sfp->pos) { DIGIT_CASES: if (++len > 15) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } value *= 10; @@ -315,12 +589,12 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { } if (fpos == len || len - fpos > 3) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } if (dest) { - dest->type = SF_TYPE_DECIMAL; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_DECIMAL; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->decimal.numer = value * sign; switch (len - fpos) { @@ -342,9 +616,9 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { return 0; } -static int parser_date(sf_parser *sfp, sf_value *dest) { +static int parser_date(sfparse_parser *sfp, sfparse_value *dest) { int rv; - sf_value val; + sfparse_value val; /* The first byte has already been validated by the caller. */ assert('@' == *sfp->pos); @@ -352,7 +626,7 @@ static int parser_date(sf_parser *sfp, sf_value *dest) { ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } rv = parser_number(sfp, &val); @@ -360,27 +634,93 @@ static int parser_date(sf_parser *sfp, sf_value *dest) { return rv; } - if (val.type != SF_TYPE_INTEGER) { - return SF_ERR_PARSE_ERROR; + if (val.type != SFPARSE_TYPE_INTEGER) { + return SFPARSE_ERR_PARSE; } if (dest) { *dest = val; - dest->type = SF_TYPE_DATE; + dest->type = SFPARSE_TYPE_DATE; } return 0; } -static int parser_string(sf_parser *sfp, sf_value *dest) { +#ifdef __AVX2__ +static const uint8_t *find_char_string(const uint8_t *first, + const uint8_t *last) { + const __m256i bs = _mm256_set1_epi8('\\'); + const __m256i dq = _mm256_set1_epi8('"'); + const __m256i del = _mm256_set1_epi8(0x7f); + const __m256i sp = _mm256_set1_epi8(' '); + __m256i s, x; + uint32_t m; + + for (; first != last; first += 32) { + s = _mm256_loadu_si256((void *)first); + + x = _mm256_cmpgt_epi8(sp, s); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, bs), x); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, dq), x); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, del), x); + + m = (uint32_t)_mm256_movemask_epi8(x); + if (m) { + return first + ctz(m); + } + } + + return last; +} +#endif /* __AVX2__ */ + +static int parser_string(sfparse_parser *sfp, sfparse_value *dest) { const uint8_t *base; - uint32_t flags = SF_VALUE_FLAG_NONE; +#ifdef __AVX2__ + const uint8_t *last; +#endif /* __AVX2__ */ + uint32_t flags = SFPARSE_VALUE_FLAG_NONE; /* The first byte has already been validated by the caller. */ assert('"' == *sfp->pos); base = ++sfp->pos; +#ifdef __AVX2__ + for (; sfp->end - sfp->pos >= 32; ++sfp->pos) { + last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); + + sfp->pos = find_char_string(sfp->pos, last); + if (sfp->pos == last) { + break; + } + + switch (*sfp->pos) { + case '\\': + ++sfp->pos; + if (parser_eof(sfp)) { + return SFPARSE_ERR_PARSE; + } + + switch (*sfp->pos) { + case '"': + case '\\': + flags = SFPARSE_VALUE_FLAG_ESCAPED_STRING; + + break; + default: + return SFPARSE_ERR_PARSE; + } + + break; + case '"': + goto fin; + default: + return SFPARSE_ERR_PARSE; + } + } +#endif /* __AVX2__ */ + for (; !parser_eof(sfp); ++sfp->pos) { switch (*sfp->pos) { X20_21_CASES: @@ -390,75 +730,131 @@ static int parser_string(sf_parser *sfp, sf_value *dest) { case '\\': ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } switch (*sfp->pos) { case '"': case '\\': - flags = SF_VALUE_FLAG_ESCAPED_STRING; + flags = SFPARSE_VALUE_FLAG_ESCAPED_STRING; break; default: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } break; case '"': - if (dest) { - dest->type = SF_TYPE_STRING; - dest->flags = flags; - dest->vec.len = (size_t)(sfp->pos - base); - dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; - } + goto fin; + default: + return SFPARSE_ERR_PARSE; + } + } - ++sfp->pos; + return SFPARSE_ERR_PARSE; - return 0; - default: - return SF_ERR_PARSE_ERROR; +fin: + if (dest) { + dest->type = SFPARSE_TYPE_STRING; + dest->flags = flags; + dest->vec.len = (size_t)(sfp->pos - base); + dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; + } + + ++sfp->pos; + + return 0; +} + +#ifdef __AVX2__ +static const uint8_t *find_char_token(const uint8_t *first, + const uint8_t *last) { + /* r0: !..:, excluding "(), + r1: A..Z + r2: ^..~, excluding {} */ + const __m256i r0l = _mm256_set1_epi8('!' - 1); + const __m256i r0r = _mm256_set1_epi8(':' + 1); + const __m256i dq = _mm256_set1_epi8('"'); + const __m256i prl = _mm256_set1_epi8('('); + const __m256i prr = _mm256_set1_epi8(')'); + const __m256i comma = _mm256_set1_epi8(','); + const __m256i r1l = _mm256_set1_epi8('A' - 1); + const __m256i r1r = _mm256_set1_epi8('Z' + 1); + const __m256i r2l = _mm256_set1_epi8('^' - 1); + const __m256i r2r = _mm256_set1_epi8('~' + 1); + const __m256i cbl = _mm256_set1_epi8('{'); + const __m256i cbr = _mm256_set1_epi8('}'); + __m256i s, x; + uint32_t m; + + for (; first != last; first += 32) { + s = _mm256_loadu_si256((void *)first); + + x = _mm256_andnot_si256( + _mm256_cmpeq_epi8(s, comma), + _mm256_andnot_si256( + _mm256_cmpeq_epi8(s, prr), + _mm256_andnot_si256( + _mm256_cmpeq_epi8(s, prl), + _mm256_andnot_si256(_mm256_cmpeq_epi8(s, dq), + _mm256_and_si256(_mm256_cmpgt_epi8(s, r0l), + _mm256_cmpgt_epi8(r0r, s)))))); + x = _mm256_or_si256( + _mm256_and_si256(_mm256_cmpgt_epi8(s, r1l), _mm256_cmpgt_epi8(r1r, s)), + x); + x = _mm256_or_si256( + _mm256_andnot_si256( + _mm256_cmpeq_epi8(s, cbr), + _mm256_andnot_si256(_mm256_cmpeq_epi8(s, cbl), + _mm256_and_si256(_mm256_cmpgt_epi8(s, r2l), + _mm256_cmpgt_epi8(r2r, s)))), + x); + + m = ~(uint32_t)_mm256_movemask_epi8(x); + if (m) { + return first + ctz(m); } } - return SF_ERR_PARSE_ERROR; + return last; } +#endif /* __AVX2__ */ -static int parser_token(sf_parser *sfp, sf_value *dest) { +static int parser_token(sfparse_parser *sfp, sfparse_value *dest) { const uint8_t *base; +#ifdef __AVX2__ + const uint8_t *last; +#endif /* __AVX2__ */ /* The first byte has already been validated by the caller. */ base = sfp->pos++; +#ifdef __AVX2__ + if (sfp->end - sfp->pos >= 32) { + last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); + + sfp->pos = find_char_token(sfp->pos, last); + if (sfp->pos != last) { + goto fin; + } + } +#endif /* __AVX2__ */ + for (; !parser_eof(sfp); ++sfp->pos) { switch (*sfp->pos) { - case '!': - case '#': - case '$': - case '%': - case '&': - case '\'': - case '*': - case '+': - case '-': - case '.': - case '^': - case '_': - case '`': - case '|': - case '~': - case ':': - case '/': - DIGIT_CASES: - ALPHA_CASES: + TOKEN_CASES: continue; } break; } +#ifdef __AVX2__ +fin: +#endif /* __AVX2__ */ if (dest) { - dest->type = SF_TYPE_TOKEN; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_TOKEN; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->vec.base = (uint8_t *)base; dest->vec.len = (size_t)(sfp->pos - base); } @@ -466,14 +862,63 @@ static int parser_token(sf_parser *sfp, sf_value *dest) { return 0; } -static int parser_byteseq(sf_parser *sfp, sf_value *dest) { +#ifdef __AVX2__ +static const uint8_t *find_char_byteseq(const uint8_t *first, + const uint8_t *last) { + const __m256i pls = _mm256_set1_epi8('+'); + const __m256i fs = _mm256_set1_epi8('/'); + const __m256i r0l = _mm256_set1_epi8('0' - 1); + const __m256i r0r = _mm256_set1_epi8('9' + 1); + const __m256i r1l = _mm256_set1_epi8('A' - 1); + const __m256i r1r = _mm256_set1_epi8('Z' + 1); + const __m256i r2l = _mm256_set1_epi8('a' - 1); + const __m256i r2r = _mm256_set1_epi8('z' + 1); + __m256i s, x; + uint32_t m; + + for (; first != last; first += 32) { + s = _mm256_loadu_si256((void *)first); + + x = _mm256_cmpeq_epi8(s, pls); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, fs), x); + x = _mm256_or_si256( + _mm256_and_si256(_mm256_cmpgt_epi8(s, r0l), _mm256_cmpgt_epi8(r0r, s)), + x); + x = _mm256_or_si256( + _mm256_and_si256(_mm256_cmpgt_epi8(s, r1l), _mm256_cmpgt_epi8(r1r, s)), + x); + x = _mm256_or_si256( + _mm256_and_si256(_mm256_cmpgt_epi8(s, r2l), _mm256_cmpgt_epi8(r2r, s)), + x); + + m = ~(uint32_t)_mm256_movemask_epi8(x); + if (m) { + return first + ctz(m); + } + } + + return last; +} +#endif /* __AVX2__ */ + +static int parser_byteseq(sfparse_parser *sfp, sfparse_value *dest) { const uint8_t *base; +#ifdef __AVX2__ + const uint8_t *last; +#endif /* __AVX2__ */ /* The first byte has already been validated by the caller. */ assert(':' == *sfp->pos); base = ++sfp->pos; +#ifdef __AVX2__ + if (sfp->end - sfp->pos >= 32) { + last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); + sfp->pos = find_char_byteseq(sfp->pos, last); + } +#endif /* __AVX2__ */ + for (; !parser_eof(sfp); ++sfp->pos) { switch (*sfp->pos) { case '+': @@ -485,75 +930,47 @@ static int parser_byteseq(sf_parser *sfp, sf_value *dest) { switch ((sfp->pos - base) & 0x3) { case 0: case 1: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; case 2: - switch (*(sfp->pos - 1)) { - case 'A': - case 'Q': - case 'g': - case 'w': - break; - default: - return SF_ERR_PARSE_ERROR; - } - ++sfp->pos; - if (parser_eof(sfp) || *sfp->pos != '=') { - return SF_ERR_PARSE_ERROR; + if (parser_eof(sfp)) { + return SFPARSE_ERR_PARSE; + } + + if (*sfp->pos == '=') { + ++sfp->pos; } break; case 3: - switch (*(sfp->pos - 1)) { - case 'A': - case 'E': - case 'I': - case 'M': - case 'Q': - case 'U': - case 'Y': - case 'c': - case 'g': - case 'k': - case 'o': - case 's': - case 'w': - case '0': - case '4': - case '8': - break; - default: - return SF_ERR_PARSE_ERROR; - } + ++sfp->pos; break; } - ++sfp->pos; - if (parser_eof(sfp) || *sfp->pos != ':') { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } goto fin; case ':': - if ((sfp->pos - base) & 0x3) { - return SF_ERR_PARSE_ERROR; + if (((sfp->pos - base) & 0x3) == 1) { + return SFPARSE_ERR_PARSE; } goto fin; default: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } } - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; fin: if (dest) { - dest->type = SF_TYPE_BYTESEQ; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_BYTESEQ; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->vec.len = (size_t)(sfp->pos - base); dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; } @@ -563,7 +980,7 @@ static int parser_byteseq(sf_parser *sfp, sf_value *dest) { return 0; } -static int parser_boolean(sf_parser *sfp, sf_value *dest) { +static int parser_boolean(sfparse_parser *sfp, sfparse_value *dest) { int b; /* The first byte has already been validated by the caller. */ @@ -572,7 +989,7 @@ static int parser_boolean(sf_parser *sfp, sf_value *dest) { ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } switch (*sfp->pos) { @@ -585,21 +1002,184 @@ static int parser_boolean(sf_parser *sfp, sf_value *dest) { break; default: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } ++sfp->pos; if (dest) { - dest->type = SF_TYPE_BOOLEAN; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_BOOLEAN; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->boolean = b; } return 0; } -static int parser_bare_item(sf_parser *sfp, sf_value *dest) { +static int pctdecode(uint8_t *pc, const uint8_t **ppos) { + uint8_t c, b = **ppos; + + switch (b) { + DIGIT_CASES: + c = (uint8_t)((b - '0') << 4); + + break; + LCHEXALPHA_CASES: + c = (uint8_t)((b - 'a' + 10) << 4); + + break; + default: + return -1; + } + + b = *++*ppos; + + switch (b) { + DIGIT_CASES: + c |= (uint8_t)(b - '0'); + + break; + LCHEXALPHA_CASES: + c |= (uint8_t)(b - 'a' + 10); + + break; + default: + return -1; + } + + *pc = c; + ++*ppos; + + return 0; +} + +/* Start of utf8 dfa */ +/* Copyright (c) 2008-2010 Bjoern Hoehrmann + * See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. + * + * Copyright (c) 2008-2009 Bjoern Hoehrmann + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#define UTF8_ACCEPT 0 +#define UTF8_REJECT 12 + +/* clang-format off */ +static const uint8_t utf8d[] = { + /* + * The first part of the table maps bytes to character classes that + * to reduce the size of the transition table and create bitmasks. + */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, + + /* + * The second part is a transition table that maps a combination + * of a state of the automaton and a character class to a state. + */ + 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, + 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, + 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, + 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, + 12,36,12,12,12,12,12,12,12,12,12,12, +}; +/* clang-format on */ + +static void utf8_decode(uint32_t *state, uint8_t byte) { + *state = utf8d[256 + *state + utf8d[byte]]; +} + +/* End of utf8 dfa */ + +static int parser_dispstring(sfparse_parser *sfp, sfparse_value *dest) { + const uint8_t *base; + uint8_t c; + uint32_t utf8state = UTF8_ACCEPT; + + assert('%' == *sfp->pos); + + ++sfp->pos; + + if (parser_eof(sfp) || *sfp->pos != '"') { + return SFPARSE_ERR_PARSE; + } + + base = ++sfp->pos; + + for (; !parser_eof(sfp);) { + switch (*sfp->pos) { + X00_1F_CASES: + X7F_FF_CASES: + return SFPARSE_ERR_PARSE; + case '%': + ++sfp->pos; + + if (sfp->pos + 2 > sfp->end) { + return SFPARSE_ERR_PARSE; + } + + if (pctdecode(&c, &sfp->pos) != 0) { + return SFPARSE_ERR_PARSE; + } + + utf8_decode(&utf8state, c); + if (utf8state == UTF8_REJECT) { + return SFPARSE_ERR_PARSE; + } + + break; + case '"': + if (utf8state != UTF8_ACCEPT) { + return SFPARSE_ERR_PARSE; + } + + if (dest) { + dest->type = SFPARSE_TYPE_DISPSTRING; + dest->flags = SFPARSE_VALUE_FLAG_NONE; + dest->vec.len = (size_t)(sfp->pos - base); + dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; + } + + ++sfp->pos; + + return 0; + default: + if (utf8state != UTF8_ACCEPT) { + return SFPARSE_ERR_PARSE; + } + + ++sfp->pos; + } + } + + return SFPARSE_ERR_PARSE; +} + +static int parser_bare_item(sfparse_parser *sfp, sfparse_value *dest) { switch (*sfp->pos) { case '"': return parser_string(sfp, dest); @@ -615,29 +1195,32 @@ static int parser_bare_item(sf_parser *sfp, sf_value *dest) { case '*': ALPHA_CASES: return parser_token(sfp, dest); + case '%': + return parser_dispstring(sfp, dest); default: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } } -static int parser_skip_inner_list(sf_parser *sfp); +static int parser_skip_inner_list(sfparse_parser *sfp); -int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { +int sfparse_parser_param(sfparse_parser *sfp, sfparse_vec *dest_key, + sfparse_value *dest_value) { int rv; - switch (sfp->state & SF_STATE_OP_MASK) { - case SF_STATE_BEFORE: + switch (sfp->state & SFPARSE_STATE_OP_MASK) { + case SFPARSE_STATE_BEFORE: rv = parser_skip_inner_list(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_BEFORE_PARAMS: - parser_set_op_state(sfp, SF_STATE_PARAMS); + case SFPARSE_STATE_BEFORE_PARAMS: + parser_set_op_state(sfp, SFPARSE_STATE_PARAMS); break; - case SF_STATE_PARAMS: + case SFPARSE_STATE_PARAMS: break; default: assert(0); @@ -645,16 +1228,16 @@ int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { } if (parser_eof(sfp) || *sfp->pos != ';') { - parser_set_op_state(sfp, SF_STATE_AFTER); + parser_set_op_state(sfp, SFPARSE_STATE_AFTER); - return SF_ERR_EOF; + return SFPARSE_ERR_EOF; } ++sfp->pos; parser_discard_sp(sfp); if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } rv = parser_key(sfp, dest_key); @@ -664,8 +1247,8 @@ int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { if (parser_eof(sfp) || *sfp->pos != '=') { if (dest_value) { - dest_value->type = SF_TYPE_BOOLEAN; - dest_value->flags = SF_VALUE_FLAG_NONE; + dest_value->type = SFPARSE_TYPE_BOOLEAN; + dest_value->flags = SFPARSE_VALUE_FLAG_NONE; dest_value->boolean = 1; } @@ -675,23 +1258,23 @@ int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } return parser_bare_item(sfp, dest_value); } -static int parser_skip_params(sf_parser *sfp) { +static int parser_skip_params(sfparse_parser *sfp) { int rv; for (;;) { - rv = sf_parser_param(sfp, NULL, NULL); + rv = sfparse_parser_param(sfp, NULL, NULL); switch (rv) { case 0: break; - case SF_ERR_EOF: + case SFPARSE_ERR_EOF: return 0; - case SF_ERR_PARSE_ERROR: + case SFPARSE_ERR_PARSE: return rv; default: assert(0); @@ -700,45 +1283,45 @@ static int parser_skip_params(sf_parser *sfp) { } } -int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { +int sfparse_parser_inner_list(sfparse_parser *sfp, sfparse_value *dest) { int rv; - switch (sfp->state & SF_STATE_OP_MASK) { - case SF_STATE_BEFORE: + switch (sfp->state & SFPARSE_STATE_OP_MASK) { + case SFPARSE_STATE_BEFORE: parser_discard_sp(sfp); if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } break; - case SF_STATE_BEFORE_PARAMS: + case SFPARSE_STATE_BEFORE_PARAMS: rv = parser_skip_params(sfp); if (rv != 0) { return rv; } - /* Technically, we are entering SF_STATE_AFTER, but we will set + /* Technically, we are entering SFPARSE_STATE_AFTER, but we will set another state without reading the state. */ - /* parser_set_op_state(sfp, SF_STATE_AFTER); */ + /* parser_set_op_state(sfp, SFPARSE_STATE_AFTER); */ /* fall through */ - case SF_STATE_AFTER: + case SFPARSE_STATE_AFTER: if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } switch (*sfp->pos) { case ' ': parser_discard_sp(sfp); if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } break; case ')': break; default: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } break; @@ -751,9 +1334,9 @@ int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { ++sfp->pos; parser_unset_inner_list_state(sfp); - parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); + parser_set_op_state(sfp, SFPARSE_STATE_BEFORE_PARAMS); - return SF_ERR_EOF; + return SFPARSE_ERR_EOF; } rv = parser_bare_item(sfp, dest); @@ -761,22 +1344,22 @@ int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { return rv; } - parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); + parser_set_op_state(sfp, SFPARSE_STATE_BEFORE_PARAMS); return 0; } -static int parser_skip_inner_list(sf_parser *sfp) { +static int parser_skip_inner_list(sfparse_parser *sfp) { int rv; for (;;) { - rv = sf_parser_inner_list(sfp, NULL); + rv = sfparse_parser_inner_list(sfp, NULL); switch (rv) { case 0: break; - case SF_ERR_EOF: + case SFPARSE_ERR_EOF: return 0; - case SF_ERR_PARSE_ERROR: + case SFPARSE_ERR_PARSE: return rv; default: assert(0); @@ -785,39 +1368,39 @@ static int parser_skip_inner_list(sf_parser *sfp) { } } -static int parser_next_key_or_item(sf_parser *sfp) { +static int parser_next_key_or_item(sfparse_parser *sfp) { parser_discard_ows(sfp); if (parser_eof(sfp)) { - return SF_ERR_EOF; + return SFPARSE_ERR_EOF; } if (*sfp->pos != ',') { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } ++sfp->pos; parser_discard_ows(sfp); if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } return 0; } -static int parser_dict_value(sf_parser *sfp, sf_value *dest) { +static int parser_dict_value(sfparse_parser *sfp, sfparse_value *dest) { int rv; if (parser_eof(sfp) || *(sfp->pos) != '=') { /* Boolean true */ if (dest) { - dest->type = SF_TYPE_BOOLEAN; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_BOOLEAN; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->boolean = 1; } - sfp->state = SF_STATE_DICT_BEFORE_PARAMS; + sfp->state = SFPARSE_STATE_DICT_BEFORE_PARAMS; return 0; } @@ -825,18 +1408,18 @@ static int parser_dict_value(sf_parser *sfp, sf_value *dest) { ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } if (*sfp->pos == '(') { if (dest) { - dest->type = SF_TYPE_INNER_LIST; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_INNER_LIST; + dest->flags = SFPARSE_VALUE_FLAG_NONE; } ++sfp->pos; - sfp->state = SF_STATE_DICT_INNER_LIST_BEFORE; + sfp->state = SFPARSE_STATE_DICT_INNER_LIST_BEFORE; return 0; } @@ -846,41 +1429,42 @@ static int parser_dict_value(sf_parser *sfp, sf_value *dest) { return rv; } - sfp->state = SF_STATE_DICT_BEFORE_PARAMS; + sfp->state = SFPARSE_STATE_DICT_BEFORE_PARAMS; return 0; } -int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { +int sfparse_parser_dict(sfparse_parser *sfp, sfparse_vec *dest_key, + sfparse_value *dest_value) { int rv; switch (sfp->state) { - case SF_STATE_DICT_INNER_LIST_BEFORE: + case SFPARSE_STATE_DICT_INNER_LIST_BEFORE: rv = parser_skip_inner_list(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_DICT_BEFORE_PARAMS: + case SFPARSE_STATE_DICT_BEFORE_PARAMS: rv = parser_skip_params(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_DICT_AFTER: + case SFPARSE_STATE_DICT_AFTER: rv = parser_next_key_or_item(sfp); if (rv != 0) { return rv; } break; - case SF_STATE_INITIAL: + case SFPARSE_STATE_INITIAL: parser_discard_sp(sfp); if (parser_eof(sfp)) { - return SF_ERR_EOF; + return SFPARSE_ERR_EOF; } break; @@ -897,36 +1481,36 @@ int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { return parser_dict_value(sfp, dest_value); } -int sf_parser_list(sf_parser *sfp, sf_value *dest) { +int sfparse_parser_list(sfparse_parser *sfp, sfparse_value *dest) { int rv; switch (sfp->state) { - case SF_STATE_LIST_INNER_LIST_BEFORE: + case SFPARSE_STATE_LIST_INNER_LIST_BEFORE: rv = parser_skip_inner_list(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_LIST_BEFORE_PARAMS: + case SFPARSE_STATE_LIST_BEFORE_PARAMS: rv = parser_skip_params(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_LIST_AFTER: + case SFPARSE_STATE_LIST_AFTER: rv = parser_next_key_or_item(sfp); if (rv != 0) { return rv; } break; - case SF_STATE_INITIAL: + case SFPARSE_STATE_INITIAL: parser_discard_sp(sfp); if (parser_eof(sfp)) { - return SF_ERR_EOF; + return SFPARSE_ERR_EOF; } break; @@ -937,13 +1521,13 @@ int sf_parser_list(sf_parser *sfp, sf_value *dest) { if (*sfp->pos == '(') { if (dest) { - dest->type = SF_TYPE_INNER_LIST; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_INNER_LIST; + dest->flags = SFPARSE_VALUE_FLAG_NONE; } ++sfp->pos; - sfp->state = SF_STATE_LIST_INNER_LIST_BEFORE; + sfp->state = SFPARSE_STATE_LIST_INNER_LIST_BEFORE; return 0; } @@ -953,45 +1537,45 @@ int sf_parser_list(sf_parser *sfp, sf_value *dest) { return rv; } - sfp->state = SF_STATE_LIST_BEFORE_PARAMS; + sfp->state = SFPARSE_STATE_LIST_BEFORE_PARAMS; return 0; } -int sf_parser_item(sf_parser *sfp, sf_value *dest) { +int sfparse_parser_item(sfparse_parser *sfp, sfparse_value *dest) { int rv; switch (sfp->state) { - case SF_STATE_INITIAL: + case SFPARSE_STATE_INITIAL: parser_discard_sp(sfp); if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } break; - case SF_STATE_ITEM_INNER_LIST_BEFORE: + case SFPARSE_STATE_ITEM_INNER_LIST_BEFORE: rv = parser_skip_inner_list(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_ITEM_BEFORE_PARAMS: + case SFPARSE_STATE_ITEM_BEFORE_PARAMS: rv = parser_skip_params(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_ITEM_AFTER: + case SFPARSE_STATE_ITEM_AFTER: parser_discard_sp(sfp); if (!parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } - return SF_ERR_EOF; + return SFPARSE_ERR_EOF; default: assert(0); abort(); @@ -999,13 +1583,13 @@ int sf_parser_item(sf_parser *sfp, sf_value *dest) { if (*sfp->pos == '(') { if (dest) { - dest->type = SF_TYPE_INNER_LIST; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_INNER_LIST; + dest->flags = SFPARSE_VALUE_FLAG_NONE; } ++sfp->pos; - sfp->state = SF_STATE_ITEM_INNER_LIST_BEFORE; + sfp->state = SFPARSE_STATE_ITEM_INNER_LIST_BEFORE; return 0; } @@ -1015,12 +1599,13 @@ int sf_parser_item(sf_parser *sfp, sf_value *dest) { return rv; } - sfp->state = SF_STATE_ITEM_BEFORE_PARAMS; + sfp->state = SFPARSE_STATE_ITEM_BEFORE_PARAMS; return 0; } -void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen) { +void sfparse_parser_init(sfparse_parser *sfp, const uint8_t *data, + size_t datalen) { if (datalen == 0) { sfp->pos = sfp->end = NULL; } else { @@ -1028,16 +1613,16 @@ void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen) { sfp->end = data + datalen; } - sfp->state = SF_STATE_INITIAL; + sfp->state = SFPARSE_STATE_INITIAL; } -void sf_unescape(sf_vec *dest, const sf_vec *src) { +void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src) { const uint8_t *p, *q; uint8_t *o; size_t len, slen; if (src->len == 0) { - *dest = *src; + dest->len = 0; return; } @@ -1049,16 +1634,12 @@ void sf_unescape(sf_vec *dest, const sf_vec *src) { for (;;) { q = memchr(p, '\\', len); if (q == NULL) { - if (len == src->len) { - *dest = *src; - - return; - } - memcpy(o, p, len); o += len; - break; + dest->len = (size_t)(o - dest->base); + + return; } slen = (size_t)(q - p); @@ -1069,11 +1650,9 @@ void sf_unescape(sf_vec *dest, const sf_vec *src) { *o++ = *p++; len -= slen + 2; } - - dest->len = (size_t)(o - dest->base); } -void sf_base64decode(sf_vec *dest, const sf_vec *src) { +void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src) { static const int index_tbl[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -1092,20 +1671,22 @@ void sf_base64decode(sf_vec *dest, const sf_vec *src) { uint8_t *o; const uint8_t *p, *end; uint32_t n; - size_t i; + size_t i, left; int idx; - assert((src->len & 0x3) == 0); - if (src->len == 0) { - *dest = *src; + dest->len = 0; return; } o = dest->base; p = src->base; - end = src->base + src->len; + left = src->len & 0x3; + if (left == 0 && src->base[src->len - 1] == '=') { + left = 4; + } + end = src->base + src->len - left; for (; p != end;) { n = 0; @@ -1113,33 +1694,94 @@ void sf_base64decode(sf_vec *dest, const sf_vec *src) { for (i = 1; i <= 4; ++i, ++p) { idx = index_tbl[*p]; - if (idx == -1) { - assert(i > 2); + assert(idx != -1); - if (i == 3) { - assert(*p == '=' && *(p + 1) == '=' && p + 2 == end); + n += (uint32_t)(idx << (24 - i * 6)); + } - *o++ = (uint8_t)(n >> 16); + *o++ = (uint8_t)(n >> 16); + *o++ = (n >> 8) & 0xffu; + *o++ = n & 0xffu; + } - goto fin; - } + switch (left) { + case 0: + goto fin; + case 1: + assert(0); + abort(); + case 3: + if (src->base[src->len - 1] == '=') { + left = 2; + } - assert(*p == '=' && p + 1 == end); + break; + case 4: + assert('=' == src->base[src->len - 1]); - *o++ = (uint8_t)(n >> 16); - *o++ = (n >> 8) & 0xffu; + if (src->base[src->len - 2] == '=') { + left = 2; + } else { + left = 3; + } - goto fin; - } + break; + } - n += (uint32_t)(idx << (24 - i * 6)); - } + switch (left) { + case 2: + *o = (uint8_t)(index_tbl[*p++] << 2); + *o++ |= (uint8_t)(index_tbl[*p++] >> 4); - *o++ = (uint8_t)(n >> 16); + break; + case 3: + n = (uint32_t)(index_tbl[*p++] << 10); + n += (uint32_t)(index_tbl[*p++] << 4); + n += (uint32_t)(index_tbl[*p++] >> 2); *o++ = (n >> 8) & 0xffu; *o++ = n & 0xffu; + + break; } fin: dest->len = (size_t)(o - dest->base); } + +void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src) { + const uint8_t *p, *q; + uint8_t *o; + size_t len, slen; + + if (src->len == 0) { + dest->len = 0; + + return; + } + + o = dest->base; + p = src->base; + len = src->len; + + for (;;) { + q = memchr(p, '%', len); + if (q == NULL) { + memcpy(o, p, len); + o += len; + + dest->len = (size_t)(o - dest->base); + + return; + } + + slen = (size_t)(q - p); + memcpy(o, p, slen); + o += slen; + + p = q + 1; + + pctdecode(o++, &p); + + len -= slen + 3; + } +} diff --git a/deps/nghttp2/lib/sfparse.h b/deps/nghttp2/lib/sfparse.h index 1474db1429acea..9341221a099438 100644 --- a/deps/nghttp2/lib/sfparse.h +++ b/deps/nghttp2/lib/sfparse.h @@ -31,86 +31,90 @@ libcurl) */ #if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) # define WIN32 -#endif +#endif /* (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) */ #ifdef __cplusplus extern "C" { -#endif +#endif /* defined(__cplusplus) */ #if defined(_MSC_VER) && (_MSC_VER < 1800) /* MSVC < 2013 does not have inttypes.h because it is not C99 compliant. See compiler macros and version number in https://sourceforge.net/p/predef/wiki/Compilers/ */ # include -#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +#else /* !(defined(_MSC_VER) && (_MSC_VER < 1800)) */ # include -#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +#endif /* !(defined(_MSC_VER) && (_MSC_VER < 1800)) */ #include #include /** * @enum * - * :type:`sf_type` defines value type. + * :type:`sfparse_type` defines value type. */ -typedef enum sf_type { +typedef enum sfparse_type { /** - * :enum:`SF_TYPE_BOOLEAN` indicates boolean type. + * :enum:`SFPARSE_TYPE_BOOLEAN` indicates boolean type. */ - SF_TYPE_BOOLEAN, + SFPARSE_TYPE_BOOLEAN, /** - * :enum:`SF_TYPE_INTEGER` indicates integer type. + * :enum:`SFPARSE_TYPE_INTEGER` indicates integer type. */ - SF_TYPE_INTEGER, + SFPARSE_TYPE_INTEGER, /** - * :enum:`SF_TYPE_DECIMAL` indicates decimal type. + * :enum:`SFPARSE_TYPE_DECIMAL` indicates decimal type. */ - SF_TYPE_DECIMAL, + SFPARSE_TYPE_DECIMAL, /** - * :enum:`SF_TYPE_STRING` indicates string type. + * :enum:`SFPARSE_TYPE_STRING` indicates string type. */ - SF_TYPE_STRING, + SFPARSE_TYPE_STRING, /** - * :enum:`SF_TYPE_TOKEN` indicates token type. + * :enum:`SFPARSE_TYPE_TOKEN` indicates token type. */ - SF_TYPE_TOKEN, + SFPARSE_TYPE_TOKEN, /** - * :enum:`SF_TYPE_BYTESEQ` indicates byte sequence type. + * :enum:`SFPARSE_TYPE_BYTESEQ` indicates byte sequence type. */ - SF_TYPE_BYTESEQ, + SFPARSE_TYPE_BYTESEQ, /** - * :enum:`SF_TYPE_INNER_LIST` indicates inner list type. + * :enum:`SFPARSE_TYPE_INNER_LIST` indicates inner list type. */ - SF_TYPE_INNER_LIST, + SFPARSE_TYPE_INNER_LIST, /** - * :enum:`SF_TYPE_DATE` indicates date type. + * :enum:`SFPARSE_TYPE_DATE` indicates date type. */ - SF_TYPE_DATE -} sf_type; + SFPARSE_TYPE_DATE, + /** + * :enum:`SFPARSE_TYPE_DISPSTRING` indicates display string type. + */ + SFPARSE_TYPE_DISPSTRING +} sfparse_type; /** * @macro * - * :macro:`SF_ERR_PARSE_ERROR` indicates fatal parse error has + * :macro:`SFPARSE_ERR_PARSE` indicates fatal parse error has * occurred, and it is not possible to continue the processing. */ -#define SF_ERR_PARSE_ERROR -1 +#define SFPARSE_ERR_PARSE -1 /** * @macro * - * :macro:`SF_ERR_EOF` indicates that there is nothing left to read. - * The context of this error varies depending on the function that - * returns this error code. + * :macro:`SFPARSE_ERR_EOF` indicates that there is nothing left to + * read. The context of this error varies depending on the function + * that returns this error code. */ -#define SF_ERR_EOF -2 +#define SFPARSE_ERR_EOF -2 /** * @struct * - * :type:`sf_vec` stores sequence of bytes. + * :type:`sfparse_vec` stores sequence of bytes. */ -typedef struct sf_vec { +typedef struct sfparse_vec { /** * :member:`base` points to the beginning of the sequence of bytes. */ @@ -119,29 +123,29 @@ typedef struct sf_vec { * :member:`len` is the number of bytes contained in this sequence. */ size_t len; -} sf_vec; +} sfparse_vec; /** * @macro * - * :macro:`SF_VALUE_FLAG_NONE` indicates no flag set. + * :macro:`SFPARSE_VALUE_FLAG_NONE` indicates no flag set. */ -#define SF_VALUE_FLAG_NONE 0x0u +#define SFPARSE_VALUE_FLAG_NONE 0x0u /** * @macro * - * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` indicates that a string + * :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` indicates that a string * contains escaped character(s). */ -#define SF_VALUE_FLAG_ESCAPED_STRING 0x1u +#define SFPARSE_VALUE_FLAG_ESCAPED_STRING 0x1u /** * @struct * - * :type:`sf_decimal` contains decimal value. + * :type:`sfparse_decimal` contains decimal value. */ -typedef struct sf_decimal { +typedef struct sfparse_decimal { /** * :member:`numer` contains numerator of the decimal value. */ @@ -150,260 +154,289 @@ typedef struct sf_decimal { * :member:`denom` contains denominator of the decimal value. */ int64_t denom; -} sf_decimal; +} sfparse_decimal; /** * @struct * - * :type:`sf_value` stores a Structured Field item. For Inner List, - * only type is set to :enum:`sf_type.SF_TYPE_INNER_LIST`. In order - * to read the items contained in an inner list, call - * `sf_parser_inner_list`. + * :type:`sfparse_value` stores a Structured Field item. For Inner + * List, only type is set to + * :enum:`sfparse_type.SFPARSE_TYPE_INNER_LIST`. In order to read the + * items contained in an inner list, call `sfparse_parser_inner_list`. */ -typedef struct sf_value { +typedef struct sfparse_value { /** * :member:`type` is the type of the value contained in this * particular object. */ - sf_type type; + sfparse_type type; /** * :member:`flags` is bitwise OR of one or more of - * :macro:`SF_VALUE_FLAG_* `. + * :macro:`SFPARSE_VALUE_FLAG_* `. */ uint32_t flags; /** * @anonunion_start * - * @sf_value_value + * @sfparse_value_value */ union { /** * :member:`boolean` contains boolean value if :member:`type` == - * :enum:`sf_type.SF_TYPE_BOOLEAN`. 1 indicates true, and 0 - * indicates false. + * :enum:`sfparse_type.SFPARSE_TYPE_BOOLEAN`. 1 indicates true, + * and 0 indicates false. */ int boolean; /** * :member:`integer` contains integer value if :member:`type` is - * either :enum:`sf_type.SF_TYPE_INTEGER` or - * :enum:`sf_type.SF_TYPE_DATE`. + * either :enum:`sfparse_type.SFPARSE_TYPE_INTEGER` or + * :enum:`sfparse_type.SFPARSE_TYPE_DATE`. */ int64_t integer; /** * :member:`decimal` contains decimal value if :member:`type` == - * :enum:`sf_type.SF_TYPE_DECIMAL`. + * :enum:`sfparse_type.SFPARSE_TYPE_DECIMAL`. */ - sf_decimal decimal; + sfparse_decimal decimal; /** * :member:`vec` contains sequence of bytes if :member:`type` is - * either :enum:`sf_type.SF_TYPE_STRING`, - * :enum:`sf_type.SF_TYPE_TOKEN`, or - * :enum:`sf_type.SF_TYPE_BYTESEQ`. + * either :enum:`sfparse_type.SFPARSE_TYPE_STRING`, + * :enum:`sfparse_type.SFPARSE_TYPE_TOKEN`, + * :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, or + * :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`. * - * For :enum:`sf_type.SF_TYPE_STRING`, this field contains one or - * more escaped characters if :member:`flags` has - * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` set. To unescape the - * string, use `sf_unescape`. + * For :enum:`sfparse_type.SFPARSE_TYPE_STRING`, this field + * contains one or more escaped characters if :member:`flags` has + * :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` set. To unescape + * the string, use `sfparse_unescape`. * - * For :enum:`sf_type.SF_TYPE_BYTESEQ`, this field contains base64 - * encoded string. To decode this byte string, use - * `sf_base64decode`. + * For :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, this field + * contains base64 encoded string. To decode this byte string, + * use `sfparse_base64decode`. * - * If :member:`vec.len ` == 0, :member:`vec.base - * ` is guaranteed to be NULL. + * For :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`, this field + * may contain percent-encoded UTF-8 byte sequences. To decode + * it, use `sfparse_pctdecode`. + * + * If :member:`vec.len ` == 0, :member:`vec.base + * ` is guaranteed to be NULL. */ - sf_vec vec; + sfparse_vec vec; /** * @anonunion_end */ }; -} sf_value; +} sfparse_value; /** * @struct * - * :type:`sf_parser` is the Structured Field Values parser. Use - * `sf_parser_init` to initialize it. + * :type:`sfparse_parser` is the Structured Field Values parser. Use + * `sfparse_parser_init` to initialize it. */ -typedef struct sf_parser { +typedef struct sfparse_parser { /* all fields are private */ const uint8_t *pos; const uint8_t *end; uint32_t state; -} sf_parser; +} sfparse_parser; /** * @function * - * `sf_parser_init` initializes |sfp| with the given buffer pointed by - * |data| of length |datalen|. + * `sfparse_parser_init` initializes |sfp| with the given data encoded + * in Structured Field Values pointed by |data| of length |datalen|. */ -void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen); +void sfparse_parser_init(sfparse_parser *sfp, const uint8_t *data, + size_t datalen); /** * @function * - * `sf_parser_param` reads a parameter. If this function returns 0, - * it stores parameter key and value in |dest_key| and |dest_value| + * `sfparse_parser_param` reads a parameter. If this function returns + * 0, it stores parameter key and value in |dest_key| and |dest_value| * respectively, if they are not NULL. * * This function does no effort to find duplicated keys. Same key may * be reported more than once. * * Caller should keep calling this function until it returns negative - * error code. If it returns :macro:`SF_ERR_EOF`, all parameters have - * read, and caller can continue to read rest of the values. If it - * returns :macro:`SF_ERR_PARSE_ERROR`, it encountered fatal error + * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all parameters + * have read, and caller can continue to read rest of the values. If + * it returns :macro:`SFPARSE_ERR_PARSE`, it encountered fatal error * while parsing field value. */ -int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); +int sfparse_parser_param(sfparse_parser *sfp, sfparse_vec *dest_key, + sfparse_value *dest_value); /** * @function * - * `sf_parser_dict` reads the next dictionary key and value pair. If - * this function returns 0, it stores the key and value in |dest_key| - * and |dest_value| respectively, if they are not NULL. + * `sfparse_parser_dict` reads the next dictionary key and value pair. + * If this function returns 0, it stores the key and value in + * |dest_key| and |dest_value| respectively, if they are not NULL. * * Caller can optionally read parameters attached to the pair by - * calling `sf_parser_param`. + * calling `sfparse_parser_param`. * * This function does no effort to find duplicated keys. Same key may * be reported more than once. * * Caller should keep calling this function until it returns negative - * error code. If it returns :macro:`SF_ERR_EOF`, all key and value - * pairs have been read, and there is nothing left to read. + * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all key and + * value pairs have been read, and there is nothing left to read. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :macro:`SF_ERR_EOF` + * :macro:`SFPARSE_ERR_EOF` * All values in the dictionary have read. - * :macro:`SF_ERR_PARSE_ERROR` + * :macro:`SFPARSE_ERR_PARSE` * It encountered fatal error while parsing field value. */ -int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); +int sfparse_parser_dict(sfparse_parser *sfp, sfparse_vec *dest_key, + sfparse_value *dest_value); /** * @function * - * `sf_parser_list` reads the next list item. If this function + * `sfparse_parser_list` reads the next list item. If this function * returns 0, it stores the item in |dest| if it is not NULL. * * Caller can optionally read parameters attached to the item by - * calling `sf_parser_param`. + * calling `sfparse_parser_param`. * * Caller should keep calling this function until it returns negative - * error code. If it returns :macro:`SF_ERR_EOF`, all values in the - * list have been read, and there is nothing left to read. + * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all values in + * the list have been read, and there is nothing left to read. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :macro:`SF_ERR_EOF` + * :macro:`SFPARSE_ERR_EOF` * All values in the list have read. - * :macro:`SF_ERR_PARSE_ERROR` + * :macro:`SFPARSE_ERR_PARSE` * It encountered fatal error while parsing field value. */ -int sf_parser_list(sf_parser *sfp, sf_value *dest); +int sfparse_parser_list(sfparse_parser *sfp, sfparse_value *dest); /** * @function * - * `sf_parser_item` reads a single item. If this function returns 0, - * it stores the item in |dest| if it is not NULL. + * `sfparse_parser_item` reads a single item. If this function + * returns 0, it stores the item in |dest| if it is not NULL. * * This function is only used for the field value that consists of a * single item. * * Caller can optionally read parameters attached to the item by - * calling `sf_parser_param`. + * calling `sfparse_parser_param`. * * Caller should call this function again to make sure that there is * nothing left to read. If this 2nd function call returns - * :macro:`SF_ERR_EOF`, all data have been processed successfully. + * :macro:`SFPARSE_ERR_EOF`, all data have been processed + * successfully. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :macro:`SF_ERR_EOF` + * :macro:`SFPARSE_ERR_EOF` * There is nothing left to read. - * :macro:`SF_ERR_PARSE_ERROR` + * :macro:`SFPARSE_ERR_PARSE` * It encountered fatal error while parsing field value. */ -int sf_parser_item(sf_parser *sfp, sf_value *dest); +int sfparse_parser_item(sfparse_parser *sfp, sfparse_value *dest); /** * @function * - * `sf_parser_inner_list` reads the next inner list item. If this - * function returns 0, it stores the item in |dest| if it is not NULL. + * `sfparse_parser_inner_list` reads the next inner list item. If + * this function returns 0, it stores the item in |dest| if it is not + * NULL. * * Caller can optionally read parameters attached to the item by - * calling `sf_parser_param`. + * calling `sfparse_parser_param`. * * Caller should keep calling this function until it returns negative - * error code. If it returns :macro:`SF_ERR_EOF`, all values in this - * inner list have been read, and caller can optionally read + * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all values in + * this inner list have been read, and caller can optionally read * parameters attached to this inner list by calling - * `sf_parser_param`. Then caller can continue to read rest of the - * values. + * `sfparse_parser_param`. Then caller can continue to read rest of + * the values. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :macro:`SF_ERR_EOF` + * :macro:`SFPARSE_ERR_EOF` * All values in the inner list have read. - * :macro:`SF_ERR_PARSE_ERROR` + * :macro:`SFPARSE_ERR_PARSE` * It encountered fatal error while parsing field value. */ -int sf_parser_inner_list(sf_parser *sfp, sf_value *dest); +int sfparse_parser_inner_list(sfparse_parser *sfp, sfparse_value *dest); /** * @function * - * `sf_unescape` copies |src| to |dest| by removing escapes (``\``). - * |src| should be the pointer to :member:`sf_value.vec` of type - * :enum:`sf_type.SF_TYPE_STRING` produced by either `sf_parser_dict`, - * `sf_parser_list`, `sf_parser_inner_list`, `sf_parser_item`, or - * `sf_parser_param`, otherwise the behavior is undefined. + * `sfparse_unescape` copies |src| to |dest| by removing escapes + * (``\``). |src| should be the pointer to + * :member:`sfparse_value.vec` of type + * :enum:`sfparse_type.SFPARSE_TYPE_STRING` produced by either + * `sfparse_parser_dict`, `sfparse_parser_list`, + * `sfparse_parser_inner_list`, `sfparse_parser_item`, or + * `sfparse_parser_param`, otherwise the behavior is undefined. * - * :member:`dest->base ` must point to the buffer that - * has sufficient space to store the unescaped string. - * - * If there is no escape character in |src|, |*src| is assigned to - * |*dest|. This includes the case that :member:`src->len - * ` == 0. + * :member:`dest->base ` must point to the buffer + * that has sufficient space to store the unescaped string. The + * memory areas pointed by :member:`dest->base ` and + * :member:`src->base ` must not overlap. * * This function sets the length of unescaped string to - * :member:`dest->len `. + * :member:`dest->len `. */ -void sf_unescape(sf_vec *dest, const sf_vec *src); +void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src); /** * @function * - * `sf_base64decode` decodes Base64 encoded string |src| and writes - * the result into |dest|. |src| should be the pointer to - * :member:`sf_value.vec` of type :enum:`sf_type.SF_TYPE_BYTESEQ` - * produced by either `sf_parser_dict`, `sf_parser_list`, - * `sf_parser_inner_list`, `sf_parser_item`, or `sf_parser_param`, - * otherwise the behavior is undefined. + * `sfparse_base64decode` decodes Base64 encoded string |src| and + * writes the result into |dest|. |src| should be the pointer to + * :member:`sfparse_value.vec` of type + * :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ` produced by either + * `sfparse_parser_dict`, `sfparse_parser_list`, + * `sfparse_parser_inner_list`, `sfparse_parser_item`, or + * `sfparse_parser_param`, otherwise the behavior is undefined. + * + * :member:`dest->base ` must point to the buffer + * that has sufficient space to store the decoded byte string. * - * :member:`dest->base ` must point to the buffer that - * has sufficient space to store the decoded byte string. + * This function sets the length of decoded byte string to + * :member:`dest->len `. + */ +void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src); + +/** + * @function + * + * `sfparse_pctdecode` decodes percent-encoded string |src| and writes + * the result into |dest|. |src| should be the pointer to + * :member:`sfparse_value.vec` of type + * :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING` produced by either + * `sfparse_parser_dict`, `sfparse_parser_list`, + * `sfparse_parser_inner_list`, `sfparse_parser_item`, or + * `sfparse_parser_param`, otherwise the behavior is undefined. * - * If :member:`src->len ` == 0, |*src| is assigned to - * |*dest|. + * :member:`dest->base ` must point to the buffer + * that has sufficient space to store the decoded byte string. The + * memory areas pointed by :member:`dest->base ` and + * :member:`src->base ` must not overlap. * * This function sets the length of decoded byte string to - * :member:`dest->len `. + * :member:`dest->len `. */ -void sf_base64decode(sf_vec *dest, const sf_vec *src); +void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src); #ifdef __cplusplus } -#endif +#endif /* defined(__cplusplus) */ -#endif /* SFPARSE_H */ +#endif /* !defined(SFPARSE_H) */ diff --git a/deps/openssl/.gitignore b/deps/openssl/.gitignore index ef7d3ad4caba66..104bfb441d9a1f 100644 --- a/deps/openssl/.gitignore +++ b/deps/openssl/.gitignore @@ -1,5 +1,9 @@ openssl/demos -openssl/doc +openssl/doc/* +!openssl/doc/man1 +openssl/doc/man1/* +!openssl/doc/man1/build.info +!openssl/doc/build.info openssl/fuzz/corpora openssl/makefile.in openssl/Makefile.in diff --git a/deps/openssl/config/Dockerfile b/deps/openssl/config/Dockerfile index 5133a88b0d33e2..9929a9315ead91 100644 --- a/deps/openssl/config/Dockerfile +++ b/deps/openssl/config/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 +FROM ubuntu:22.04 VOLUME /node diff --git a/deps/openssl/openssl-cl_asm.gypi b/deps/openssl/openssl-cl_asm.gypi index cd10355c171228..2e58f0dcb094a0 100644 --- a/deps/openssl/openssl-cl_asm.gypi +++ b/deps/openssl/openssl-cl_asm.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/asm/openssl-cl.gypi'], }, 'target_arch=="arm" and OS=="linux"', { 'includes': ['config/archs/linux-armv4/asm/openssl-cl.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in "linux openharmony"', { 'includes': ['config/archs/linux-aarch64/asm/openssl-cl.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/asm/openssl-cl.gypi'], diff --git a/deps/openssl/openssl-cl_asm_avx2.gypi b/deps/openssl/openssl-cl_asm_avx2.gypi index 50b5a9c375bd8d..03056a832d0322 100644 --- a/deps/openssl/openssl-cl_asm_avx2.gypi +++ b/deps/openssl/openssl-cl_asm_avx2.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/asm_avx2/openssl-cl.gypi'], }, 'target_arch=="arm" and OS=="linux"', { 'includes': ['config/archs/linux-armv4/asm_avx2/openssl-cl.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in "linux openharmony"', { 'includes': ['config/archs/linux-aarch64/asm_avx2/openssl-cl.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/asm_avx2/openssl-cl.gypi'], diff --git a/deps/openssl/openssl-cl_no_asm.gypi b/deps/openssl/openssl-cl_no_asm.gypi index 0964fb36739b3a..c838da5cf9ea85 100644 --- a/deps/openssl/openssl-cl_no_asm.gypi +++ b/deps/openssl/openssl-cl_no_asm.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/no-asm/openssl-cl.gypi'], }, 'target_arch=="arm" and OS in ("linux", "android")', { 'includes': ['config/archs/linux-armv4/no-asm/openssl-cl.gypi'], - }, 'target_arch=="arm64" and OS in ("linux", "android")', { + }, 'target_arch=="arm64" and OS in ("linux", "android", "openharmony")', { 'includes': ['config/archs/linux-aarch64/no-asm/openssl-cl.gypi'], }, 'target_arch=="arm64" and OS=="win"', { 'includes': ['config/archs/VC-WIN64-ARM/no-asm/openssl-cl.gypi'], diff --git a/deps/openssl/openssl-cli.gypi b/deps/openssl/openssl-cli.gypi index b4c278b4fe8f9f..ae74be9a2b17d2 100644 --- a/deps/openssl/openssl-cli.gypi +++ b/deps/openssl/openssl-cli.gypi @@ -14,7 +14,7 @@ 'link_settings': { 'libraries': ['<@(openssl_cli_libraries_win)'], }, - }, 'OS in "linux android"', { + }, 'OS in "linux android openharmony"', { 'link_settings': { 'libraries': [ '-ldl', diff --git a/deps/openssl/openssl-fips_asm.gypi b/deps/openssl/openssl-fips_asm.gypi index 631df9eb893288..633aae4b386759 100644 --- a/deps/openssl/openssl-fips_asm.gypi +++ b/deps/openssl/openssl-fips_asm.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/asm/openssl-fips.gypi'], }, 'target_arch=="arm" and OS=="linux"', { 'includes': ['config/archs/linux-armv4/asm/openssl-fips.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in "linux openharmony"', { 'includes': ['config/archs/linux-aarch64/asm/openssl-fips.gypi'], }, 'target_arch=="arm64" and OS=="mac"', { 'includes': ['config/archs/darwin64-arm64-cc/asm/openssl-fips.gypi'], diff --git a/deps/openssl/openssl-fips_asm_avx2.gypi b/deps/openssl/openssl-fips_asm_avx2.gypi index 4d63cacf29d040..74cc78c42a7b15 100644 --- a/deps/openssl/openssl-fips_asm_avx2.gypi +++ b/deps/openssl/openssl-fips_asm_avx2.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/asm_avx2/openssl-fips.gypi'], }, 'target_arch=="arm" and OS=="linux"', { 'includes': ['config/archs/linux-armv4/asm_avx2/openssl-fips.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in "linux openharmony"', { 'includes': ['config/archs/linux-aarch64/asm_avx2/openssl-fips.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/asm_avx2/openssl-fips.gypi'], diff --git a/deps/openssl/openssl-fips_no_asm.gypi b/deps/openssl/openssl-fips_no_asm.gypi index 7fdfd772abbce8..ab8074cf4397a5 100644 --- a/deps/openssl/openssl-fips_no_asm.gypi +++ b/deps/openssl/openssl-fips_no_asm.gypi @@ -9,7 +9,7 @@ 'includes': ['config/archs/linux64-s390x/no-asm/openssl-fips.gypi'], }, 'target_arch=="arm" and OS in ("linux", "android")', { 'includes': ['config/archs/linux-armv4/no-asm/openssl-fips.gypi'], - }, 'target_arch=="arm64" and OS in ("linux", "android")', { + }, 'target_arch=="arm64" and OS in ("linux", "android", "openharmony")', { 'includes': ['config/archs/linux-aarch64/no-asm/openssl-fips.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/no-asm/openssl-fips.gypi'], diff --git a/deps/openssl/openssl/doc/build.info b/deps/openssl/openssl/doc/build.info new file mode 100644 index 00000000000000..0279e2390a3242 --- /dev/null +++ b/deps/openssl/openssl/doc/build.info @@ -0,0 +1,4902 @@ +SUBDIRS = man1 + +DEPEND[html/man1/CA.pl.html]=man1/CA.pl.pod +GENERATE[html/man1/CA.pl.html]=man1/CA.pl.pod +DEPEND[man/man1/CA.pl.1]=man1/CA.pl.pod +GENERATE[man/man1/CA.pl.1]=man1/CA.pl.pod +DEPEND[html/man1/openssl-asn1parse.html]=man1/openssl-asn1parse.pod +GENERATE[html/man1/openssl-asn1parse.html]=man1/openssl-asn1parse.pod +DEPEND[man/man1/openssl-asn1parse.1]=man1/openssl-asn1parse.pod +GENERATE[man/man1/openssl-asn1parse.1]=man1/openssl-asn1parse.pod +DEPEND[man1/openssl-asn1parse.pod]{pod}=man1/openssl-asn1parse.pod.in +GENERATE[man1/openssl-asn1parse.pod]=man1/openssl-asn1parse.pod.in +DEPEND[html/man1/openssl-ca.html]=man1/openssl-ca.pod +GENERATE[html/man1/openssl-ca.html]=man1/openssl-ca.pod +DEPEND[man/man1/openssl-ca.1]=man1/openssl-ca.pod +GENERATE[man/man1/openssl-ca.1]=man1/openssl-ca.pod +DEPEND[man1/openssl-ca.pod]{pod}=man1/openssl-ca.pod.in +GENERATE[man1/openssl-ca.pod]=man1/openssl-ca.pod.in +DEPEND[html/man1/openssl-ciphers.html]=man1/openssl-ciphers.pod +GENERATE[html/man1/openssl-ciphers.html]=man1/openssl-ciphers.pod +DEPEND[man/man1/openssl-ciphers.1]=man1/openssl-ciphers.pod +GENERATE[man/man1/openssl-ciphers.1]=man1/openssl-ciphers.pod +DEPEND[man1/openssl-ciphers.pod]{pod}=man1/openssl-ciphers.pod.in +GENERATE[man1/openssl-ciphers.pod]=man1/openssl-ciphers.pod.in +DEPEND[html/man1/openssl-cmds.html]=man1/openssl-cmds.pod +GENERATE[html/man1/openssl-cmds.html]=man1/openssl-cmds.pod +DEPEND[man/man1/openssl-cmds.1]=man1/openssl-cmds.pod +GENERATE[man/man1/openssl-cmds.1]=man1/openssl-cmds.pod +DEPEND[man1/openssl-cmds.pod]{pod}=man1/openssl-cmds.pod.in +GENERATE[man1/openssl-cmds.pod]=man1/openssl-cmds.pod.in +DEPEND[html/man1/openssl-cmp.html]=man1/openssl-cmp.pod +GENERATE[html/man1/openssl-cmp.html]=man1/openssl-cmp.pod +DEPEND[man/man1/openssl-cmp.1]=man1/openssl-cmp.pod +GENERATE[man/man1/openssl-cmp.1]=man1/openssl-cmp.pod +DEPEND[man1/openssl-cmp.pod]{pod}=man1/openssl-cmp.pod.in +GENERATE[man1/openssl-cmp.pod]=man1/openssl-cmp.pod.in +DEPEND[html/man1/openssl-cms.html]=man1/openssl-cms.pod +GENERATE[html/man1/openssl-cms.html]=man1/openssl-cms.pod +DEPEND[man/man1/openssl-cms.1]=man1/openssl-cms.pod +GENERATE[man/man1/openssl-cms.1]=man1/openssl-cms.pod +DEPEND[man1/openssl-cms.pod]{pod}=man1/openssl-cms.pod.in +GENERATE[man1/openssl-cms.pod]=man1/openssl-cms.pod.in +DEPEND[html/man1/openssl-crl.html]=man1/openssl-crl.pod +GENERATE[html/man1/openssl-crl.html]=man1/openssl-crl.pod +DEPEND[man/man1/openssl-crl.1]=man1/openssl-crl.pod +GENERATE[man/man1/openssl-crl.1]=man1/openssl-crl.pod +DEPEND[man1/openssl-crl.pod]{pod}=man1/openssl-crl.pod.in +GENERATE[man1/openssl-crl.pod]=man1/openssl-crl.pod.in +DEPEND[html/man1/openssl-crl2pkcs7.html]=man1/openssl-crl2pkcs7.pod +GENERATE[html/man1/openssl-crl2pkcs7.html]=man1/openssl-crl2pkcs7.pod +DEPEND[man/man1/openssl-crl2pkcs7.1]=man1/openssl-crl2pkcs7.pod +GENERATE[man/man1/openssl-crl2pkcs7.1]=man1/openssl-crl2pkcs7.pod +DEPEND[man1/openssl-crl2pkcs7.pod]{pod}=man1/openssl-crl2pkcs7.pod.in +GENERATE[man1/openssl-crl2pkcs7.pod]=man1/openssl-crl2pkcs7.pod.in +DEPEND[html/man1/openssl-dgst.html]=man1/openssl-dgst.pod +GENERATE[html/man1/openssl-dgst.html]=man1/openssl-dgst.pod +DEPEND[man/man1/openssl-dgst.1]=man1/openssl-dgst.pod +GENERATE[man/man1/openssl-dgst.1]=man1/openssl-dgst.pod +DEPEND[man1/openssl-dgst.pod]{pod}=man1/openssl-dgst.pod.in +GENERATE[man1/openssl-dgst.pod]=man1/openssl-dgst.pod.in +DEPEND[html/man1/openssl-dhparam.html]=man1/openssl-dhparam.pod +GENERATE[html/man1/openssl-dhparam.html]=man1/openssl-dhparam.pod +DEPEND[man/man1/openssl-dhparam.1]=man1/openssl-dhparam.pod +GENERATE[man/man1/openssl-dhparam.1]=man1/openssl-dhparam.pod +DEPEND[man1/openssl-dhparam.pod]{pod}=man1/openssl-dhparam.pod.in +GENERATE[man1/openssl-dhparam.pod]=man1/openssl-dhparam.pod.in +DEPEND[html/man1/openssl-dsa.html]=man1/openssl-dsa.pod +GENERATE[html/man1/openssl-dsa.html]=man1/openssl-dsa.pod +DEPEND[man/man1/openssl-dsa.1]=man1/openssl-dsa.pod +GENERATE[man/man1/openssl-dsa.1]=man1/openssl-dsa.pod +DEPEND[man1/openssl-dsa.pod]{pod}=man1/openssl-dsa.pod.in +GENERATE[man1/openssl-dsa.pod]=man1/openssl-dsa.pod.in +DEPEND[html/man1/openssl-dsaparam.html]=man1/openssl-dsaparam.pod +GENERATE[html/man1/openssl-dsaparam.html]=man1/openssl-dsaparam.pod +DEPEND[man/man1/openssl-dsaparam.1]=man1/openssl-dsaparam.pod +GENERATE[man/man1/openssl-dsaparam.1]=man1/openssl-dsaparam.pod +DEPEND[man1/openssl-dsaparam.pod]{pod}=man1/openssl-dsaparam.pod.in +GENERATE[man1/openssl-dsaparam.pod]=man1/openssl-dsaparam.pod.in +DEPEND[html/man1/openssl-ec.html]=man1/openssl-ec.pod +GENERATE[html/man1/openssl-ec.html]=man1/openssl-ec.pod +DEPEND[man/man1/openssl-ec.1]=man1/openssl-ec.pod +GENERATE[man/man1/openssl-ec.1]=man1/openssl-ec.pod +DEPEND[man1/openssl-ec.pod]{pod}=man1/openssl-ec.pod.in +GENERATE[man1/openssl-ec.pod]=man1/openssl-ec.pod.in +DEPEND[html/man1/openssl-ecparam.html]=man1/openssl-ecparam.pod +GENERATE[html/man1/openssl-ecparam.html]=man1/openssl-ecparam.pod +DEPEND[man/man1/openssl-ecparam.1]=man1/openssl-ecparam.pod +GENERATE[man/man1/openssl-ecparam.1]=man1/openssl-ecparam.pod +DEPEND[man1/openssl-ecparam.pod]{pod}=man1/openssl-ecparam.pod.in +GENERATE[man1/openssl-ecparam.pod]=man1/openssl-ecparam.pod.in +DEPEND[html/man1/openssl-enc.html]=man1/openssl-enc.pod +GENERATE[html/man1/openssl-enc.html]=man1/openssl-enc.pod +DEPEND[man/man1/openssl-enc.1]=man1/openssl-enc.pod +GENERATE[man/man1/openssl-enc.1]=man1/openssl-enc.pod +DEPEND[man1/openssl-enc.pod]{pod}=man1/openssl-enc.pod.in +GENERATE[man1/openssl-enc.pod]=man1/openssl-enc.pod.in +DEPEND[html/man1/openssl-engine.html]=man1/openssl-engine.pod +GENERATE[html/man1/openssl-engine.html]=man1/openssl-engine.pod +DEPEND[man/man1/openssl-engine.1]=man1/openssl-engine.pod +GENERATE[man/man1/openssl-engine.1]=man1/openssl-engine.pod +DEPEND[man1/openssl-engine.pod]{pod}=man1/openssl-engine.pod.in +GENERATE[man1/openssl-engine.pod]=man1/openssl-engine.pod.in +DEPEND[html/man1/openssl-errstr.html]=man1/openssl-errstr.pod +GENERATE[html/man1/openssl-errstr.html]=man1/openssl-errstr.pod +DEPEND[man/man1/openssl-errstr.1]=man1/openssl-errstr.pod +GENERATE[man/man1/openssl-errstr.1]=man1/openssl-errstr.pod +DEPEND[man1/openssl-errstr.pod]{pod}=man1/openssl-errstr.pod.in +GENERATE[man1/openssl-errstr.pod]=man1/openssl-errstr.pod.in +DEPEND[html/man1/openssl-fipsinstall.html]=man1/openssl-fipsinstall.pod +GENERATE[html/man1/openssl-fipsinstall.html]=man1/openssl-fipsinstall.pod +DEPEND[man/man1/openssl-fipsinstall.1]=man1/openssl-fipsinstall.pod +GENERATE[man/man1/openssl-fipsinstall.1]=man1/openssl-fipsinstall.pod +DEPEND[man1/openssl-fipsinstall.pod]{pod}=man1/openssl-fipsinstall.pod.in +GENERATE[man1/openssl-fipsinstall.pod]=man1/openssl-fipsinstall.pod.in +DEPEND[html/man1/openssl-format-options.html]=man1/openssl-format-options.pod +GENERATE[html/man1/openssl-format-options.html]=man1/openssl-format-options.pod +DEPEND[man/man1/openssl-format-options.1]=man1/openssl-format-options.pod +GENERATE[man/man1/openssl-format-options.1]=man1/openssl-format-options.pod +DEPEND[html/man1/openssl-gendsa.html]=man1/openssl-gendsa.pod +GENERATE[html/man1/openssl-gendsa.html]=man1/openssl-gendsa.pod +DEPEND[man/man1/openssl-gendsa.1]=man1/openssl-gendsa.pod +GENERATE[man/man1/openssl-gendsa.1]=man1/openssl-gendsa.pod +DEPEND[man1/openssl-gendsa.pod]{pod}=man1/openssl-gendsa.pod.in +GENERATE[man1/openssl-gendsa.pod]=man1/openssl-gendsa.pod.in +DEPEND[html/man1/openssl-genpkey.html]=man1/openssl-genpkey.pod +GENERATE[html/man1/openssl-genpkey.html]=man1/openssl-genpkey.pod +DEPEND[man/man1/openssl-genpkey.1]=man1/openssl-genpkey.pod +GENERATE[man/man1/openssl-genpkey.1]=man1/openssl-genpkey.pod +DEPEND[man1/openssl-genpkey.pod]{pod}=man1/openssl-genpkey.pod.in +GENERATE[man1/openssl-genpkey.pod]=man1/openssl-genpkey.pod.in +DEPEND[html/man1/openssl-genrsa.html]=man1/openssl-genrsa.pod +GENERATE[html/man1/openssl-genrsa.html]=man1/openssl-genrsa.pod +DEPEND[man/man1/openssl-genrsa.1]=man1/openssl-genrsa.pod +GENERATE[man/man1/openssl-genrsa.1]=man1/openssl-genrsa.pod +DEPEND[man1/openssl-genrsa.pod]{pod}=man1/openssl-genrsa.pod.in +GENERATE[man1/openssl-genrsa.pod]=man1/openssl-genrsa.pod.in +DEPEND[html/man1/openssl-info.html]=man1/openssl-info.pod +GENERATE[html/man1/openssl-info.html]=man1/openssl-info.pod +DEPEND[man/man1/openssl-info.1]=man1/openssl-info.pod +GENERATE[man/man1/openssl-info.1]=man1/openssl-info.pod +DEPEND[man1/openssl-info.pod]{pod}=man1/openssl-info.pod.in +GENERATE[man1/openssl-info.pod]=man1/openssl-info.pod.in +DEPEND[html/man1/openssl-kdf.html]=man1/openssl-kdf.pod +GENERATE[html/man1/openssl-kdf.html]=man1/openssl-kdf.pod +DEPEND[man/man1/openssl-kdf.1]=man1/openssl-kdf.pod +GENERATE[man/man1/openssl-kdf.1]=man1/openssl-kdf.pod +DEPEND[man1/openssl-kdf.pod]{pod}=man1/openssl-kdf.pod.in +GENERATE[man1/openssl-kdf.pod]=man1/openssl-kdf.pod.in +DEPEND[html/man1/openssl-list.html]=man1/openssl-list.pod +GENERATE[html/man1/openssl-list.html]=man1/openssl-list.pod +DEPEND[man/man1/openssl-list.1]=man1/openssl-list.pod +GENERATE[man/man1/openssl-list.1]=man1/openssl-list.pod +DEPEND[man1/openssl-list.pod]{pod}=man1/openssl-list.pod.in +GENERATE[man1/openssl-list.pod]=man1/openssl-list.pod.in +DEPEND[html/man1/openssl-mac.html]=man1/openssl-mac.pod +GENERATE[html/man1/openssl-mac.html]=man1/openssl-mac.pod +DEPEND[man/man1/openssl-mac.1]=man1/openssl-mac.pod +GENERATE[man/man1/openssl-mac.1]=man1/openssl-mac.pod +DEPEND[man1/openssl-mac.pod]{pod}=man1/openssl-mac.pod.in +GENERATE[man1/openssl-mac.pod]=man1/openssl-mac.pod.in +DEPEND[html/man1/openssl-namedisplay-options.html]=man1/openssl-namedisplay-options.pod +GENERATE[html/man1/openssl-namedisplay-options.html]=man1/openssl-namedisplay-options.pod +DEPEND[man/man1/openssl-namedisplay-options.1]=man1/openssl-namedisplay-options.pod +GENERATE[man/man1/openssl-namedisplay-options.1]=man1/openssl-namedisplay-options.pod +DEPEND[html/man1/openssl-nseq.html]=man1/openssl-nseq.pod +GENERATE[html/man1/openssl-nseq.html]=man1/openssl-nseq.pod +DEPEND[man/man1/openssl-nseq.1]=man1/openssl-nseq.pod +GENERATE[man/man1/openssl-nseq.1]=man1/openssl-nseq.pod +DEPEND[man1/openssl-nseq.pod]{pod}=man1/openssl-nseq.pod.in +GENERATE[man1/openssl-nseq.pod]=man1/openssl-nseq.pod.in +DEPEND[html/man1/openssl-ocsp.html]=man1/openssl-ocsp.pod +GENERATE[html/man1/openssl-ocsp.html]=man1/openssl-ocsp.pod +DEPEND[man/man1/openssl-ocsp.1]=man1/openssl-ocsp.pod +GENERATE[man/man1/openssl-ocsp.1]=man1/openssl-ocsp.pod +DEPEND[man1/openssl-ocsp.pod]{pod}=man1/openssl-ocsp.pod.in +GENERATE[man1/openssl-ocsp.pod]=man1/openssl-ocsp.pod.in +DEPEND[html/man1/openssl-passphrase-options.html]=man1/openssl-passphrase-options.pod +GENERATE[html/man1/openssl-passphrase-options.html]=man1/openssl-passphrase-options.pod +DEPEND[man/man1/openssl-passphrase-options.1]=man1/openssl-passphrase-options.pod +GENERATE[man/man1/openssl-passphrase-options.1]=man1/openssl-passphrase-options.pod +DEPEND[html/man1/openssl-passwd.html]=man1/openssl-passwd.pod +GENERATE[html/man1/openssl-passwd.html]=man1/openssl-passwd.pod +DEPEND[man/man1/openssl-passwd.1]=man1/openssl-passwd.pod +GENERATE[man/man1/openssl-passwd.1]=man1/openssl-passwd.pod +DEPEND[man1/openssl-passwd.pod]{pod}=man1/openssl-passwd.pod.in +GENERATE[man1/openssl-passwd.pod]=man1/openssl-passwd.pod.in +DEPEND[html/man1/openssl-pkcs12.html]=man1/openssl-pkcs12.pod +GENERATE[html/man1/openssl-pkcs12.html]=man1/openssl-pkcs12.pod +DEPEND[man/man1/openssl-pkcs12.1]=man1/openssl-pkcs12.pod +GENERATE[man/man1/openssl-pkcs12.1]=man1/openssl-pkcs12.pod +DEPEND[man1/openssl-pkcs12.pod]{pod}=man1/openssl-pkcs12.pod.in +GENERATE[man1/openssl-pkcs12.pod]=man1/openssl-pkcs12.pod.in +DEPEND[html/man1/openssl-pkcs7.html]=man1/openssl-pkcs7.pod +GENERATE[html/man1/openssl-pkcs7.html]=man1/openssl-pkcs7.pod +DEPEND[man/man1/openssl-pkcs7.1]=man1/openssl-pkcs7.pod +GENERATE[man/man1/openssl-pkcs7.1]=man1/openssl-pkcs7.pod +DEPEND[man1/openssl-pkcs7.pod]{pod}=man1/openssl-pkcs7.pod.in +GENERATE[man1/openssl-pkcs7.pod]=man1/openssl-pkcs7.pod.in +DEPEND[html/man1/openssl-pkcs8.html]=man1/openssl-pkcs8.pod +GENERATE[html/man1/openssl-pkcs8.html]=man1/openssl-pkcs8.pod +DEPEND[man/man1/openssl-pkcs8.1]=man1/openssl-pkcs8.pod +GENERATE[man/man1/openssl-pkcs8.1]=man1/openssl-pkcs8.pod +DEPEND[man1/openssl-pkcs8.pod]{pod}=man1/openssl-pkcs8.pod.in +GENERATE[man1/openssl-pkcs8.pod]=man1/openssl-pkcs8.pod.in +DEPEND[html/man1/openssl-pkey.html]=man1/openssl-pkey.pod +GENERATE[html/man1/openssl-pkey.html]=man1/openssl-pkey.pod +DEPEND[man/man1/openssl-pkey.1]=man1/openssl-pkey.pod +GENERATE[man/man1/openssl-pkey.1]=man1/openssl-pkey.pod +DEPEND[man1/openssl-pkey.pod]{pod}=man1/openssl-pkey.pod.in +GENERATE[man1/openssl-pkey.pod]=man1/openssl-pkey.pod.in +DEPEND[html/man1/openssl-pkeyparam.html]=man1/openssl-pkeyparam.pod +GENERATE[html/man1/openssl-pkeyparam.html]=man1/openssl-pkeyparam.pod +DEPEND[man/man1/openssl-pkeyparam.1]=man1/openssl-pkeyparam.pod +GENERATE[man/man1/openssl-pkeyparam.1]=man1/openssl-pkeyparam.pod +DEPEND[man1/openssl-pkeyparam.pod]{pod}=man1/openssl-pkeyparam.pod.in +GENERATE[man1/openssl-pkeyparam.pod]=man1/openssl-pkeyparam.pod.in +DEPEND[html/man1/openssl-pkeyutl.html]=man1/openssl-pkeyutl.pod +GENERATE[html/man1/openssl-pkeyutl.html]=man1/openssl-pkeyutl.pod +DEPEND[man/man1/openssl-pkeyutl.1]=man1/openssl-pkeyutl.pod +GENERATE[man/man1/openssl-pkeyutl.1]=man1/openssl-pkeyutl.pod +DEPEND[man1/openssl-pkeyutl.pod]{pod}=man1/openssl-pkeyutl.pod.in +GENERATE[man1/openssl-pkeyutl.pod]=man1/openssl-pkeyutl.pod.in +DEPEND[html/man1/openssl-prime.html]=man1/openssl-prime.pod +GENERATE[html/man1/openssl-prime.html]=man1/openssl-prime.pod +DEPEND[man/man1/openssl-prime.1]=man1/openssl-prime.pod +GENERATE[man/man1/openssl-prime.1]=man1/openssl-prime.pod +DEPEND[man1/openssl-prime.pod]{pod}=man1/openssl-prime.pod.in +GENERATE[man1/openssl-prime.pod]=man1/openssl-prime.pod.in +DEPEND[html/man1/openssl-rand.html]=man1/openssl-rand.pod +GENERATE[html/man1/openssl-rand.html]=man1/openssl-rand.pod +DEPEND[man/man1/openssl-rand.1]=man1/openssl-rand.pod +GENERATE[man/man1/openssl-rand.1]=man1/openssl-rand.pod +DEPEND[man1/openssl-rand.pod]{pod}=man1/openssl-rand.pod.in +GENERATE[man1/openssl-rand.pod]=man1/openssl-rand.pod.in +DEPEND[html/man1/openssl-rehash.html]=man1/openssl-rehash.pod +GENERATE[html/man1/openssl-rehash.html]=man1/openssl-rehash.pod +DEPEND[man/man1/openssl-rehash.1]=man1/openssl-rehash.pod +GENERATE[man/man1/openssl-rehash.1]=man1/openssl-rehash.pod +DEPEND[man1/openssl-rehash.pod]{pod}=man1/openssl-rehash.pod.in +GENERATE[man1/openssl-rehash.pod]=man1/openssl-rehash.pod.in +DEPEND[html/man1/openssl-req.html]=man1/openssl-req.pod +GENERATE[html/man1/openssl-req.html]=man1/openssl-req.pod +DEPEND[man/man1/openssl-req.1]=man1/openssl-req.pod +GENERATE[man/man1/openssl-req.1]=man1/openssl-req.pod +DEPEND[man1/openssl-req.pod]{pod}=man1/openssl-req.pod.in +GENERATE[man1/openssl-req.pod]=man1/openssl-req.pod.in +DEPEND[html/man1/openssl-rsa.html]=man1/openssl-rsa.pod +GENERATE[html/man1/openssl-rsa.html]=man1/openssl-rsa.pod +DEPEND[man/man1/openssl-rsa.1]=man1/openssl-rsa.pod +GENERATE[man/man1/openssl-rsa.1]=man1/openssl-rsa.pod +DEPEND[man1/openssl-rsa.pod]{pod}=man1/openssl-rsa.pod.in +GENERATE[man1/openssl-rsa.pod]=man1/openssl-rsa.pod.in +DEPEND[html/man1/openssl-rsautl.html]=man1/openssl-rsautl.pod +GENERATE[html/man1/openssl-rsautl.html]=man1/openssl-rsautl.pod +DEPEND[man/man1/openssl-rsautl.1]=man1/openssl-rsautl.pod +GENERATE[man/man1/openssl-rsautl.1]=man1/openssl-rsautl.pod +DEPEND[man1/openssl-rsautl.pod]{pod}=man1/openssl-rsautl.pod.in +GENERATE[man1/openssl-rsautl.pod]=man1/openssl-rsautl.pod.in +DEPEND[html/man1/openssl-s_client.html]=man1/openssl-s_client.pod +GENERATE[html/man1/openssl-s_client.html]=man1/openssl-s_client.pod +DEPEND[man/man1/openssl-s_client.1]=man1/openssl-s_client.pod +GENERATE[man/man1/openssl-s_client.1]=man1/openssl-s_client.pod +DEPEND[man1/openssl-s_client.pod]{pod}=man1/openssl-s_client.pod.in +GENERATE[man1/openssl-s_client.pod]=man1/openssl-s_client.pod.in +DEPEND[html/man1/openssl-s_server.html]=man1/openssl-s_server.pod +GENERATE[html/man1/openssl-s_server.html]=man1/openssl-s_server.pod +DEPEND[man/man1/openssl-s_server.1]=man1/openssl-s_server.pod +GENERATE[man/man1/openssl-s_server.1]=man1/openssl-s_server.pod +DEPEND[man1/openssl-s_server.pod]{pod}=man1/openssl-s_server.pod.in +GENERATE[man1/openssl-s_server.pod]=man1/openssl-s_server.pod.in +DEPEND[html/man1/openssl-s_time.html]=man1/openssl-s_time.pod +GENERATE[html/man1/openssl-s_time.html]=man1/openssl-s_time.pod +DEPEND[man/man1/openssl-s_time.1]=man1/openssl-s_time.pod +GENERATE[man/man1/openssl-s_time.1]=man1/openssl-s_time.pod +DEPEND[man1/openssl-s_time.pod]{pod}=man1/openssl-s_time.pod.in +GENERATE[man1/openssl-s_time.pod]=man1/openssl-s_time.pod.in +DEPEND[html/man1/openssl-sess_id.html]=man1/openssl-sess_id.pod +GENERATE[html/man1/openssl-sess_id.html]=man1/openssl-sess_id.pod +DEPEND[man/man1/openssl-sess_id.1]=man1/openssl-sess_id.pod +GENERATE[man/man1/openssl-sess_id.1]=man1/openssl-sess_id.pod +DEPEND[man1/openssl-sess_id.pod]{pod}=man1/openssl-sess_id.pod.in +GENERATE[man1/openssl-sess_id.pod]=man1/openssl-sess_id.pod.in +DEPEND[html/man1/openssl-smime.html]=man1/openssl-smime.pod +GENERATE[html/man1/openssl-smime.html]=man1/openssl-smime.pod +DEPEND[man/man1/openssl-smime.1]=man1/openssl-smime.pod +GENERATE[man/man1/openssl-smime.1]=man1/openssl-smime.pod +DEPEND[man1/openssl-smime.pod]{pod}=man1/openssl-smime.pod.in +GENERATE[man1/openssl-smime.pod]=man1/openssl-smime.pod.in +DEPEND[html/man1/openssl-speed.html]=man1/openssl-speed.pod +GENERATE[html/man1/openssl-speed.html]=man1/openssl-speed.pod +DEPEND[man/man1/openssl-speed.1]=man1/openssl-speed.pod +GENERATE[man/man1/openssl-speed.1]=man1/openssl-speed.pod +DEPEND[man1/openssl-speed.pod]{pod}=man1/openssl-speed.pod.in +GENERATE[man1/openssl-speed.pod]=man1/openssl-speed.pod.in +DEPEND[html/man1/openssl-spkac.html]=man1/openssl-spkac.pod +GENERATE[html/man1/openssl-spkac.html]=man1/openssl-spkac.pod +DEPEND[man/man1/openssl-spkac.1]=man1/openssl-spkac.pod +GENERATE[man/man1/openssl-spkac.1]=man1/openssl-spkac.pod +DEPEND[man1/openssl-spkac.pod]{pod}=man1/openssl-spkac.pod.in +GENERATE[man1/openssl-spkac.pod]=man1/openssl-spkac.pod.in +DEPEND[html/man1/openssl-srp.html]=man1/openssl-srp.pod +GENERATE[html/man1/openssl-srp.html]=man1/openssl-srp.pod +DEPEND[man/man1/openssl-srp.1]=man1/openssl-srp.pod +GENERATE[man/man1/openssl-srp.1]=man1/openssl-srp.pod +DEPEND[man1/openssl-srp.pod]{pod}=man1/openssl-srp.pod.in +GENERATE[man1/openssl-srp.pod]=man1/openssl-srp.pod.in +DEPEND[html/man1/openssl-storeutl.html]=man1/openssl-storeutl.pod +GENERATE[html/man1/openssl-storeutl.html]=man1/openssl-storeutl.pod +DEPEND[man/man1/openssl-storeutl.1]=man1/openssl-storeutl.pod +GENERATE[man/man1/openssl-storeutl.1]=man1/openssl-storeutl.pod +DEPEND[man1/openssl-storeutl.pod]{pod}=man1/openssl-storeutl.pod.in +GENERATE[man1/openssl-storeutl.pod]=man1/openssl-storeutl.pod.in +DEPEND[html/man1/openssl-ts.html]=man1/openssl-ts.pod +GENERATE[html/man1/openssl-ts.html]=man1/openssl-ts.pod +DEPEND[man/man1/openssl-ts.1]=man1/openssl-ts.pod +GENERATE[man/man1/openssl-ts.1]=man1/openssl-ts.pod +DEPEND[man1/openssl-ts.pod]{pod}=man1/openssl-ts.pod.in +GENERATE[man1/openssl-ts.pod]=man1/openssl-ts.pod.in +DEPEND[html/man1/openssl-verification-options.html]=man1/openssl-verification-options.pod +GENERATE[html/man1/openssl-verification-options.html]=man1/openssl-verification-options.pod +DEPEND[man/man1/openssl-verification-options.1]=man1/openssl-verification-options.pod +GENERATE[man/man1/openssl-verification-options.1]=man1/openssl-verification-options.pod +DEPEND[html/man1/openssl-verify.html]=man1/openssl-verify.pod +GENERATE[html/man1/openssl-verify.html]=man1/openssl-verify.pod +DEPEND[man/man1/openssl-verify.1]=man1/openssl-verify.pod +GENERATE[man/man1/openssl-verify.1]=man1/openssl-verify.pod +DEPEND[man1/openssl-verify.pod]{pod}=man1/openssl-verify.pod.in +GENERATE[man1/openssl-verify.pod]=man1/openssl-verify.pod.in +DEPEND[html/man1/openssl-version.html]=man1/openssl-version.pod +GENERATE[html/man1/openssl-version.html]=man1/openssl-version.pod +DEPEND[man/man1/openssl-version.1]=man1/openssl-version.pod +GENERATE[man/man1/openssl-version.1]=man1/openssl-version.pod +DEPEND[man1/openssl-version.pod]{pod}=man1/openssl-version.pod.in +GENERATE[man1/openssl-version.pod]=man1/openssl-version.pod.in +DEPEND[html/man1/openssl-x509.html]=man1/openssl-x509.pod +GENERATE[html/man1/openssl-x509.html]=man1/openssl-x509.pod +DEPEND[man/man1/openssl-x509.1]=man1/openssl-x509.pod +GENERATE[man/man1/openssl-x509.1]=man1/openssl-x509.pod +DEPEND[man1/openssl-x509.pod]{pod}=man1/openssl-x509.pod.in +GENERATE[man1/openssl-x509.pod]=man1/openssl-x509.pod.in +DEPEND[html/man1/openssl.html]=man1/openssl.pod +GENERATE[html/man1/openssl.html]=man1/openssl.pod +DEPEND[man/man1/openssl.1]=man1/openssl.pod +GENERATE[man/man1/openssl.1]=man1/openssl.pod +DEPEND[html/man1/tsget.html]=man1/tsget.pod +GENERATE[html/man1/tsget.html]=man1/tsget.pod +DEPEND[man/man1/tsget.1]=man1/tsget.pod +GENERATE[man/man1/tsget.1]=man1/tsget.pod +IMAGEDOCS[man1]= +HTMLDOCS[man1]=html/man1/CA.pl.html \ +html/man1/openssl-asn1parse.html \ +html/man1/openssl-ca.html \ +html/man1/openssl-ciphers.html \ +html/man1/openssl-cmds.html \ +html/man1/openssl-cmp.html \ +html/man1/openssl-cms.html \ +html/man1/openssl-crl.html \ +html/man1/openssl-crl2pkcs7.html \ +html/man1/openssl-dgst.html \ +html/man1/openssl-dhparam.html \ +html/man1/openssl-dsa.html \ +html/man1/openssl-dsaparam.html \ +html/man1/openssl-ec.html \ +html/man1/openssl-ecparam.html \ +html/man1/openssl-enc.html \ +html/man1/openssl-engine.html \ +html/man1/openssl-errstr.html \ +html/man1/openssl-fipsinstall.html \ +html/man1/openssl-format-options.html \ +html/man1/openssl-gendsa.html \ +html/man1/openssl-genpkey.html \ +html/man1/openssl-genrsa.html \ +html/man1/openssl-info.html \ +html/man1/openssl-kdf.html \ +html/man1/openssl-list.html \ +html/man1/openssl-mac.html \ +html/man1/openssl-namedisplay-options.html \ +html/man1/openssl-nseq.html \ +html/man1/openssl-ocsp.html \ +html/man1/openssl-passphrase-options.html \ +html/man1/openssl-passwd.html \ +html/man1/openssl-pkcs12.html \ +html/man1/openssl-pkcs7.html \ +html/man1/openssl-pkcs8.html \ +html/man1/openssl-pkey.html \ +html/man1/openssl-pkeyparam.html \ +html/man1/openssl-pkeyutl.html \ +html/man1/openssl-prime.html \ +html/man1/openssl-rand.html \ +html/man1/openssl-rehash.html \ +html/man1/openssl-req.html \ +html/man1/openssl-rsa.html \ +html/man1/openssl-rsautl.html \ +html/man1/openssl-s_client.html \ +html/man1/openssl-s_server.html \ +html/man1/openssl-s_time.html \ +html/man1/openssl-sess_id.html \ +html/man1/openssl-smime.html \ +html/man1/openssl-speed.html \ +html/man1/openssl-spkac.html \ +html/man1/openssl-srp.html \ +html/man1/openssl-storeutl.html \ +html/man1/openssl-ts.html \ +html/man1/openssl-verification-options.html \ +html/man1/openssl-verify.html \ +html/man1/openssl-version.html \ +html/man1/openssl-x509.html \ +html/man1/openssl.html \ +html/man1/tsget.html +MANDOCS[man1]=man/man1/CA.pl.1 \ +man/man1/openssl-asn1parse.1 \ +man/man1/openssl-ca.1 \ +man/man1/openssl-ciphers.1 \ +man/man1/openssl-cmds.1 \ +man/man1/openssl-cmp.1 \ +man/man1/openssl-cms.1 \ +man/man1/openssl-crl.1 \ +man/man1/openssl-crl2pkcs7.1 \ +man/man1/openssl-dgst.1 \ +man/man1/openssl-dhparam.1 \ +man/man1/openssl-dsa.1 \ +man/man1/openssl-dsaparam.1 \ +man/man1/openssl-ec.1 \ +man/man1/openssl-ecparam.1 \ +man/man1/openssl-enc.1 \ +man/man1/openssl-engine.1 \ +man/man1/openssl-errstr.1 \ +man/man1/openssl-fipsinstall.1 \ +man/man1/openssl-format-options.1 \ +man/man1/openssl-gendsa.1 \ +man/man1/openssl-genpkey.1 \ +man/man1/openssl-genrsa.1 \ +man/man1/openssl-info.1 \ +man/man1/openssl-kdf.1 \ +man/man1/openssl-list.1 \ +man/man1/openssl-mac.1 \ +man/man1/openssl-namedisplay-options.1 \ +man/man1/openssl-nseq.1 \ +man/man1/openssl-ocsp.1 \ +man/man1/openssl-passphrase-options.1 \ +man/man1/openssl-passwd.1 \ +man/man1/openssl-pkcs12.1 \ +man/man1/openssl-pkcs7.1 \ +man/man1/openssl-pkcs8.1 \ +man/man1/openssl-pkey.1 \ +man/man1/openssl-pkeyparam.1 \ +man/man1/openssl-pkeyutl.1 \ +man/man1/openssl-prime.1 \ +man/man1/openssl-rand.1 \ +man/man1/openssl-rehash.1 \ +man/man1/openssl-req.1 \ +man/man1/openssl-rsa.1 \ +man/man1/openssl-rsautl.1 \ +man/man1/openssl-s_client.1 \ +man/man1/openssl-s_server.1 \ +man/man1/openssl-s_time.1 \ +man/man1/openssl-sess_id.1 \ +man/man1/openssl-smime.1 \ +man/man1/openssl-speed.1 \ +man/man1/openssl-spkac.1 \ +man/man1/openssl-srp.1 \ +man/man1/openssl-storeutl.1 \ +man/man1/openssl-ts.1 \ +man/man1/openssl-verification-options.1 \ +man/man1/openssl-verify.1 \ +man/man1/openssl-version.1 \ +man/man1/openssl-x509.1 \ +man/man1/openssl.1 \ +man/man1/tsget.1 +DEPEND[html/man3/ADMISSIONS.html]=man3/ADMISSIONS.pod +GENERATE[html/man3/ADMISSIONS.html]=man3/ADMISSIONS.pod +DEPEND[man/man3/ADMISSIONS.3]=man3/ADMISSIONS.pod +GENERATE[man/man3/ADMISSIONS.3]=man3/ADMISSIONS.pod +DEPEND[html/man3/ASN1_EXTERN_FUNCS.html]=man3/ASN1_EXTERN_FUNCS.pod +GENERATE[html/man3/ASN1_EXTERN_FUNCS.html]=man3/ASN1_EXTERN_FUNCS.pod +DEPEND[man/man3/ASN1_EXTERN_FUNCS.3]=man3/ASN1_EXTERN_FUNCS.pod +GENERATE[man/man3/ASN1_EXTERN_FUNCS.3]=man3/ASN1_EXTERN_FUNCS.pod +DEPEND[html/man3/ASN1_INTEGER_get_int64.html]=man3/ASN1_INTEGER_get_int64.pod +GENERATE[html/man3/ASN1_INTEGER_get_int64.html]=man3/ASN1_INTEGER_get_int64.pod +DEPEND[man/man3/ASN1_INTEGER_get_int64.3]=man3/ASN1_INTEGER_get_int64.pod +GENERATE[man/man3/ASN1_INTEGER_get_int64.3]=man3/ASN1_INTEGER_get_int64.pod +DEPEND[html/man3/ASN1_INTEGER_new.html]=man3/ASN1_INTEGER_new.pod +GENERATE[html/man3/ASN1_INTEGER_new.html]=man3/ASN1_INTEGER_new.pod +DEPEND[man/man3/ASN1_INTEGER_new.3]=man3/ASN1_INTEGER_new.pod +GENERATE[man/man3/ASN1_INTEGER_new.3]=man3/ASN1_INTEGER_new.pod +DEPEND[html/man3/ASN1_ITEM_lookup.html]=man3/ASN1_ITEM_lookup.pod +GENERATE[html/man3/ASN1_ITEM_lookup.html]=man3/ASN1_ITEM_lookup.pod +DEPEND[man/man3/ASN1_ITEM_lookup.3]=man3/ASN1_ITEM_lookup.pod +GENERATE[man/man3/ASN1_ITEM_lookup.3]=man3/ASN1_ITEM_lookup.pod +DEPEND[html/man3/ASN1_OBJECT_new.html]=man3/ASN1_OBJECT_new.pod +GENERATE[html/man3/ASN1_OBJECT_new.html]=man3/ASN1_OBJECT_new.pod +DEPEND[man/man3/ASN1_OBJECT_new.3]=man3/ASN1_OBJECT_new.pod +GENERATE[man/man3/ASN1_OBJECT_new.3]=man3/ASN1_OBJECT_new.pod +DEPEND[html/man3/ASN1_STRING_TABLE_add.html]=man3/ASN1_STRING_TABLE_add.pod +GENERATE[html/man3/ASN1_STRING_TABLE_add.html]=man3/ASN1_STRING_TABLE_add.pod +DEPEND[man/man3/ASN1_STRING_TABLE_add.3]=man3/ASN1_STRING_TABLE_add.pod +GENERATE[man/man3/ASN1_STRING_TABLE_add.3]=man3/ASN1_STRING_TABLE_add.pod +DEPEND[html/man3/ASN1_STRING_length.html]=man3/ASN1_STRING_length.pod +GENERATE[html/man3/ASN1_STRING_length.html]=man3/ASN1_STRING_length.pod +DEPEND[man/man3/ASN1_STRING_length.3]=man3/ASN1_STRING_length.pod +GENERATE[man/man3/ASN1_STRING_length.3]=man3/ASN1_STRING_length.pod +DEPEND[html/man3/ASN1_STRING_new.html]=man3/ASN1_STRING_new.pod +GENERATE[html/man3/ASN1_STRING_new.html]=man3/ASN1_STRING_new.pod +DEPEND[man/man3/ASN1_STRING_new.3]=man3/ASN1_STRING_new.pod +GENERATE[man/man3/ASN1_STRING_new.3]=man3/ASN1_STRING_new.pod +DEPEND[html/man3/ASN1_STRING_print_ex.html]=man3/ASN1_STRING_print_ex.pod +GENERATE[html/man3/ASN1_STRING_print_ex.html]=man3/ASN1_STRING_print_ex.pod +DEPEND[man/man3/ASN1_STRING_print_ex.3]=man3/ASN1_STRING_print_ex.pod +GENERATE[man/man3/ASN1_STRING_print_ex.3]=man3/ASN1_STRING_print_ex.pod +DEPEND[html/man3/ASN1_TIME_set.html]=man3/ASN1_TIME_set.pod +GENERATE[html/man3/ASN1_TIME_set.html]=man3/ASN1_TIME_set.pod +DEPEND[man/man3/ASN1_TIME_set.3]=man3/ASN1_TIME_set.pod +GENERATE[man/man3/ASN1_TIME_set.3]=man3/ASN1_TIME_set.pod +DEPEND[html/man3/ASN1_TYPE_get.html]=man3/ASN1_TYPE_get.pod +GENERATE[html/man3/ASN1_TYPE_get.html]=man3/ASN1_TYPE_get.pod +DEPEND[man/man3/ASN1_TYPE_get.3]=man3/ASN1_TYPE_get.pod +GENERATE[man/man3/ASN1_TYPE_get.3]=man3/ASN1_TYPE_get.pod +DEPEND[html/man3/ASN1_aux_cb.html]=man3/ASN1_aux_cb.pod +GENERATE[html/man3/ASN1_aux_cb.html]=man3/ASN1_aux_cb.pod +DEPEND[man/man3/ASN1_aux_cb.3]=man3/ASN1_aux_cb.pod +GENERATE[man/man3/ASN1_aux_cb.3]=man3/ASN1_aux_cb.pod +DEPEND[html/man3/ASN1_generate_nconf.html]=man3/ASN1_generate_nconf.pod +GENERATE[html/man3/ASN1_generate_nconf.html]=man3/ASN1_generate_nconf.pod +DEPEND[man/man3/ASN1_generate_nconf.3]=man3/ASN1_generate_nconf.pod +GENERATE[man/man3/ASN1_generate_nconf.3]=man3/ASN1_generate_nconf.pod +DEPEND[html/man3/ASN1_item_d2i_bio.html]=man3/ASN1_item_d2i_bio.pod +GENERATE[html/man3/ASN1_item_d2i_bio.html]=man3/ASN1_item_d2i_bio.pod +DEPEND[man/man3/ASN1_item_d2i_bio.3]=man3/ASN1_item_d2i_bio.pod +GENERATE[man/man3/ASN1_item_d2i_bio.3]=man3/ASN1_item_d2i_bio.pod +DEPEND[html/man3/ASN1_item_new.html]=man3/ASN1_item_new.pod +GENERATE[html/man3/ASN1_item_new.html]=man3/ASN1_item_new.pod +DEPEND[man/man3/ASN1_item_new.3]=man3/ASN1_item_new.pod +GENERATE[man/man3/ASN1_item_new.3]=man3/ASN1_item_new.pod +DEPEND[html/man3/ASN1_item_sign.html]=man3/ASN1_item_sign.pod +GENERATE[html/man3/ASN1_item_sign.html]=man3/ASN1_item_sign.pod +DEPEND[man/man3/ASN1_item_sign.3]=man3/ASN1_item_sign.pod +GENERATE[man/man3/ASN1_item_sign.3]=man3/ASN1_item_sign.pod +DEPEND[html/man3/ASYNC_WAIT_CTX_new.html]=man3/ASYNC_WAIT_CTX_new.pod +GENERATE[html/man3/ASYNC_WAIT_CTX_new.html]=man3/ASYNC_WAIT_CTX_new.pod +DEPEND[man/man3/ASYNC_WAIT_CTX_new.3]=man3/ASYNC_WAIT_CTX_new.pod +GENERATE[man/man3/ASYNC_WAIT_CTX_new.3]=man3/ASYNC_WAIT_CTX_new.pod +DEPEND[html/man3/ASYNC_start_job.html]=man3/ASYNC_start_job.pod +GENERATE[html/man3/ASYNC_start_job.html]=man3/ASYNC_start_job.pod +DEPEND[man/man3/ASYNC_start_job.3]=man3/ASYNC_start_job.pod +GENERATE[man/man3/ASYNC_start_job.3]=man3/ASYNC_start_job.pod +DEPEND[html/man3/BF_encrypt.html]=man3/BF_encrypt.pod +GENERATE[html/man3/BF_encrypt.html]=man3/BF_encrypt.pod +DEPEND[man/man3/BF_encrypt.3]=man3/BF_encrypt.pod +GENERATE[man/man3/BF_encrypt.3]=man3/BF_encrypt.pod +DEPEND[html/man3/BIO_ADDR.html]=man3/BIO_ADDR.pod +GENERATE[html/man3/BIO_ADDR.html]=man3/BIO_ADDR.pod +DEPEND[man/man3/BIO_ADDR.3]=man3/BIO_ADDR.pod +GENERATE[man/man3/BIO_ADDR.3]=man3/BIO_ADDR.pod +DEPEND[html/man3/BIO_ADDRINFO.html]=man3/BIO_ADDRINFO.pod +GENERATE[html/man3/BIO_ADDRINFO.html]=man3/BIO_ADDRINFO.pod +DEPEND[man/man3/BIO_ADDRINFO.3]=man3/BIO_ADDRINFO.pod +GENERATE[man/man3/BIO_ADDRINFO.3]=man3/BIO_ADDRINFO.pod +DEPEND[html/man3/BIO_connect.html]=man3/BIO_connect.pod +GENERATE[html/man3/BIO_connect.html]=man3/BIO_connect.pod +DEPEND[man/man3/BIO_connect.3]=man3/BIO_connect.pod +GENERATE[man/man3/BIO_connect.3]=man3/BIO_connect.pod +DEPEND[html/man3/BIO_ctrl.html]=man3/BIO_ctrl.pod +GENERATE[html/man3/BIO_ctrl.html]=man3/BIO_ctrl.pod +DEPEND[man/man3/BIO_ctrl.3]=man3/BIO_ctrl.pod +GENERATE[man/man3/BIO_ctrl.3]=man3/BIO_ctrl.pod +DEPEND[html/man3/BIO_f_base64.html]=man3/BIO_f_base64.pod +GENERATE[html/man3/BIO_f_base64.html]=man3/BIO_f_base64.pod +DEPEND[man/man3/BIO_f_base64.3]=man3/BIO_f_base64.pod +GENERATE[man/man3/BIO_f_base64.3]=man3/BIO_f_base64.pod +DEPEND[html/man3/BIO_f_buffer.html]=man3/BIO_f_buffer.pod +GENERATE[html/man3/BIO_f_buffer.html]=man3/BIO_f_buffer.pod +DEPEND[man/man3/BIO_f_buffer.3]=man3/BIO_f_buffer.pod +GENERATE[man/man3/BIO_f_buffer.3]=man3/BIO_f_buffer.pod +DEPEND[html/man3/BIO_f_cipher.html]=man3/BIO_f_cipher.pod +GENERATE[html/man3/BIO_f_cipher.html]=man3/BIO_f_cipher.pod +DEPEND[man/man3/BIO_f_cipher.3]=man3/BIO_f_cipher.pod +GENERATE[man/man3/BIO_f_cipher.3]=man3/BIO_f_cipher.pod +DEPEND[html/man3/BIO_f_md.html]=man3/BIO_f_md.pod +GENERATE[html/man3/BIO_f_md.html]=man3/BIO_f_md.pod +DEPEND[man/man3/BIO_f_md.3]=man3/BIO_f_md.pod +GENERATE[man/man3/BIO_f_md.3]=man3/BIO_f_md.pod +DEPEND[html/man3/BIO_f_null.html]=man3/BIO_f_null.pod +GENERATE[html/man3/BIO_f_null.html]=man3/BIO_f_null.pod +DEPEND[man/man3/BIO_f_null.3]=man3/BIO_f_null.pod +GENERATE[man/man3/BIO_f_null.3]=man3/BIO_f_null.pod +DEPEND[html/man3/BIO_f_prefix.html]=man3/BIO_f_prefix.pod +GENERATE[html/man3/BIO_f_prefix.html]=man3/BIO_f_prefix.pod +DEPEND[man/man3/BIO_f_prefix.3]=man3/BIO_f_prefix.pod +GENERATE[man/man3/BIO_f_prefix.3]=man3/BIO_f_prefix.pod +DEPEND[html/man3/BIO_f_readbuffer.html]=man3/BIO_f_readbuffer.pod +GENERATE[html/man3/BIO_f_readbuffer.html]=man3/BIO_f_readbuffer.pod +DEPEND[man/man3/BIO_f_readbuffer.3]=man3/BIO_f_readbuffer.pod +GENERATE[man/man3/BIO_f_readbuffer.3]=man3/BIO_f_readbuffer.pod +DEPEND[html/man3/BIO_f_ssl.html]=man3/BIO_f_ssl.pod +GENERATE[html/man3/BIO_f_ssl.html]=man3/BIO_f_ssl.pod +DEPEND[man/man3/BIO_f_ssl.3]=man3/BIO_f_ssl.pod +GENERATE[man/man3/BIO_f_ssl.3]=man3/BIO_f_ssl.pod +DEPEND[html/man3/BIO_find_type.html]=man3/BIO_find_type.pod +GENERATE[html/man3/BIO_find_type.html]=man3/BIO_find_type.pod +DEPEND[man/man3/BIO_find_type.3]=man3/BIO_find_type.pod +GENERATE[man/man3/BIO_find_type.3]=man3/BIO_find_type.pod +DEPEND[html/man3/BIO_get_data.html]=man3/BIO_get_data.pod +GENERATE[html/man3/BIO_get_data.html]=man3/BIO_get_data.pod +DEPEND[man/man3/BIO_get_data.3]=man3/BIO_get_data.pod +GENERATE[man/man3/BIO_get_data.3]=man3/BIO_get_data.pod +DEPEND[html/man3/BIO_get_ex_new_index.html]=man3/BIO_get_ex_new_index.pod +GENERATE[html/man3/BIO_get_ex_new_index.html]=man3/BIO_get_ex_new_index.pod +DEPEND[man/man3/BIO_get_ex_new_index.3]=man3/BIO_get_ex_new_index.pod +GENERATE[man/man3/BIO_get_ex_new_index.3]=man3/BIO_get_ex_new_index.pod +DEPEND[html/man3/BIO_meth_new.html]=man3/BIO_meth_new.pod +GENERATE[html/man3/BIO_meth_new.html]=man3/BIO_meth_new.pod +DEPEND[man/man3/BIO_meth_new.3]=man3/BIO_meth_new.pod +GENERATE[man/man3/BIO_meth_new.3]=man3/BIO_meth_new.pod +DEPEND[html/man3/BIO_new.html]=man3/BIO_new.pod +GENERATE[html/man3/BIO_new.html]=man3/BIO_new.pod +DEPEND[man/man3/BIO_new.3]=man3/BIO_new.pod +GENERATE[man/man3/BIO_new.3]=man3/BIO_new.pod +DEPEND[html/man3/BIO_new_CMS.html]=man3/BIO_new_CMS.pod +GENERATE[html/man3/BIO_new_CMS.html]=man3/BIO_new_CMS.pod +DEPEND[man/man3/BIO_new_CMS.3]=man3/BIO_new_CMS.pod +GENERATE[man/man3/BIO_new_CMS.3]=man3/BIO_new_CMS.pod +DEPEND[html/man3/BIO_parse_hostserv.html]=man3/BIO_parse_hostserv.pod +GENERATE[html/man3/BIO_parse_hostserv.html]=man3/BIO_parse_hostserv.pod +DEPEND[man/man3/BIO_parse_hostserv.3]=man3/BIO_parse_hostserv.pod +GENERATE[man/man3/BIO_parse_hostserv.3]=man3/BIO_parse_hostserv.pod +DEPEND[html/man3/BIO_printf.html]=man3/BIO_printf.pod +GENERATE[html/man3/BIO_printf.html]=man3/BIO_printf.pod +DEPEND[man/man3/BIO_printf.3]=man3/BIO_printf.pod +GENERATE[man/man3/BIO_printf.3]=man3/BIO_printf.pod +DEPEND[html/man3/BIO_push.html]=man3/BIO_push.pod +GENERATE[html/man3/BIO_push.html]=man3/BIO_push.pod +DEPEND[man/man3/BIO_push.3]=man3/BIO_push.pod +GENERATE[man/man3/BIO_push.3]=man3/BIO_push.pod +DEPEND[html/man3/BIO_read.html]=man3/BIO_read.pod +GENERATE[html/man3/BIO_read.html]=man3/BIO_read.pod +DEPEND[man/man3/BIO_read.3]=man3/BIO_read.pod +GENERATE[man/man3/BIO_read.3]=man3/BIO_read.pod +DEPEND[html/man3/BIO_s_accept.html]=man3/BIO_s_accept.pod +GENERATE[html/man3/BIO_s_accept.html]=man3/BIO_s_accept.pod +DEPEND[man/man3/BIO_s_accept.3]=man3/BIO_s_accept.pod +GENERATE[man/man3/BIO_s_accept.3]=man3/BIO_s_accept.pod +DEPEND[html/man3/BIO_s_bio.html]=man3/BIO_s_bio.pod +GENERATE[html/man3/BIO_s_bio.html]=man3/BIO_s_bio.pod +DEPEND[man/man3/BIO_s_bio.3]=man3/BIO_s_bio.pod +GENERATE[man/man3/BIO_s_bio.3]=man3/BIO_s_bio.pod +DEPEND[html/man3/BIO_s_connect.html]=man3/BIO_s_connect.pod +GENERATE[html/man3/BIO_s_connect.html]=man3/BIO_s_connect.pod +DEPEND[man/man3/BIO_s_connect.3]=man3/BIO_s_connect.pod +GENERATE[man/man3/BIO_s_connect.3]=man3/BIO_s_connect.pod +DEPEND[html/man3/BIO_s_core.html]=man3/BIO_s_core.pod +GENERATE[html/man3/BIO_s_core.html]=man3/BIO_s_core.pod +DEPEND[man/man3/BIO_s_core.3]=man3/BIO_s_core.pod +GENERATE[man/man3/BIO_s_core.3]=man3/BIO_s_core.pod +DEPEND[html/man3/BIO_s_datagram.html]=man3/BIO_s_datagram.pod +GENERATE[html/man3/BIO_s_datagram.html]=man3/BIO_s_datagram.pod +DEPEND[man/man3/BIO_s_datagram.3]=man3/BIO_s_datagram.pod +GENERATE[man/man3/BIO_s_datagram.3]=man3/BIO_s_datagram.pod +DEPEND[html/man3/BIO_s_fd.html]=man3/BIO_s_fd.pod +GENERATE[html/man3/BIO_s_fd.html]=man3/BIO_s_fd.pod +DEPEND[man/man3/BIO_s_fd.3]=man3/BIO_s_fd.pod +GENERATE[man/man3/BIO_s_fd.3]=man3/BIO_s_fd.pod +DEPEND[html/man3/BIO_s_file.html]=man3/BIO_s_file.pod +GENERATE[html/man3/BIO_s_file.html]=man3/BIO_s_file.pod +DEPEND[man/man3/BIO_s_file.3]=man3/BIO_s_file.pod +GENERATE[man/man3/BIO_s_file.3]=man3/BIO_s_file.pod +DEPEND[html/man3/BIO_s_mem.html]=man3/BIO_s_mem.pod +GENERATE[html/man3/BIO_s_mem.html]=man3/BIO_s_mem.pod +DEPEND[man/man3/BIO_s_mem.3]=man3/BIO_s_mem.pod +GENERATE[man/man3/BIO_s_mem.3]=man3/BIO_s_mem.pod +DEPEND[html/man3/BIO_s_null.html]=man3/BIO_s_null.pod +GENERATE[html/man3/BIO_s_null.html]=man3/BIO_s_null.pod +DEPEND[man/man3/BIO_s_null.3]=man3/BIO_s_null.pod +GENERATE[man/man3/BIO_s_null.3]=man3/BIO_s_null.pod +DEPEND[html/man3/BIO_s_socket.html]=man3/BIO_s_socket.pod +GENERATE[html/man3/BIO_s_socket.html]=man3/BIO_s_socket.pod +DEPEND[man/man3/BIO_s_socket.3]=man3/BIO_s_socket.pod +GENERATE[man/man3/BIO_s_socket.3]=man3/BIO_s_socket.pod +DEPEND[html/man3/BIO_set_callback.html]=man3/BIO_set_callback.pod +GENERATE[html/man3/BIO_set_callback.html]=man3/BIO_set_callback.pod +DEPEND[man/man3/BIO_set_callback.3]=man3/BIO_set_callback.pod +GENERATE[man/man3/BIO_set_callback.3]=man3/BIO_set_callback.pod +DEPEND[html/man3/BIO_should_retry.html]=man3/BIO_should_retry.pod +GENERATE[html/man3/BIO_should_retry.html]=man3/BIO_should_retry.pod +DEPEND[man/man3/BIO_should_retry.3]=man3/BIO_should_retry.pod +GENERATE[man/man3/BIO_should_retry.3]=man3/BIO_should_retry.pod +DEPEND[html/man3/BIO_socket_wait.html]=man3/BIO_socket_wait.pod +GENERATE[html/man3/BIO_socket_wait.html]=man3/BIO_socket_wait.pod +DEPEND[man/man3/BIO_socket_wait.3]=man3/BIO_socket_wait.pod +GENERATE[man/man3/BIO_socket_wait.3]=man3/BIO_socket_wait.pod +DEPEND[html/man3/BN_BLINDING_new.html]=man3/BN_BLINDING_new.pod +GENERATE[html/man3/BN_BLINDING_new.html]=man3/BN_BLINDING_new.pod +DEPEND[man/man3/BN_BLINDING_new.3]=man3/BN_BLINDING_new.pod +GENERATE[man/man3/BN_BLINDING_new.3]=man3/BN_BLINDING_new.pod +DEPEND[html/man3/BN_CTX_new.html]=man3/BN_CTX_new.pod +GENERATE[html/man3/BN_CTX_new.html]=man3/BN_CTX_new.pod +DEPEND[man/man3/BN_CTX_new.3]=man3/BN_CTX_new.pod +GENERATE[man/man3/BN_CTX_new.3]=man3/BN_CTX_new.pod +DEPEND[html/man3/BN_CTX_start.html]=man3/BN_CTX_start.pod +GENERATE[html/man3/BN_CTX_start.html]=man3/BN_CTX_start.pod +DEPEND[man/man3/BN_CTX_start.3]=man3/BN_CTX_start.pod +GENERATE[man/man3/BN_CTX_start.3]=man3/BN_CTX_start.pod +DEPEND[html/man3/BN_add.html]=man3/BN_add.pod +GENERATE[html/man3/BN_add.html]=man3/BN_add.pod +DEPEND[man/man3/BN_add.3]=man3/BN_add.pod +GENERATE[man/man3/BN_add.3]=man3/BN_add.pod +DEPEND[html/man3/BN_add_word.html]=man3/BN_add_word.pod +GENERATE[html/man3/BN_add_word.html]=man3/BN_add_word.pod +DEPEND[man/man3/BN_add_word.3]=man3/BN_add_word.pod +GENERATE[man/man3/BN_add_word.3]=man3/BN_add_word.pod +DEPEND[html/man3/BN_bn2bin.html]=man3/BN_bn2bin.pod +GENERATE[html/man3/BN_bn2bin.html]=man3/BN_bn2bin.pod +DEPEND[man/man3/BN_bn2bin.3]=man3/BN_bn2bin.pod +GENERATE[man/man3/BN_bn2bin.3]=man3/BN_bn2bin.pod +DEPEND[html/man3/BN_cmp.html]=man3/BN_cmp.pod +GENERATE[html/man3/BN_cmp.html]=man3/BN_cmp.pod +DEPEND[man/man3/BN_cmp.3]=man3/BN_cmp.pod +GENERATE[man/man3/BN_cmp.3]=man3/BN_cmp.pod +DEPEND[html/man3/BN_copy.html]=man3/BN_copy.pod +GENERATE[html/man3/BN_copy.html]=man3/BN_copy.pod +DEPEND[man/man3/BN_copy.3]=man3/BN_copy.pod +GENERATE[man/man3/BN_copy.3]=man3/BN_copy.pod +DEPEND[html/man3/BN_generate_prime.html]=man3/BN_generate_prime.pod +GENERATE[html/man3/BN_generate_prime.html]=man3/BN_generate_prime.pod +DEPEND[man/man3/BN_generate_prime.3]=man3/BN_generate_prime.pod +GENERATE[man/man3/BN_generate_prime.3]=man3/BN_generate_prime.pod +DEPEND[html/man3/BN_mod_exp_mont.html]=man3/BN_mod_exp_mont.pod +GENERATE[html/man3/BN_mod_exp_mont.html]=man3/BN_mod_exp_mont.pod +DEPEND[man/man3/BN_mod_exp_mont.3]=man3/BN_mod_exp_mont.pod +GENERATE[man/man3/BN_mod_exp_mont.3]=man3/BN_mod_exp_mont.pod +DEPEND[html/man3/BN_mod_inverse.html]=man3/BN_mod_inverse.pod +GENERATE[html/man3/BN_mod_inverse.html]=man3/BN_mod_inverse.pod +DEPEND[man/man3/BN_mod_inverse.3]=man3/BN_mod_inverse.pod +GENERATE[man/man3/BN_mod_inverse.3]=man3/BN_mod_inverse.pod +DEPEND[html/man3/BN_mod_mul_montgomery.html]=man3/BN_mod_mul_montgomery.pod +GENERATE[html/man3/BN_mod_mul_montgomery.html]=man3/BN_mod_mul_montgomery.pod +DEPEND[man/man3/BN_mod_mul_montgomery.3]=man3/BN_mod_mul_montgomery.pod +GENERATE[man/man3/BN_mod_mul_montgomery.3]=man3/BN_mod_mul_montgomery.pod +DEPEND[html/man3/BN_mod_mul_reciprocal.html]=man3/BN_mod_mul_reciprocal.pod +GENERATE[html/man3/BN_mod_mul_reciprocal.html]=man3/BN_mod_mul_reciprocal.pod +DEPEND[man/man3/BN_mod_mul_reciprocal.3]=man3/BN_mod_mul_reciprocal.pod +GENERATE[man/man3/BN_mod_mul_reciprocal.3]=man3/BN_mod_mul_reciprocal.pod +DEPEND[html/man3/BN_new.html]=man3/BN_new.pod +GENERATE[html/man3/BN_new.html]=man3/BN_new.pod +DEPEND[man/man3/BN_new.3]=man3/BN_new.pod +GENERATE[man/man3/BN_new.3]=man3/BN_new.pod +DEPEND[html/man3/BN_num_bytes.html]=man3/BN_num_bytes.pod +GENERATE[html/man3/BN_num_bytes.html]=man3/BN_num_bytes.pod +DEPEND[man/man3/BN_num_bytes.3]=man3/BN_num_bytes.pod +GENERATE[man/man3/BN_num_bytes.3]=man3/BN_num_bytes.pod +DEPEND[html/man3/BN_rand.html]=man3/BN_rand.pod +GENERATE[html/man3/BN_rand.html]=man3/BN_rand.pod +DEPEND[man/man3/BN_rand.3]=man3/BN_rand.pod +GENERATE[man/man3/BN_rand.3]=man3/BN_rand.pod +DEPEND[html/man3/BN_security_bits.html]=man3/BN_security_bits.pod +GENERATE[html/man3/BN_security_bits.html]=man3/BN_security_bits.pod +DEPEND[man/man3/BN_security_bits.3]=man3/BN_security_bits.pod +GENERATE[man/man3/BN_security_bits.3]=man3/BN_security_bits.pod +DEPEND[html/man3/BN_set_bit.html]=man3/BN_set_bit.pod +GENERATE[html/man3/BN_set_bit.html]=man3/BN_set_bit.pod +DEPEND[man/man3/BN_set_bit.3]=man3/BN_set_bit.pod +GENERATE[man/man3/BN_set_bit.3]=man3/BN_set_bit.pod +DEPEND[html/man3/BN_swap.html]=man3/BN_swap.pod +GENERATE[html/man3/BN_swap.html]=man3/BN_swap.pod +DEPEND[man/man3/BN_swap.3]=man3/BN_swap.pod +GENERATE[man/man3/BN_swap.3]=man3/BN_swap.pod +DEPEND[html/man3/BN_zero.html]=man3/BN_zero.pod +GENERATE[html/man3/BN_zero.html]=man3/BN_zero.pod +DEPEND[man/man3/BN_zero.3]=man3/BN_zero.pod +GENERATE[man/man3/BN_zero.3]=man3/BN_zero.pod +DEPEND[html/man3/BUF_MEM_new.html]=man3/BUF_MEM_new.pod +GENERATE[html/man3/BUF_MEM_new.html]=man3/BUF_MEM_new.pod +DEPEND[man/man3/BUF_MEM_new.3]=man3/BUF_MEM_new.pod +GENERATE[man/man3/BUF_MEM_new.3]=man3/BUF_MEM_new.pod +DEPEND[html/man3/CMS_EncryptedData_decrypt.html]=man3/CMS_EncryptedData_decrypt.pod +GENERATE[html/man3/CMS_EncryptedData_decrypt.html]=man3/CMS_EncryptedData_decrypt.pod +DEPEND[man/man3/CMS_EncryptedData_decrypt.3]=man3/CMS_EncryptedData_decrypt.pod +GENERATE[man/man3/CMS_EncryptedData_decrypt.3]=man3/CMS_EncryptedData_decrypt.pod +DEPEND[html/man3/CMS_EncryptedData_encrypt.html]=man3/CMS_EncryptedData_encrypt.pod +GENERATE[html/man3/CMS_EncryptedData_encrypt.html]=man3/CMS_EncryptedData_encrypt.pod +DEPEND[man/man3/CMS_EncryptedData_encrypt.3]=man3/CMS_EncryptedData_encrypt.pod +GENERATE[man/man3/CMS_EncryptedData_encrypt.3]=man3/CMS_EncryptedData_encrypt.pod +DEPEND[html/man3/CMS_EnvelopedData_create.html]=man3/CMS_EnvelopedData_create.pod +GENERATE[html/man3/CMS_EnvelopedData_create.html]=man3/CMS_EnvelopedData_create.pod +DEPEND[man/man3/CMS_EnvelopedData_create.3]=man3/CMS_EnvelopedData_create.pod +GENERATE[man/man3/CMS_EnvelopedData_create.3]=man3/CMS_EnvelopedData_create.pod +DEPEND[html/man3/CMS_add0_cert.html]=man3/CMS_add0_cert.pod +GENERATE[html/man3/CMS_add0_cert.html]=man3/CMS_add0_cert.pod +DEPEND[man/man3/CMS_add0_cert.3]=man3/CMS_add0_cert.pod +GENERATE[man/man3/CMS_add0_cert.3]=man3/CMS_add0_cert.pod +DEPEND[html/man3/CMS_add1_recipient_cert.html]=man3/CMS_add1_recipient_cert.pod +GENERATE[html/man3/CMS_add1_recipient_cert.html]=man3/CMS_add1_recipient_cert.pod +DEPEND[man/man3/CMS_add1_recipient_cert.3]=man3/CMS_add1_recipient_cert.pod +GENERATE[man/man3/CMS_add1_recipient_cert.3]=man3/CMS_add1_recipient_cert.pod +DEPEND[html/man3/CMS_add1_signer.html]=man3/CMS_add1_signer.pod +GENERATE[html/man3/CMS_add1_signer.html]=man3/CMS_add1_signer.pod +DEPEND[man/man3/CMS_add1_signer.3]=man3/CMS_add1_signer.pod +GENERATE[man/man3/CMS_add1_signer.3]=man3/CMS_add1_signer.pod +DEPEND[html/man3/CMS_compress.html]=man3/CMS_compress.pod +GENERATE[html/man3/CMS_compress.html]=man3/CMS_compress.pod +DEPEND[man/man3/CMS_compress.3]=man3/CMS_compress.pod +GENERATE[man/man3/CMS_compress.3]=man3/CMS_compress.pod +DEPEND[html/man3/CMS_data_create.html]=man3/CMS_data_create.pod +GENERATE[html/man3/CMS_data_create.html]=man3/CMS_data_create.pod +DEPEND[man/man3/CMS_data_create.3]=man3/CMS_data_create.pod +GENERATE[man/man3/CMS_data_create.3]=man3/CMS_data_create.pod +DEPEND[html/man3/CMS_decrypt.html]=man3/CMS_decrypt.pod +GENERATE[html/man3/CMS_decrypt.html]=man3/CMS_decrypt.pod +DEPEND[man/man3/CMS_decrypt.3]=man3/CMS_decrypt.pod +GENERATE[man/man3/CMS_decrypt.3]=man3/CMS_decrypt.pod +DEPEND[html/man3/CMS_digest_create.html]=man3/CMS_digest_create.pod +GENERATE[html/man3/CMS_digest_create.html]=man3/CMS_digest_create.pod +DEPEND[man/man3/CMS_digest_create.3]=man3/CMS_digest_create.pod +GENERATE[man/man3/CMS_digest_create.3]=man3/CMS_digest_create.pod +DEPEND[html/man3/CMS_encrypt.html]=man3/CMS_encrypt.pod +GENERATE[html/man3/CMS_encrypt.html]=man3/CMS_encrypt.pod +DEPEND[man/man3/CMS_encrypt.3]=man3/CMS_encrypt.pod +GENERATE[man/man3/CMS_encrypt.3]=man3/CMS_encrypt.pod +DEPEND[html/man3/CMS_final.html]=man3/CMS_final.pod +GENERATE[html/man3/CMS_final.html]=man3/CMS_final.pod +DEPEND[man/man3/CMS_final.3]=man3/CMS_final.pod +GENERATE[man/man3/CMS_final.3]=man3/CMS_final.pod +DEPEND[html/man3/CMS_get0_RecipientInfos.html]=man3/CMS_get0_RecipientInfos.pod +GENERATE[html/man3/CMS_get0_RecipientInfos.html]=man3/CMS_get0_RecipientInfos.pod +DEPEND[man/man3/CMS_get0_RecipientInfos.3]=man3/CMS_get0_RecipientInfos.pod +GENERATE[man/man3/CMS_get0_RecipientInfos.3]=man3/CMS_get0_RecipientInfos.pod +DEPEND[html/man3/CMS_get0_SignerInfos.html]=man3/CMS_get0_SignerInfos.pod +GENERATE[html/man3/CMS_get0_SignerInfos.html]=man3/CMS_get0_SignerInfos.pod +DEPEND[man/man3/CMS_get0_SignerInfos.3]=man3/CMS_get0_SignerInfos.pod +GENERATE[man/man3/CMS_get0_SignerInfos.3]=man3/CMS_get0_SignerInfos.pod +DEPEND[html/man3/CMS_get0_type.html]=man3/CMS_get0_type.pod +GENERATE[html/man3/CMS_get0_type.html]=man3/CMS_get0_type.pod +DEPEND[man/man3/CMS_get0_type.3]=man3/CMS_get0_type.pod +GENERATE[man/man3/CMS_get0_type.3]=man3/CMS_get0_type.pod +DEPEND[html/man3/CMS_get1_ReceiptRequest.html]=man3/CMS_get1_ReceiptRequest.pod +GENERATE[html/man3/CMS_get1_ReceiptRequest.html]=man3/CMS_get1_ReceiptRequest.pod +DEPEND[man/man3/CMS_get1_ReceiptRequest.3]=man3/CMS_get1_ReceiptRequest.pod +GENERATE[man/man3/CMS_get1_ReceiptRequest.3]=man3/CMS_get1_ReceiptRequest.pod +DEPEND[html/man3/CMS_sign.html]=man3/CMS_sign.pod +GENERATE[html/man3/CMS_sign.html]=man3/CMS_sign.pod +DEPEND[man/man3/CMS_sign.3]=man3/CMS_sign.pod +GENERATE[man/man3/CMS_sign.3]=man3/CMS_sign.pod +DEPEND[html/man3/CMS_sign_receipt.html]=man3/CMS_sign_receipt.pod +GENERATE[html/man3/CMS_sign_receipt.html]=man3/CMS_sign_receipt.pod +DEPEND[man/man3/CMS_sign_receipt.3]=man3/CMS_sign_receipt.pod +GENERATE[man/man3/CMS_sign_receipt.3]=man3/CMS_sign_receipt.pod +DEPEND[html/man3/CMS_signed_get_attr.html]=man3/CMS_signed_get_attr.pod +GENERATE[html/man3/CMS_signed_get_attr.html]=man3/CMS_signed_get_attr.pod +DEPEND[man/man3/CMS_signed_get_attr.3]=man3/CMS_signed_get_attr.pod +GENERATE[man/man3/CMS_signed_get_attr.3]=man3/CMS_signed_get_attr.pod +DEPEND[html/man3/CMS_uncompress.html]=man3/CMS_uncompress.pod +GENERATE[html/man3/CMS_uncompress.html]=man3/CMS_uncompress.pod +DEPEND[man/man3/CMS_uncompress.3]=man3/CMS_uncompress.pod +GENERATE[man/man3/CMS_uncompress.3]=man3/CMS_uncompress.pod +DEPEND[html/man3/CMS_verify.html]=man3/CMS_verify.pod +GENERATE[html/man3/CMS_verify.html]=man3/CMS_verify.pod +DEPEND[man/man3/CMS_verify.3]=man3/CMS_verify.pod +GENERATE[man/man3/CMS_verify.3]=man3/CMS_verify.pod +DEPEND[html/man3/CMS_verify_receipt.html]=man3/CMS_verify_receipt.pod +GENERATE[html/man3/CMS_verify_receipt.html]=man3/CMS_verify_receipt.pod +DEPEND[man/man3/CMS_verify_receipt.3]=man3/CMS_verify_receipt.pod +GENERATE[man/man3/CMS_verify_receipt.3]=man3/CMS_verify_receipt.pod +DEPEND[html/man3/CONF_modules_free.html]=man3/CONF_modules_free.pod +GENERATE[html/man3/CONF_modules_free.html]=man3/CONF_modules_free.pod +DEPEND[man/man3/CONF_modules_free.3]=man3/CONF_modules_free.pod +GENERATE[man/man3/CONF_modules_free.3]=man3/CONF_modules_free.pod +DEPEND[html/man3/CONF_modules_load_file.html]=man3/CONF_modules_load_file.pod +GENERATE[html/man3/CONF_modules_load_file.html]=man3/CONF_modules_load_file.pod +DEPEND[man/man3/CONF_modules_load_file.3]=man3/CONF_modules_load_file.pod +GENERATE[man/man3/CONF_modules_load_file.3]=man3/CONF_modules_load_file.pod +DEPEND[html/man3/CRYPTO_THREAD_run_once.html]=man3/CRYPTO_THREAD_run_once.pod +GENERATE[html/man3/CRYPTO_THREAD_run_once.html]=man3/CRYPTO_THREAD_run_once.pod +DEPEND[man/man3/CRYPTO_THREAD_run_once.3]=man3/CRYPTO_THREAD_run_once.pod +GENERATE[man/man3/CRYPTO_THREAD_run_once.3]=man3/CRYPTO_THREAD_run_once.pod +DEPEND[html/man3/CRYPTO_get_ex_new_index.html]=man3/CRYPTO_get_ex_new_index.pod +GENERATE[html/man3/CRYPTO_get_ex_new_index.html]=man3/CRYPTO_get_ex_new_index.pod +DEPEND[man/man3/CRYPTO_get_ex_new_index.3]=man3/CRYPTO_get_ex_new_index.pod +GENERATE[man/man3/CRYPTO_get_ex_new_index.3]=man3/CRYPTO_get_ex_new_index.pod +DEPEND[html/man3/CRYPTO_memcmp.html]=man3/CRYPTO_memcmp.pod +GENERATE[html/man3/CRYPTO_memcmp.html]=man3/CRYPTO_memcmp.pod +DEPEND[man/man3/CRYPTO_memcmp.3]=man3/CRYPTO_memcmp.pod +GENERATE[man/man3/CRYPTO_memcmp.3]=man3/CRYPTO_memcmp.pod +DEPEND[html/man3/CTLOG_STORE_get0_log_by_id.html]=man3/CTLOG_STORE_get0_log_by_id.pod +GENERATE[html/man3/CTLOG_STORE_get0_log_by_id.html]=man3/CTLOG_STORE_get0_log_by_id.pod +DEPEND[man/man3/CTLOG_STORE_get0_log_by_id.3]=man3/CTLOG_STORE_get0_log_by_id.pod +GENERATE[man/man3/CTLOG_STORE_get0_log_by_id.3]=man3/CTLOG_STORE_get0_log_by_id.pod +DEPEND[html/man3/CTLOG_STORE_new.html]=man3/CTLOG_STORE_new.pod +GENERATE[html/man3/CTLOG_STORE_new.html]=man3/CTLOG_STORE_new.pod +DEPEND[man/man3/CTLOG_STORE_new.3]=man3/CTLOG_STORE_new.pod +GENERATE[man/man3/CTLOG_STORE_new.3]=man3/CTLOG_STORE_new.pod +DEPEND[html/man3/CTLOG_new.html]=man3/CTLOG_new.pod +GENERATE[html/man3/CTLOG_new.html]=man3/CTLOG_new.pod +DEPEND[man/man3/CTLOG_new.3]=man3/CTLOG_new.pod +GENERATE[man/man3/CTLOG_new.3]=man3/CTLOG_new.pod +DEPEND[html/man3/CT_POLICY_EVAL_CTX_new.html]=man3/CT_POLICY_EVAL_CTX_new.pod +GENERATE[html/man3/CT_POLICY_EVAL_CTX_new.html]=man3/CT_POLICY_EVAL_CTX_new.pod +DEPEND[man/man3/CT_POLICY_EVAL_CTX_new.3]=man3/CT_POLICY_EVAL_CTX_new.pod +GENERATE[man/man3/CT_POLICY_EVAL_CTX_new.3]=man3/CT_POLICY_EVAL_CTX_new.pod +DEPEND[html/man3/DEFINE_STACK_OF.html]=man3/DEFINE_STACK_OF.pod +GENERATE[html/man3/DEFINE_STACK_OF.html]=man3/DEFINE_STACK_OF.pod +DEPEND[man/man3/DEFINE_STACK_OF.3]=man3/DEFINE_STACK_OF.pod +GENERATE[man/man3/DEFINE_STACK_OF.3]=man3/DEFINE_STACK_OF.pod +DEPEND[html/man3/DES_random_key.html]=man3/DES_random_key.pod +GENERATE[html/man3/DES_random_key.html]=man3/DES_random_key.pod +DEPEND[man/man3/DES_random_key.3]=man3/DES_random_key.pod +GENERATE[man/man3/DES_random_key.3]=man3/DES_random_key.pod +DEPEND[html/man3/DH_generate_key.html]=man3/DH_generate_key.pod +GENERATE[html/man3/DH_generate_key.html]=man3/DH_generate_key.pod +DEPEND[man/man3/DH_generate_key.3]=man3/DH_generate_key.pod +GENERATE[man/man3/DH_generate_key.3]=man3/DH_generate_key.pod +DEPEND[html/man3/DH_generate_parameters.html]=man3/DH_generate_parameters.pod +GENERATE[html/man3/DH_generate_parameters.html]=man3/DH_generate_parameters.pod +DEPEND[man/man3/DH_generate_parameters.3]=man3/DH_generate_parameters.pod +GENERATE[man/man3/DH_generate_parameters.3]=man3/DH_generate_parameters.pod +DEPEND[html/man3/DH_get0_pqg.html]=man3/DH_get0_pqg.pod +GENERATE[html/man3/DH_get0_pqg.html]=man3/DH_get0_pqg.pod +DEPEND[man/man3/DH_get0_pqg.3]=man3/DH_get0_pqg.pod +GENERATE[man/man3/DH_get0_pqg.3]=man3/DH_get0_pqg.pod +DEPEND[html/man3/DH_get_1024_160.html]=man3/DH_get_1024_160.pod +GENERATE[html/man3/DH_get_1024_160.html]=man3/DH_get_1024_160.pod +DEPEND[man/man3/DH_get_1024_160.3]=man3/DH_get_1024_160.pod +GENERATE[man/man3/DH_get_1024_160.3]=man3/DH_get_1024_160.pod +DEPEND[html/man3/DH_meth_new.html]=man3/DH_meth_new.pod +GENERATE[html/man3/DH_meth_new.html]=man3/DH_meth_new.pod +DEPEND[man/man3/DH_meth_new.3]=man3/DH_meth_new.pod +GENERATE[man/man3/DH_meth_new.3]=man3/DH_meth_new.pod +DEPEND[html/man3/DH_new.html]=man3/DH_new.pod +GENERATE[html/man3/DH_new.html]=man3/DH_new.pod +DEPEND[man/man3/DH_new.3]=man3/DH_new.pod +GENERATE[man/man3/DH_new.3]=man3/DH_new.pod +DEPEND[html/man3/DH_new_by_nid.html]=man3/DH_new_by_nid.pod +GENERATE[html/man3/DH_new_by_nid.html]=man3/DH_new_by_nid.pod +DEPEND[man/man3/DH_new_by_nid.3]=man3/DH_new_by_nid.pod +GENERATE[man/man3/DH_new_by_nid.3]=man3/DH_new_by_nid.pod +DEPEND[html/man3/DH_set_method.html]=man3/DH_set_method.pod +GENERATE[html/man3/DH_set_method.html]=man3/DH_set_method.pod +DEPEND[man/man3/DH_set_method.3]=man3/DH_set_method.pod +GENERATE[man/man3/DH_set_method.3]=man3/DH_set_method.pod +DEPEND[html/man3/DH_size.html]=man3/DH_size.pod +GENERATE[html/man3/DH_size.html]=man3/DH_size.pod +DEPEND[man/man3/DH_size.3]=man3/DH_size.pod +GENERATE[man/man3/DH_size.3]=man3/DH_size.pod +DEPEND[html/man3/DSA_SIG_new.html]=man3/DSA_SIG_new.pod +GENERATE[html/man3/DSA_SIG_new.html]=man3/DSA_SIG_new.pod +DEPEND[man/man3/DSA_SIG_new.3]=man3/DSA_SIG_new.pod +GENERATE[man/man3/DSA_SIG_new.3]=man3/DSA_SIG_new.pod +DEPEND[html/man3/DSA_do_sign.html]=man3/DSA_do_sign.pod +GENERATE[html/man3/DSA_do_sign.html]=man3/DSA_do_sign.pod +DEPEND[man/man3/DSA_do_sign.3]=man3/DSA_do_sign.pod +GENERATE[man/man3/DSA_do_sign.3]=man3/DSA_do_sign.pod +DEPEND[html/man3/DSA_dup_DH.html]=man3/DSA_dup_DH.pod +GENERATE[html/man3/DSA_dup_DH.html]=man3/DSA_dup_DH.pod +DEPEND[man/man3/DSA_dup_DH.3]=man3/DSA_dup_DH.pod +GENERATE[man/man3/DSA_dup_DH.3]=man3/DSA_dup_DH.pod +DEPEND[html/man3/DSA_generate_key.html]=man3/DSA_generate_key.pod +GENERATE[html/man3/DSA_generate_key.html]=man3/DSA_generate_key.pod +DEPEND[man/man3/DSA_generate_key.3]=man3/DSA_generate_key.pod +GENERATE[man/man3/DSA_generate_key.3]=man3/DSA_generate_key.pod +DEPEND[html/man3/DSA_generate_parameters.html]=man3/DSA_generate_parameters.pod +GENERATE[html/man3/DSA_generate_parameters.html]=man3/DSA_generate_parameters.pod +DEPEND[man/man3/DSA_generate_parameters.3]=man3/DSA_generate_parameters.pod +GENERATE[man/man3/DSA_generate_parameters.3]=man3/DSA_generate_parameters.pod +DEPEND[html/man3/DSA_get0_pqg.html]=man3/DSA_get0_pqg.pod +GENERATE[html/man3/DSA_get0_pqg.html]=man3/DSA_get0_pqg.pod +DEPEND[man/man3/DSA_get0_pqg.3]=man3/DSA_get0_pqg.pod +GENERATE[man/man3/DSA_get0_pqg.3]=man3/DSA_get0_pqg.pod +DEPEND[html/man3/DSA_meth_new.html]=man3/DSA_meth_new.pod +GENERATE[html/man3/DSA_meth_new.html]=man3/DSA_meth_new.pod +DEPEND[man/man3/DSA_meth_new.3]=man3/DSA_meth_new.pod +GENERATE[man/man3/DSA_meth_new.3]=man3/DSA_meth_new.pod +DEPEND[html/man3/DSA_new.html]=man3/DSA_new.pod +GENERATE[html/man3/DSA_new.html]=man3/DSA_new.pod +DEPEND[man/man3/DSA_new.3]=man3/DSA_new.pod +GENERATE[man/man3/DSA_new.3]=man3/DSA_new.pod +DEPEND[html/man3/DSA_set_method.html]=man3/DSA_set_method.pod +GENERATE[html/man3/DSA_set_method.html]=man3/DSA_set_method.pod +DEPEND[man/man3/DSA_set_method.3]=man3/DSA_set_method.pod +GENERATE[man/man3/DSA_set_method.3]=man3/DSA_set_method.pod +DEPEND[html/man3/DSA_sign.html]=man3/DSA_sign.pod +GENERATE[html/man3/DSA_sign.html]=man3/DSA_sign.pod +DEPEND[man/man3/DSA_sign.3]=man3/DSA_sign.pod +GENERATE[man/man3/DSA_sign.3]=man3/DSA_sign.pod +DEPEND[html/man3/DSA_size.html]=man3/DSA_size.pod +GENERATE[html/man3/DSA_size.html]=man3/DSA_size.pod +DEPEND[man/man3/DSA_size.3]=man3/DSA_size.pod +GENERATE[man/man3/DSA_size.3]=man3/DSA_size.pod +DEPEND[html/man3/DTLS_get_data_mtu.html]=man3/DTLS_get_data_mtu.pod +GENERATE[html/man3/DTLS_get_data_mtu.html]=man3/DTLS_get_data_mtu.pod +DEPEND[man/man3/DTLS_get_data_mtu.3]=man3/DTLS_get_data_mtu.pod +GENERATE[man/man3/DTLS_get_data_mtu.3]=man3/DTLS_get_data_mtu.pod +DEPEND[html/man3/DTLS_set_timer_cb.html]=man3/DTLS_set_timer_cb.pod +GENERATE[html/man3/DTLS_set_timer_cb.html]=man3/DTLS_set_timer_cb.pod +DEPEND[man/man3/DTLS_set_timer_cb.3]=man3/DTLS_set_timer_cb.pod +GENERATE[man/man3/DTLS_set_timer_cb.3]=man3/DTLS_set_timer_cb.pod +DEPEND[html/man3/DTLSv1_listen.html]=man3/DTLSv1_listen.pod +GENERATE[html/man3/DTLSv1_listen.html]=man3/DTLSv1_listen.pod +DEPEND[man/man3/DTLSv1_listen.3]=man3/DTLSv1_listen.pod +GENERATE[man/man3/DTLSv1_listen.3]=man3/DTLSv1_listen.pod +DEPEND[html/man3/ECDSA_SIG_new.html]=man3/ECDSA_SIG_new.pod +GENERATE[html/man3/ECDSA_SIG_new.html]=man3/ECDSA_SIG_new.pod +DEPEND[man/man3/ECDSA_SIG_new.3]=man3/ECDSA_SIG_new.pod +GENERATE[man/man3/ECDSA_SIG_new.3]=man3/ECDSA_SIG_new.pod +DEPEND[html/man3/ECDSA_sign.html]=man3/ECDSA_sign.pod +GENERATE[html/man3/ECDSA_sign.html]=man3/ECDSA_sign.pod +DEPEND[man/man3/ECDSA_sign.3]=man3/ECDSA_sign.pod +GENERATE[man/man3/ECDSA_sign.3]=man3/ECDSA_sign.pod +DEPEND[html/man3/ECPKParameters_print.html]=man3/ECPKParameters_print.pod +GENERATE[html/man3/ECPKParameters_print.html]=man3/ECPKParameters_print.pod +DEPEND[man/man3/ECPKParameters_print.3]=man3/ECPKParameters_print.pod +GENERATE[man/man3/ECPKParameters_print.3]=man3/ECPKParameters_print.pod +DEPEND[html/man3/EC_GFp_simple_method.html]=man3/EC_GFp_simple_method.pod +GENERATE[html/man3/EC_GFp_simple_method.html]=man3/EC_GFp_simple_method.pod +DEPEND[man/man3/EC_GFp_simple_method.3]=man3/EC_GFp_simple_method.pod +GENERATE[man/man3/EC_GFp_simple_method.3]=man3/EC_GFp_simple_method.pod +DEPEND[html/man3/EC_GROUP_copy.html]=man3/EC_GROUP_copy.pod +GENERATE[html/man3/EC_GROUP_copy.html]=man3/EC_GROUP_copy.pod +DEPEND[man/man3/EC_GROUP_copy.3]=man3/EC_GROUP_copy.pod +GENERATE[man/man3/EC_GROUP_copy.3]=man3/EC_GROUP_copy.pod +DEPEND[html/man3/EC_GROUP_new.html]=man3/EC_GROUP_new.pod +GENERATE[html/man3/EC_GROUP_new.html]=man3/EC_GROUP_new.pod +DEPEND[man/man3/EC_GROUP_new.3]=man3/EC_GROUP_new.pod +GENERATE[man/man3/EC_GROUP_new.3]=man3/EC_GROUP_new.pod +DEPEND[html/man3/EC_KEY_get_enc_flags.html]=man3/EC_KEY_get_enc_flags.pod +GENERATE[html/man3/EC_KEY_get_enc_flags.html]=man3/EC_KEY_get_enc_flags.pod +DEPEND[man/man3/EC_KEY_get_enc_flags.3]=man3/EC_KEY_get_enc_flags.pod +GENERATE[man/man3/EC_KEY_get_enc_flags.3]=man3/EC_KEY_get_enc_flags.pod +DEPEND[html/man3/EC_KEY_new.html]=man3/EC_KEY_new.pod +GENERATE[html/man3/EC_KEY_new.html]=man3/EC_KEY_new.pod +DEPEND[man/man3/EC_KEY_new.3]=man3/EC_KEY_new.pod +GENERATE[man/man3/EC_KEY_new.3]=man3/EC_KEY_new.pod +DEPEND[html/man3/EC_POINT_add.html]=man3/EC_POINT_add.pod +GENERATE[html/man3/EC_POINT_add.html]=man3/EC_POINT_add.pod +DEPEND[man/man3/EC_POINT_add.3]=man3/EC_POINT_add.pod +GENERATE[man/man3/EC_POINT_add.3]=man3/EC_POINT_add.pod +DEPEND[html/man3/EC_POINT_new.html]=man3/EC_POINT_new.pod +GENERATE[html/man3/EC_POINT_new.html]=man3/EC_POINT_new.pod +DEPEND[man/man3/EC_POINT_new.3]=man3/EC_POINT_new.pod +GENERATE[man/man3/EC_POINT_new.3]=man3/EC_POINT_new.pod +DEPEND[html/man3/ENGINE_add.html]=man3/ENGINE_add.pod +GENERATE[html/man3/ENGINE_add.html]=man3/ENGINE_add.pod +DEPEND[man/man3/ENGINE_add.3]=man3/ENGINE_add.pod +GENERATE[man/man3/ENGINE_add.3]=man3/ENGINE_add.pod +DEPEND[html/man3/ERR_GET_LIB.html]=man3/ERR_GET_LIB.pod +GENERATE[html/man3/ERR_GET_LIB.html]=man3/ERR_GET_LIB.pod +DEPEND[man/man3/ERR_GET_LIB.3]=man3/ERR_GET_LIB.pod +GENERATE[man/man3/ERR_GET_LIB.3]=man3/ERR_GET_LIB.pod +DEPEND[html/man3/ERR_clear_error.html]=man3/ERR_clear_error.pod +GENERATE[html/man3/ERR_clear_error.html]=man3/ERR_clear_error.pod +DEPEND[man/man3/ERR_clear_error.3]=man3/ERR_clear_error.pod +GENERATE[man/man3/ERR_clear_error.3]=man3/ERR_clear_error.pod +DEPEND[html/man3/ERR_error_string.html]=man3/ERR_error_string.pod +GENERATE[html/man3/ERR_error_string.html]=man3/ERR_error_string.pod +DEPEND[man/man3/ERR_error_string.3]=man3/ERR_error_string.pod +GENERATE[man/man3/ERR_error_string.3]=man3/ERR_error_string.pod +DEPEND[html/man3/ERR_get_error.html]=man3/ERR_get_error.pod +GENERATE[html/man3/ERR_get_error.html]=man3/ERR_get_error.pod +DEPEND[man/man3/ERR_get_error.3]=man3/ERR_get_error.pod +GENERATE[man/man3/ERR_get_error.3]=man3/ERR_get_error.pod +DEPEND[html/man3/ERR_load_crypto_strings.html]=man3/ERR_load_crypto_strings.pod +GENERATE[html/man3/ERR_load_crypto_strings.html]=man3/ERR_load_crypto_strings.pod +DEPEND[man/man3/ERR_load_crypto_strings.3]=man3/ERR_load_crypto_strings.pod +GENERATE[man/man3/ERR_load_crypto_strings.3]=man3/ERR_load_crypto_strings.pod +DEPEND[html/man3/ERR_load_strings.html]=man3/ERR_load_strings.pod +GENERATE[html/man3/ERR_load_strings.html]=man3/ERR_load_strings.pod +DEPEND[man/man3/ERR_load_strings.3]=man3/ERR_load_strings.pod +GENERATE[man/man3/ERR_load_strings.3]=man3/ERR_load_strings.pod +DEPEND[html/man3/ERR_new.html]=man3/ERR_new.pod +GENERATE[html/man3/ERR_new.html]=man3/ERR_new.pod +DEPEND[man/man3/ERR_new.3]=man3/ERR_new.pod +GENERATE[man/man3/ERR_new.3]=man3/ERR_new.pod +DEPEND[html/man3/ERR_print_errors.html]=man3/ERR_print_errors.pod +GENERATE[html/man3/ERR_print_errors.html]=man3/ERR_print_errors.pod +DEPEND[man/man3/ERR_print_errors.3]=man3/ERR_print_errors.pod +GENERATE[man/man3/ERR_print_errors.3]=man3/ERR_print_errors.pod +DEPEND[html/man3/ERR_put_error.html]=man3/ERR_put_error.pod +GENERATE[html/man3/ERR_put_error.html]=man3/ERR_put_error.pod +DEPEND[man/man3/ERR_put_error.3]=man3/ERR_put_error.pod +GENERATE[man/man3/ERR_put_error.3]=man3/ERR_put_error.pod +DEPEND[html/man3/ERR_remove_state.html]=man3/ERR_remove_state.pod +GENERATE[html/man3/ERR_remove_state.html]=man3/ERR_remove_state.pod +DEPEND[man/man3/ERR_remove_state.3]=man3/ERR_remove_state.pod +GENERATE[man/man3/ERR_remove_state.3]=man3/ERR_remove_state.pod +DEPEND[html/man3/ERR_set_mark.html]=man3/ERR_set_mark.pod +GENERATE[html/man3/ERR_set_mark.html]=man3/ERR_set_mark.pod +DEPEND[man/man3/ERR_set_mark.3]=man3/ERR_set_mark.pod +GENERATE[man/man3/ERR_set_mark.3]=man3/ERR_set_mark.pod +DEPEND[html/man3/EVP_ASYM_CIPHER_free.html]=man3/EVP_ASYM_CIPHER_free.pod +GENERATE[html/man3/EVP_ASYM_CIPHER_free.html]=man3/EVP_ASYM_CIPHER_free.pod +DEPEND[man/man3/EVP_ASYM_CIPHER_free.3]=man3/EVP_ASYM_CIPHER_free.pod +GENERATE[man/man3/EVP_ASYM_CIPHER_free.3]=man3/EVP_ASYM_CIPHER_free.pod +DEPEND[html/man3/EVP_BytesToKey.html]=man3/EVP_BytesToKey.pod +GENERATE[html/man3/EVP_BytesToKey.html]=man3/EVP_BytesToKey.pod +DEPEND[man/man3/EVP_BytesToKey.3]=man3/EVP_BytesToKey.pod +GENERATE[man/man3/EVP_BytesToKey.3]=man3/EVP_BytesToKey.pod +DEPEND[html/man3/EVP_CIPHER_CTX_get_cipher_data.html]=man3/EVP_CIPHER_CTX_get_cipher_data.pod +GENERATE[html/man3/EVP_CIPHER_CTX_get_cipher_data.html]=man3/EVP_CIPHER_CTX_get_cipher_data.pod +DEPEND[man/man3/EVP_CIPHER_CTX_get_cipher_data.3]=man3/EVP_CIPHER_CTX_get_cipher_data.pod +GENERATE[man/man3/EVP_CIPHER_CTX_get_cipher_data.3]=man3/EVP_CIPHER_CTX_get_cipher_data.pod +DEPEND[html/man3/EVP_CIPHER_CTX_get_original_iv.html]=man3/EVP_CIPHER_CTX_get_original_iv.pod +GENERATE[html/man3/EVP_CIPHER_CTX_get_original_iv.html]=man3/EVP_CIPHER_CTX_get_original_iv.pod +DEPEND[man/man3/EVP_CIPHER_CTX_get_original_iv.3]=man3/EVP_CIPHER_CTX_get_original_iv.pod +GENERATE[man/man3/EVP_CIPHER_CTX_get_original_iv.3]=man3/EVP_CIPHER_CTX_get_original_iv.pod +DEPEND[html/man3/EVP_CIPHER_meth_new.html]=man3/EVP_CIPHER_meth_new.pod +GENERATE[html/man3/EVP_CIPHER_meth_new.html]=man3/EVP_CIPHER_meth_new.pod +DEPEND[man/man3/EVP_CIPHER_meth_new.3]=man3/EVP_CIPHER_meth_new.pod +GENERATE[man/man3/EVP_CIPHER_meth_new.3]=man3/EVP_CIPHER_meth_new.pod +DEPEND[html/man3/EVP_DigestInit.html]=man3/EVP_DigestInit.pod +GENERATE[html/man3/EVP_DigestInit.html]=man3/EVP_DigestInit.pod +DEPEND[man/man3/EVP_DigestInit.3]=man3/EVP_DigestInit.pod +GENERATE[man/man3/EVP_DigestInit.3]=man3/EVP_DigestInit.pod +DEPEND[html/man3/EVP_DigestSignInit.html]=man3/EVP_DigestSignInit.pod +GENERATE[html/man3/EVP_DigestSignInit.html]=man3/EVP_DigestSignInit.pod +DEPEND[man/man3/EVP_DigestSignInit.3]=man3/EVP_DigestSignInit.pod +GENERATE[man/man3/EVP_DigestSignInit.3]=man3/EVP_DigestSignInit.pod +DEPEND[html/man3/EVP_DigestVerifyInit.html]=man3/EVP_DigestVerifyInit.pod +GENERATE[html/man3/EVP_DigestVerifyInit.html]=man3/EVP_DigestVerifyInit.pod +DEPEND[man/man3/EVP_DigestVerifyInit.3]=man3/EVP_DigestVerifyInit.pod +GENERATE[man/man3/EVP_DigestVerifyInit.3]=man3/EVP_DigestVerifyInit.pod +DEPEND[html/man3/EVP_EncodeInit.html]=man3/EVP_EncodeInit.pod +GENERATE[html/man3/EVP_EncodeInit.html]=man3/EVP_EncodeInit.pod +DEPEND[man/man3/EVP_EncodeInit.3]=man3/EVP_EncodeInit.pod +GENERATE[man/man3/EVP_EncodeInit.3]=man3/EVP_EncodeInit.pod +DEPEND[html/man3/EVP_EncryptInit.html]=man3/EVP_EncryptInit.pod +GENERATE[html/man3/EVP_EncryptInit.html]=man3/EVP_EncryptInit.pod +DEPEND[man/man3/EVP_EncryptInit.3]=man3/EVP_EncryptInit.pod +GENERATE[man/man3/EVP_EncryptInit.3]=man3/EVP_EncryptInit.pod +DEPEND[html/man3/EVP_KDF.html]=man3/EVP_KDF.pod +GENERATE[html/man3/EVP_KDF.html]=man3/EVP_KDF.pod +DEPEND[man/man3/EVP_KDF.3]=man3/EVP_KDF.pod +GENERATE[man/man3/EVP_KDF.3]=man3/EVP_KDF.pod +DEPEND[html/man3/EVP_KEM_free.html]=man3/EVP_KEM_free.pod +GENERATE[html/man3/EVP_KEM_free.html]=man3/EVP_KEM_free.pod +DEPEND[man/man3/EVP_KEM_free.3]=man3/EVP_KEM_free.pod +GENERATE[man/man3/EVP_KEM_free.3]=man3/EVP_KEM_free.pod +DEPEND[html/man3/EVP_KEYEXCH_free.html]=man3/EVP_KEYEXCH_free.pod +GENERATE[html/man3/EVP_KEYEXCH_free.html]=man3/EVP_KEYEXCH_free.pod +DEPEND[man/man3/EVP_KEYEXCH_free.3]=man3/EVP_KEYEXCH_free.pod +GENERATE[man/man3/EVP_KEYEXCH_free.3]=man3/EVP_KEYEXCH_free.pod +DEPEND[html/man3/EVP_KEYMGMT.html]=man3/EVP_KEYMGMT.pod +GENERATE[html/man3/EVP_KEYMGMT.html]=man3/EVP_KEYMGMT.pod +DEPEND[man/man3/EVP_KEYMGMT.3]=man3/EVP_KEYMGMT.pod +GENERATE[man/man3/EVP_KEYMGMT.3]=man3/EVP_KEYMGMT.pod +DEPEND[html/man3/EVP_MAC.html]=man3/EVP_MAC.pod +GENERATE[html/man3/EVP_MAC.html]=man3/EVP_MAC.pod +DEPEND[man/man3/EVP_MAC.3]=man3/EVP_MAC.pod +GENERATE[man/man3/EVP_MAC.3]=man3/EVP_MAC.pod +DEPEND[html/man3/EVP_MD_meth_new.html]=man3/EVP_MD_meth_new.pod +GENERATE[html/man3/EVP_MD_meth_new.html]=man3/EVP_MD_meth_new.pod +DEPEND[man/man3/EVP_MD_meth_new.3]=man3/EVP_MD_meth_new.pod +GENERATE[man/man3/EVP_MD_meth_new.3]=man3/EVP_MD_meth_new.pod +DEPEND[html/man3/EVP_OpenInit.html]=man3/EVP_OpenInit.pod +GENERATE[html/man3/EVP_OpenInit.html]=man3/EVP_OpenInit.pod +DEPEND[man/man3/EVP_OpenInit.3]=man3/EVP_OpenInit.pod +GENERATE[man/man3/EVP_OpenInit.3]=man3/EVP_OpenInit.pod +DEPEND[html/man3/EVP_PBE_CipherInit.html]=man3/EVP_PBE_CipherInit.pod +GENERATE[html/man3/EVP_PBE_CipherInit.html]=man3/EVP_PBE_CipherInit.pod +DEPEND[man/man3/EVP_PBE_CipherInit.3]=man3/EVP_PBE_CipherInit.pod +GENERATE[man/man3/EVP_PBE_CipherInit.3]=man3/EVP_PBE_CipherInit.pod +DEPEND[html/man3/EVP_PKEY2PKCS8.html]=man3/EVP_PKEY2PKCS8.pod +GENERATE[html/man3/EVP_PKEY2PKCS8.html]=man3/EVP_PKEY2PKCS8.pod +DEPEND[man/man3/EVP_PKEY2PKCS8.3]=man3/EVP_PKEY2PKCS8.pod +GENERATE[man/man3/EVP_PKEY2PKCS8.3]=man3/EVP_PKEY2PKCS8.pod +DEPEND[html/man3/EVP_PKEY_ASN1_METHOD.html]=man3/EVP_PKEY_ASN1_METHOD.pod +GENERATE[html/man3/EVP_PKEY_ASN1_METHOD.html]=man3/EVP_PKEY_ASN1_METHOD.pod +DEPEND[man/man3/EVP_PKEY_ASN1_METHOD.3]=man3/EVP_PKEY_ASN1_METHOD.pod +GENERATE[man/man3/EVP_PKEY_ASN1_METHOD.3]=man3/EVP_PKEY_ASN1_METHOD.pod +DEPEND[html/man3/EVP_PKEY_CTX_ctrl.html]=man3/EVP_PKEY_CTX_ctrl.pod +GENERATE[html/man3/EVP_PKEY_CTX_ctrl.html]=man3/EVP_PKEY_CTX_ctrl.pod +DEPEND[man/man3/EVP_PKEY_CTX_ctrl.3]=man3/EVP_PKEY_CTX_ctrl.pod +GENERATE[man/man3/EVP_PKEY_CTX_ctrl.3]=man3/EVP_PKEY_CTX_ctrl.pod +DEPEND[html/man3/EVP_PKEY_CTX_get0_libctx.html]=man3/EVP_PKEY_CTX_get0_libctx.pod +GENERATE[html/man3/EVP_PKEY_CTX_get0_libctx.html]=man3/EVP_PKEY_CTX_get0_libctx.pod +DEPEND[man/man3/EVP_PKEY_CTX_get0_libctx.3]=man3/EVP_PKEY_CTX_get0_libctx.pod +GENERATE[man/man3/EVP_PKEY_CTX_get0_libctx.3]=man3/EVP_PKEY_CTX_get0_libctx.pod +DEPEND[html/man3/EVP_PKEY_CTX_get0_pkey.html]=man3/EVP_PKEY_CTX_get0_pkey.pod +GENERATE[html/man3/EVP_PKEY_CTX_get0_pkey.html]=man3/EVP_PKEY_CTX_get0_pkey.pod +DEPEND[man/man3/EVP_PKEY_CTX_get0_pkey.3]=man3/EVP_PKEY_CTX_get0_pkey.pod +GENERATE[man/man3/EVP_PKEY_CTX_get0_pkey.3]=man3/EVP_PKEY_CTX_get0_pkey.pod +DEPEND[html/man3/EVP_PKEY_CTX_new.html]=man3/EVP_PKEY_CTX_new.pod +GENERATE[html/man3/EVP_PKEY_CTX_new.html]=man3/EVP_PKEY_CTX_new.pod +DEPEND[man/man3/EVP_PKEY_CTX_new.3]=man3/EVP_PKEY_CTX_new.pod +GENERATE[man/man3/EVP_PKEY_CTX_new.3]=man3/EVP_PKEY_CTX_new.pod +DEPEND[html/man3/EVP_PKEY_CTX_set1_pbe_pass.html]=man3/EVP_PKEY_CTX_set1_pbe_pass.pod +GENERATE[html/man3/EVP_PKEY_CTX_set1_pbe_pass.html]=man3/EVP_PKEY_CTX_set1_pbe_pass.pod +DEPEND[man/man3/EVP_PKEY_CTX_set1_pbe_pass.3]=man3/EVP_PKEY_CTX_set1_pbe_pass.pod +GENERATE[man/man3/EVP_PKEY_CTX_set1_pbe_pass.3]=man3/EVP_PKEY_CTX_set1_pbe_pass.pod +DEPEND[html/man3/EVP_PKEY_CTX_set_hkdf_md.html]=man3/EVP_PKEY_CTX_set_hkdf_md.pod +GENERATE[html/man3/EVP_PKEY_CTX_set_hkdf_md.html]=man3/EVP_PKEY_CTX_set_hkdf_md.pod +DEPEND[man/man3/EVP_PKEY_CTX_set_hkdf_md.3]=man3/EVP_PKEY_CTX_set_hkdf_md.pod +GENERATE[man/man3/EVP_PKEY_CTX_set_hkdf_md.3]=man3/EVP_PKEY_CTX_set_hkdf_md.pod +DEPEND[html/man3/EVP_PKEY_CTX_set_params.html]=man3/EVP_PKEY_CTX_set_params.pod +GENERATE[html/man3/EVP_PKEY_CTX_set_params.html]=man3/EVP_PKEY_CTX_set_params.pod +DEPEND[man/man3/EVP_PKEY_CTX_set_params.3]=man3/EVP_PKEY_CTX_set_params.pod +GENERATE[man/man3/EVP_PKEY_CTX_set_params.3]=man3/EVP_PKEY_CTX_set_params.pod +DEPEND[html/man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.html]=man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.pod +GENERATE[html/man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.html]=man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.pod +DEPEND[man/man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.3]=man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.pod +GENERATE[man/man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.3]=man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.pod +DEPEND[html/man3/EVP_PKEY_CTX_set_scrypt_N.html]=man3/EVP_PKEY_CTX_set_scrypt_N.pod +GENERATE[html/man3/EVP_PKEY_CTX_set_scrypt_N.html]=man3/EVP_PKEY_CTX_set_scrypt_N.pod +DEPEND[man/man3/EVP_PKEY_CTX_set_scrypt_N.3]=man3/EVP_PKEY_CTX_set_scrypt_N.pod +GENERATE[man/man3/EVP_PKEY_CTX_set_scrypt_N.3]=man3/EVP_PKEY_CTX_set_scrypt_N.pod +DEPEND[html/man3/EVP_PKEY_CTX_set_tls1_prf_md.html]=man3/EVP_PKEY_CTX_set_tls1_prf_md.pod +GENERATE[html/man3/EVP_PKEY_CTX_set_tls1_prf_md.html]=man3/EVP_PKEY_CTX_set_tls1_prf_md.pod +DEPEND[man/man3/EVP_PKEY_CTX_set_tls1_prf_md.3]=man3/EVP_PKEY_CTX_set_tls1_prf_md.pod +GENERATE[man/man3/EVP_PKEY_CTX_set_tls1_prf_md.3]=man3/EVP_PKEY_CTX_set_tls1_prf_md.pod +DEPEND[html/man3/EVP_PKEY_asn1_get_count.html]=man3/EVP_PKEY_asn1_get_count.pod +GENERATE[html/man3/EVP_PKEY_asn1_get_count.html]=man3/EVP_PKEY_asn1_get_count.pod +DEPEND[man/man3/EVP_PKEY_asn1_get_count.3]=man3/EVP_PKEY_asn1_get_count.pod +GENERATE[man/man3/EVP_PKEY_asn1_get_count.3]=man3/EVP_PKEY_asn1_get_count.pod +DEPEND[html/man3/EVP_PKEY_check.html]=man3/EVP_PKEY_check.pod +GENERATE[html/man3/EVP_PKEY_check.html]=man3/EVP_PKEY_check.pod +DEPEND[man/man3/EVP_PKEY_check.3]=man3/EVP_PKEY_check.pod +GENERATE[man/man3/EVP_PKEY_check.3]=man3/EVP_PKEY_check.pod +DEPEND[html/man3/EVP_PKEY_copy_parameters.html]=man3/EVP_PKEY_copy_parameters.pod +GENERATE[html/man3/EVP_PKEY_copy_parameters.html]=man3/EVP_PKEY_copy_parameters.pod +DEPEND[man/man3/EVP_PKEY_copy_parameters.3]=man3/EVP_PKEY_copy_parameters.pod +GENERATE[man/man3/EVP_PKEY_copy_parameters.3]=man3/EVP_PKEY_copy_parameters.pod +DEPEND[html/man3/EVP_PKEY_decapsulate.html]=man3/EVP_PKEY_decapsulate.pod +GENERATE[html/man3/EVP_PKEY_decapsulate.html]=man3/EVP_PKEY_decapsulate.pod +DEPEND[man/man3/EVP_PKEY_decapsulate.3]=man3/EVP_PKEY_decapsulate.pod +GENERATE[man/man3/EVP_PKEY_decapsulate.3]=man3/EVP_PKEY_decapsulate.pod +DEPEND[html/man3/EVP_PKEY_decrypt.html]=man3/EVP_PKEY_decrypt.pod +GENERATE[html/man3/EVP_PKEY_decrypt.html]=man3/EVP_PKEY_decrypt.pod +DEPEND[man/man3/EVP_PKEY_decrypt.3]=man3/EVP_PKEY_decrypt.pod +GENERATE[man/man3/EVP_PKEY_decrypt.3]=man3/EVP_PKEY_decrypt.pod +DEPEND[html/man3/EVP_PKEY_derive.html]=man3/EVP_PKEY_derive.pod +GENERATE[html/man3/EVP_PKEY_derive.html]=man3/EVP_PKEY_derive.pod +DEPEND[man/man3/EVP_PKEY_derive.3]=man3/EVP_PKEY_derive.pod +GENERATE[man/man3/EVP_PKEY_derive.3]=man3/EVP_PKEY_derive.pod +DEPEND[html/man3/EVP_PKEY_digestsign_supports_digest.html]=man3/EVP_PKEY_digestsign_supports_digest.pod +GENERATE[html/man3/EVP_PKEY_digestsign_supports_digest.html]=man3/EVP_PKEY_digestsign_supports_digest.pod +DEPEND[man/man3/EVP_PKEY_digestsign_supports_digest.3]=man3/EVP_PKEY_digestsign_supports_digest.pod +GENERATE[man/man3/EVP_PKEY_digestsign_supports_digest.3]=man3/EVP_PKEY_digestsign_supports_digest.pod +DEPEND[html/man3/EVP_PKEY_encapsulate.html]=man3/EVP_PKEY_encapsulate.pod +GENERATE[html/man3/EVP_PKEY_encapsulate.html]=man3/EVP_PKEY_encapsulate.pod +DEPEND[man/man3/EVP_PKEY_encapsulate.3]=man3/EVP_PKEY_encapsulate.pod +GENERATE[man/man3/EVP_PKEY_encapsulate.3]=man3/EVP_PKEY_encapsulate.pod +DEPEND[html/man3/EVP_PKEY_encrypt.html]=man3/EVP_PKEY_encrypt.pod +GENERATE[html/man3/EVP_PKEY_encrypt.html]=man3/EVP_PKEY_encrypt.pod +DEPEND[man/man3/EVP_PKEY_encrypt.3]=man3/EVP_PKEY_encrypt.pod +GENERATE[man/man3/EVP_PKEY_encrypt.3]=man3/EVP_PKEY_encrypt.pod +DEPEND[html/man3/EVP_PKEY_fromdata.html]=man3/EVP_PKEY_fromdata.pod +GENERATE[html/man3/EVP_PKEY_fromdata.html]=man3/EVP_PKEY_fromdata.pod +DEPEND[man/man3/EVP_PKEY_fromdata.3]=man3/EVP_PKEY_fromdata.pod +GENERATE[man/man3/EVP_PKEY_fromdata.3]=man3/EVP_PKEY_fromdata.pod +DEPEND[html/man3/EVP_PKEY_get_attr.html]=man3/EVP_PKEY_get_attr.pod +GENERATE[html/man3/EVP_PKEY_get_attr.html]=man3/EVP_PKEY_get_attr.pod +DEPEND[man/man3/EVP_PKEY_get_attr.3]=man3/EVP_PKEY_get_attr.pod +GENERATE[man/man3/EVP_PKEY_get_attr.3]=man3/EVP_PKEY_get_attr.pod +DEPEND[html/man3/EVP_PKEY_get_default_digest_nid.html]=man3/EVP_PKEY_get_default_digest_nid.pod +GENERATE[html/man3/EVP_PKEY_get_default_digest_nid.html]=man3/EVP_PKEY_get_default_digest_nid.pod +DEPEND[man/man3/EVP_PKEY_get_default_digest_nid.3]=man3/EVP_PKEY_get_default_digest_nid.pod +GENERATE[man/man3/EVP_PKEY_get_default_digest_nid.3]=man3/EVP_PKEY_get_default_digest_nid.pod +DEPEND[html/man3/EVP_PKEY_get_field_type.html]=man3/EVP_PKEY_get_field_type.pod +GENERATE[html/man3/EVP_PKEY_get_field_type.html]=man3/EVP_PKEY_get_field_type.pod +DEPEND[man/man3/EVP_PKEY_get_field_type.3]=man3/EVP_PKEY_get_field_type.pod +GENERATE[man/man3/EVP_PKEY_get_field_type.3]=man3/EVP_PKEY_get_field_type.pod +DEPEND[html/man3/EVP_PKEY_get_group_name.html]=man3/EVP_PKEY_get_group_name.pod +GENERATE[html/man3/EVP_PKEY_get_group_name.html]=man3/EVP_PKEY_get_group_name.pod +DEPEND[man/man3/EVP_PKEY_get_group_name.3]=man3/EVP_PKEY_get_group_name.pod +GENERATE[man/man3/EVP_PKEY_get_group_name.3]=man3/EVP_PKEY_get_group_name.pod +DEPEND[html/man3/EVP_PKEY_get_size.html]=man3/EVP_PKEY_get_size.pod +GENERATE[html/man3/EVP_PKEY_get_size.html]=man3/EVP_PKEY_get_size.pod +DEPEND[man/man3/EVP_PKEY_get_size.3]=man3/EVP_PKEY_get_size.pod +GENERATE[man/man3/EVP_PKEY_get_size.3]=man3/EVP_PKEY_get_size.pod +DEPEND[html/man3/EVP_PKEY_gettable_params.html]=man3/EVP_PKEY_gettable_params.pod +GENERATE[html/man3/EVP_PKEY_gettable_params.html]=man3/EVP_PKEY_gettable_params.pod +DEPEND[man/man3/EVP_PKEY_gettable_params.3]=man3/EVP_PKEY_gettable_params.pod +GENERATE[man/man3/EVP_PKEY_gettable_params.3]=man3/EVP_PKEY_gettable_params.pod +DEPEND[html/man3/EVP_PKEY_is_a.html]=man3/EVP_PKEY_is_a.pod +GENERATE[html/man3/EVP_PKEY_is_a.html]=man3/EVP_PKEY_is_a.pod +DEPEND[man/man3/EVP_PKEY_is_a.3]=man3/EVP_PKEY_is_a.pod +GENERATE[man/man3/EVP_PKEY_is_a.3]=man3/EVP_PKEY_is_a.pod +DEPEND[html/man3/EVP_PKEY_keygen.html]=man3/EVP_PKEY_keygen.pod +GENERATE[html/man3/EVP_PKEY_keygen.html]=man3/EVP_PKEY_keygen.pod +DEPEND[man/man3/EVP_PKEY_keygen.3]=man3/EVP_PKEY_keygen.pod +GENERATE[man/man3/EVP_PKEY_keygen.3]=man3/EVP_PKEY_keygen.pod +DEPEND[html/man3/EVP_PKEY_meth_get_count.html]=man3/EVP_PKEY_meth_get_count.pod +GENERATE[html/man3/EVP_PKEY_meth_get_count.html]=man3/EVP_PKEY_meth_get_count.pod +DEPEND[man/man3/EVP_PKEY_meth_get_count.3]=man3/EVP_PKEY_meth_get_count.pod +GENERATE[man/man3/EVP_PKEY_meth_get_count.3]=man3/EVP_PKEY_meth_get_count.pod +DEPEND[html/man3/EVP_PKEY_meth_new.html]=man3/EVP_PKEY_meth_new.pod +GENERATE[html/man3/EVP_PKEY_meth_new.html]=man3/EVP_PKEY_meth_new.pod +DEPEND[man/man3/EVP_PKEY_meth_new.3]=man3/EVP_PKEY_meth_new.pod +GENERATE[man/man3/EVP_PKEY_meth_new.3]=man3/EVP_PKEY_meth_new.pod +DEPEND[html/man3/EVP_PKEY_new.html]=man3/EVP_PKEY_new.pod +GENERATE[html/man3/EVP_PKEY_new.html]=man3/EVP_PKEY_new.pod +DEPEND[man/man3/EVP_PKEY_new.3]=man3/EVP_PKEY_new.pod +GENERATE[man/man3/EVP_PKEY_new.3]=man3/EVP_PKEY_new.pod +DEPEND[html/man3/EVP_PKEY_print_private.html]=man3/EVP_PKEY_print_private.pod +GENERATE[html/man3/EVP_PKEY_print_private.html]=man3/EVP_PKEY_print_private.pod +DEPEND[man/man3/EVP_PKEY_print_private.3]=man3/EVP_PKEY_print_private.pod +GENERATE[man/man3/EVP_PKEY_print_private.3]=man3/EVP_PKEY_print_private.pod +DEPEND[html/man3/EVP_PKEY_set1_RSA.html]=man3/EVP_PKEY_set1_RSA.pod +GENERATE[html/man3/EVP_PKEY_set1_RSA.html]=man3/EVP_PKEY_set1_RSA.pod +DEPEND[man/man3/EVP_PKEY_set1_RSA.3]=man3/EVP_PKEY_set1_RSA.pod +GENERATE[man/man3/EVP_PKEY_set1_RSA.3]=man3/EVP_PKEY_set1_RSA.pod +DEPEND[html/man3/EVP_PKEY_set1_encoded_public_key.html]=man3/EVP_PKEY_set1_encoded_public_key.pod +GENERATE[html/man3/EVP_PKEY_set1_encoded_public_key.html]=man3/EVP_PKEY_set1_encoded_public_key.pod +DEPEND[man/man3/EVP_PKEY_set1_encoded_public_key.3]=man3/EVP_PKEY_set1_encoded_public_key.pod +GENERATE[man/man3/EVP_PKEY_set1_encoded_public_key.3]=man3/EVP_PKEY_set1_encoded_public_key.pod +DEPEND[html/man3/EVP_PKEY_set_type.html]=man3/EVP_PKEY_set_type.pod +GENERATE[html/man3/EVP_PKEY_set_type.html]=man3/EVP_PKEY_set_type.pod +DEPEND[man/man3/EVP_PKEY_set_type.3]=man3/EVP_PKEY_set_type.pod +GENERATE[man/man3/EVP_PKEY_set_type.3]=man3/EVP_PKEY_set_type.pod +DEPEND[html/man3/EVP_PKEY_settable_params.html]=man3/EVP_PKEY_settable_params.pod +GENERATE[html/man3/EVP_PKEY_settable_params.html]=man3/EVP_PKEY_settable_params.pod +DEPEND[man/man3/EVP_PKEY_settable_params.3]=man3/EVP_PKEY_settable_params.pod +GENERATE[man/man3/EVP_PKEY_settable_params.3]=man3/EVP_PKEY_settable_params.pod +DEPEND[html/man3/EVP_PKEY_sign.html]=man3/EVP_PKEY_sign.pod +GENERATE[html/man3/EVP_PKEY_sign.html]=man3/EVP_PKEY_sign.pod +DEPEND[man/man3/EVP_PKEY_sign.3]=man3/EVP_PKEY_sign.pod +GENERATE[man/man3/EVP_PKEY_sign.3]=man3/EVP_PKEY_sign.pod +DEPEND[html/man3/EVP_PKEY_todata.html]=man3/EVP_PKEY_todata.pod +GENERATE[html/man3/EVP_PKEY_todata.html]=man3/EVP_PKEY_todata.pod +DEPEND[man/man3/EVP_PKEY_todata.3]=man3/EVP_PKEY_todata.pod +GENERATE[man/man3/EVP_PKEY_todata.3]=man3/EVP_PKEY_todata.pod +DEPEND[html/man3/EVP_PKEY_verify.html]=man3/EVP_PKEY_verify.pod +GENERATE[html/man3/EVP_PKEY_verify.html]=man3/EVP_PKEY_verify.pod +DEPEND[man/man3/EVP_PKEY_verify.3]=man3/EVP_PKEY_verify.pod +GENERATE[man/man3/EVP_PKEY_verify.3]=man3/EVP_PKEY_verify.pod +DEPEND[html/man3/EVP_PKEY_verify_recover.html]=man3/EVP_PKEY_verify_recover.pod +GENERATE[html/man3/EVP_PKEY_verify_recover.html]=man3/EVP_PKEY_verify_recover.pod +DEPEND[man/man3/EVP_PKEY_verify_recover.3]=man3/EVP_PKEY_verify_recover.pod +GENERATE[man/man3/EVP_PKEY_verify_recover.3]=man3/EVP_PKEY_verify_recover.pod +DEPEND[html/man3/EVP_RAND.html]=man3/EVP_RAND.pod +GENERATE[html/man3/EVP_RAND.html]=man3/EVP_RAND.pod +DEPEND[man/man3/EVP_RAND.3]=man3/EVP_RAND.pod +GENERATE[man/man3/EVP_RAND.3]=man3/EVP_RAND.pod +DEPEND[html/man3/EVP_SIGNATURE.html]=man3/EVP_SIGNATURE.pod +GENERATE[html/man3/EVP_SIGNATURE.html]=man3/EVP_SIGNATURE.pod +DEPEND[man/man3/EVP_SIGNATURE.3]=man3/EVP_SIGNATURE.pod +GENERATE[man/man3/EVP_SIGNATURE.3]=man3/EVP_SIGNATURE.pod +DEPEND[html/man3/EVP_SealInit.html]=man3/EVP_SealInit.pod +GENERATE[html/man3/EVP_SealInit.html]=man3/EVP_SealInit.pod +DEPEND[man/man3/EVP_SealInit.3]=man3/EVP_SealInit.pod +GENERATE[man/man3/EVP_SealInit.3]=man3/EVP_SealInit.pod +DEPEND[html/man3/EVP_SignInit.html]=man3/EVP_SignInit.pod +GENERATE[html/man3/EVP_SignInit.html]=man3/EVP_SignInit.pod +DEPEND[man/man3/EVP_SignInit.3]=man3/EVP_SignInit.pod +GENERATE[man/man3/EVP_SignInit.3]=man3/EVP_SignInit.pod +DEPEND[html/man3/EVP_VerifyInit.html]=man3/EVP_VerifyInit.pod +GENERATE[html/man3/EVP_VerifyInit.html]=man3/EVP_VerifyInit.pod +DEPEND[man/man3/EVP_VerifyInit.3]=man3/EVP_VerifyInit.pod +GENERATE[man/man3/EVP_VerifyInit.3]=man3/EVP_VerifyInit.pod +DEPEND[html/man3/EVP_aes_128_gcm.html]=man3/EVP_aes_128_gcm.pod +GENERATE[html/man3/EVP_aes_128_gcm.html]=man3/EVP_aes_128_gcm.pod +DEPEND[man/man3/EVP_aes_128_gcm.3]=man3/EVP_aes_128_gcm.pod +GENERATE[man/man3/EVP_aes_128_gcm.3]=man3/EVP_aes_128_gcm.pod +DEPEND[html/man3/EVP_aria_128_gcm.html]=man3/EVP_aria_128_gcm.pod +GENERATE[html/man3/EVP_aria_128_gcm.html]=man3/EVP_aria_128_gcm.pod +DEPEND[man/man3/EVP_aria_128_gcm.3]=man3/EVP_aria_128_gcm.pod +GENERATE[man/man3/EVP_aria_128_gcm.3]=man3/EVP_aria_128_gcm.pod +DEPEND[html/man3/EVP_bf_cbc.html]=man3/EVP_bf_cbc.pod +GENERATE[html/man3/EVP_bf_cbc.html]=man3/EVP_bf_cbc.pod +DEPEND[man/man3/EVP_bf_cbc.3]=man3/EVP_bf_cbc.pod +GENERATE[man/man3/EVP_bf_cbc.3]=man3/EVP_bf_cbc.pod +DEPEND[html/man3/EVP_blake2b512.html]=man3/EVP_blake2b512.pod +GENERATE[html/man3/EVP_blake2b512.html]=man3/EVP_blake2b512.pod +DEPEND[man/man3/EVP_blake2b512.3]=man3/EVP_blake2b512.pod +GENERATE[man/man3/EVP_blake2b512.3]=man3/EVP_blake2b512.pod +DEPEND[html/man3/EVP_camellia_128_ecb.html]=man3/EVP_camellia_128_ecb.pod +GENERATE[html/man3/EVP_camellia_128_ecb.html]=man3/EVP_camellia_128_ecb.pod +DEPEND[man/man3/EVP_camellia_128_ecb.3]=man3/EVP_camellia_128_ecb.pod +GENERATE[man/man3/EVP_camellia_128_ecb.3]=man3/EVP_camellia_128_ecb.pod +DEPEND[html/man3/EVP_cast5_cbc.html]=man3/EVP_cast5_cbc.pod +GENERATE[html/man3/EVP_cast5_cbc.html]=man3/EVP_cast5_cbc.pod +DEPEND[man/man3/EVP_cast5_cbc.3]=man3/EVP_cast5_cbc.pod +GENERATE[man/man3/EVP_cast5_cbc.3]=man3/EVP_cast5_cbc.pod +DEPEND[html/man3/EVP_chacha20.html]=man3/EVP_chacha20.pod +GENERATE[html/man3/EVP_chacha20.html]=man3/EVP_chacha20.pod +DEPEND[man/man3/EVP_chacha20.3]=man3/EVP_chacha20.pod +GENERATE[man/man3/EVP_chacha20.3]=man3/EVP_chacha20.pod +DEPEND[html/man3/EVP_des_cbc.html]=man3/EVP_des_cbc.pod +GENERATE[html/man3/EVP_des_cbc.html]=man3/EVP_des_cbc.pod +DEPEND[man/man3/EVP_des_cbc.3]=man3/EVP_des_cbc.pod +GENERATE[man/man3/EVP_des_cbc.3]=man3/EVP_des_cbc.pod +DEPEND[html/man3/EVP_desx_cbc.html]=man3/EVP_desx_cbc.pod +GENERATE[html/man3/EVP_desx_cbc.html]=man3/EVP_desx_cbc.pod +DEPEND[man/man3/EVP_desx_cbc.3]=man3/EVP_desx_cbc.pod +GENERATE[man/man3/EVP_desx_cbc.3]=man3/EVP_desx_cbc.pod +DEPEND[html/man3/EVP_idea_cbc.html]=man3/EVP_idea_cbc.pod +GENERATE[html/man3/EVP_idea_cbc.html]=man3/EVP_idea_cbc.pod +DEPEND[man/man3/EVP_idea_cbc.3]=man3/EVP_idea_cbc.pod +GENERATE[man/man3/EVP_idea_cbc.3]=man3/EVP_idea_cbc.pod +DEPEND[html/man3/EVP_md2.html]=man3/EVP_md2.pod +GENERATE[html/man3/EVP_md2.html]=man3/EVP_md2.pod +DEPEND[man/man3/EVP_md2.3]=man3/EVP_md2.pod +GENERATE[man/man3/EVP_md2.3]=man3/EVP_md2.pod +DEPEND[html/man3/EVP_md4.html]=man3/EVP_md4.pod +GENERATE[html/man3/EVP_md4.html]=man3/EVP_md4.pod +DEPEND[man/man3/EVP_md4.3]=man3/EVP_md4.pod +GENERATE[man/man3/EVP_md4.3]=man3/EVP_md4.pod +DEPEND[html/man3/EVP_md5.html]=man3/EVP_md5.pod +GENERATE[html/man3/EVP_md5.html]=man3/EVP_md5.pod +DEPEND[man/man3/EVP_md5.3]=man3/EVP_md5.pod +GENERATE[man/man3/EVP_md5.3]=man3/EVP_md5.pod +DEPEND[html/man3/EVP_mdc2.html]=man3/EVP_mdc2.pod +GENERATE[html/man3/EVP_mdc2.html]=man3/EVP_mdc2.pod +DEPEND[man/man3/EVP_mdc2.3]=man3/EVP_mdc2.pod +GENERATE[man/man3/EVP_mdc2.3]=man3/EVP_mdc2.pod +DEPEND[html/man3/EVP_rc2_cbc.html]=man3/EVP_rc2_cbc.pod +GENERATE[html/man3/EVP_rc2_cbc.html]=man3/EVP_rc2_cbc.pod +DEPEND[man/man3/EVP_rc2_cbc.3]=man3/EVP_rc2_cbc.pod +GENERATE[man/man3/EVP_rc2_cbc.3]=man3/EVP_rc2_cbc.pod +DEPEND[html/man3/EVP_rc4.html]=man3/EVP_rc4.pod +GENERATE[html/man3/EVP_rc4.html]=man3/EVP_rc4.pod +DEPEND[man/man3/EVP_rc4.3]=man3/EVP_rc4.pod +GENERATE[man/man3/EVP_rc4.3]=man3/EVP_rc4.pod +DEPEND[html/man3/EVP_rc5_32_12_16_cbc.html]=man3/EVP_rc5_32_12_16_cbc.pod +GENERATE[html/man3/EVP_rc5_32_12_16_cbc.html]=man3/EVP_rc5_32_12_16_cbc.pod +DEPEND[man/man3/EVP_rc5_32_12_16_cbc.3]=man3/EVP_rc5_32_12_16_cbc.pod +GENERATE[man/man3/EVP_rc5_32_12_16_cbc.3]=man3/EVP_rc5_32_12_16_cbc.pod +DEPEND[html/man3/EVP_ripemd160.html]=man3/EVP_ripemd160.pod +GENERATE[html/man3/EVP_ripemd160.html]=man3/EVP_ripemd160.pod +DEPEND[man/man3/EVP_ripemd160.3]=man3/EVP_ripemd160.pod +GENERATE[man/man3/EVP_ripemd160.3]=man3/EVP_ripemd160.pod +DEPEND[html/man3/EVP_seed_cbc.html]=man3/EVP_seed_cbc.pod +GENERATE[html/man3/EVP_seed_cbc.html]=man3/EVP_seed_cbc.pod +DEPEND[man/man3/EVP_seed_cbc.3]=man3/EVP_seed_cbc.pod +GENERATE[man/man3/EVP_seed_cbc.3]=man3/EVP_seed_cbc.pod +DEPEND[html/man3/EVP_set_default_properties.html]=man3/EVP_set_default_properties.pod +GENERATE[html/man3/EVP_set_default_properties.html]=man3/EVP_set_default_properties.pod +DEPEND[man/man3/EVP_set_default_properties.3]=man3/EVP_set_default_properties.pod +GENERATE[man/man3/EVP_set_default_properties.3]=man3/EVP_set_default_properties.pod +DEPEND[html/man3/EVP_sha1.html]=man3/EVP_sha1.pod +GENERATE[html/man3/EVP_sha1.html]=man3/EVP_sha1.pod +DEPEND[man/man3/EVP_sha1.3]=man3/EVP_sha1.pod +GENERATE[man/man3/EVP_sha1.3]=man3/EVP_sha1.pod +DEPEND[html/man3/EVP_sha224.html]=man3/EVP_sha224.pod +GENERATE[html/man3/EVP_sha224.html]=man3/EVP_sha224.pod +DEPEND[man/man3/EVP_sha224.3]=man3/EVP_sha224.pod +GENERATE[man/man3/EVP_sha224.3]=man3/EVP_sha224.pod +DEPEND[html/man3/EVP_sha3_224.html]=man3/EVP_sha3_224.pod +GENERATE[html/man3/EVP_sha3_224.html]=man3/EVP_sha3_224.pod +DEPEND[man/man3/EVP_sha3_224.3]=man3/EVP_sha3_224.pod +GENERATE[man/man3/EVP_sha3_224.3]=man3/EVP_sha3_224.pod +DEPEND[html/man3/EVP_sm3.html]=man3/EVP_sm3.pod +GENERATE[html/man3/EVP_sm3.html]=man3/EVP_sm3.pod +DEPEND[man/man3/EVP_sm3.3]=man3/EVP_sm3.pod +GENERATE[man/man3/EVP_sm3.3]=man3/EVP_sm3.pod +DEPEND[html/man3/EVP_sm4_cbc.html]=man3/EVP_sm4_cbc.pod +GENERATE[html/man3/EVP_sm4_cbc.html]=man3/EVP_sm4_cbc.pod +DEPEND[man/man3/EVP_sm4_cbc.3]=man3/EVP_sm4_cbc.pod +GENERATE[man/man3/EVP_sm4_cbc.3]=man3/EVP_sm4_cbc.pod +DEPEND[html/man3/EVP_whirlpool.html]=man3/EVP_whirlpool.pod +GENERATE[html/man3/EVP_whirlpool.html]=man3/EVP_whirlpool.pod +DEPEND[man/man3/EVP_whirlpool.3]=man3/EVP_whirlpool.pod +GENERATE[man/man3/EVP_whirlpool.3]=man3/EVP_whirlpool.pod +DEPEND[html/man3/HMAC.html]=man3/HMAC.pod +GENERATE[html/man3/HMAC.html]=man3/HMAC.pod +DEPEND[man/man3/HMAC.3]=man3/HMAC.pod +GENERATE[man/man3/HMAC.3]=man3/HMAC.pod +DEPEND[html/man3/MD5.html]=man3/MD5.pod +GENERATE[html/man3/MD5.html]=man3/MD5.pod +DEPEND[man/man3/MD5.3]=man3/MD5.pod +GENERATE[man/man3/MD5.3]=man3/MD5.pod +DEPEND[html/man3/MDC2_Init.html]=man3/MDC2_Init.pod +GENERATE[html/man3/MDC2_Init.html]=man3/MDC2_Init.pod +DEPEND[man/man3/MDC2_Init.3]=man3/MDC2_Init.pod +GENERATE[man/man3/MDC2_Init.3]=man3/MDC2_Init.pod +DEPEND[html/man3/NCONF_new_ex.html]=man3/NCONF_new_ex.pod +GENERATE[html/man3/NCONF_new_ex.html]=man3/NCONF_new_ex.pod +DEPEND[man/man3/NCONF_new_ex.3]=man3/NCONF_new_ex.pod +GENERATE[man/man3/NCONF_new_ex.3]=man3/NCONF_new_ex.pod +DEPEND[html/man3/OBJ_nid2obj.html]=man3/OBJ_nid2obj.pod +GENERATE[html/man3/OBJ_nid2obj.html]=man3/OBJ_nid2obj.pod +DEPEND[man/man3/OBJ_nid2obj.3]=man3/OBJ_nid2obj.pod +GENERATE[man/man3/OBJ_nid2obj.3]=man3/OBJ_nid2obj.pod +DEPEND[html/man3/OCSP_REQUEST_new.html]=man3/OCSP_REQUEST_new.pod +GENERATE[html/man3/OCSP_REQUEST_new.html]=man3/OCSP_REQUEST_new.pod +DEPEND[man/man3/OCSP_REQUEST_new.3]=man3/OCSP_REQUEST_new.pod +GENERATE[man/man3/OCSP_REQUEST_new.3]=man3/OCSP_REQUEST_new.pod +DEPEND[html/man3/OCSP_cert_to_id.html]=man3/OCSP_cert_to_id.pod +GENERATE[html/man3/OCSP_cert_to_id.html]=man3/OCSP_cert_to_id.pod +DEPEND[man/man3/OCSP_cert_to_id.3]=man3/OCSP_cert_to_id.pod +GENERATE[man/man3/OCSP_cert_to_id.3]=man3/OCSP_cert_to_id.pod +DEPEND[html/man3/OCSP_request_add1_nonce.html]=man3/OCSP_request_add1_nonce.pod +GENERATE[html/man3/OCSP_request_add1_nonce.html]=man3/OCSP_request_add1_nonce.pod +DEPEND[man/man3/OCSP_request_add1_nonce.3]=man3/OCSP_request_add1_nonce.pod +GENERATE[man/man3/OCSP_request_add1_nonce.3]=man3/OCSP_request_add1_nonce.pod +DEPEND[html/man3/OCSP_resp_find_status.html]=man3/OCSP_resp_find_status.pod +GENERATE[html/man3/OCSP_resp_find_status.html]=man3/OCSP_resp_find_status.pod +DEPEND[man/man3/OCSP_resp_find_status.3]=man3/OCSP_resp_find_status.pod +GENERATE[man/man3/OCSP_resp_find_status.3]=man3/OCSP_resp_find_status.pod +DEPEND[html/man3/OCSP_response_status.html]=man3/OCSP_response_status.pod +GENERATE[html/man3/OCSP_response_status.html]=man3/OCSP_response_status.pod +DEPEND[man/man3/OCSP_response_status.3]=man3/OCSP_response_status.pod +GENERATE[man/man3/OCSP_response_status.3]=man3/OCSP_response_status.pod +DEPEND[html/man3/OCSP_sendreq_new.html]=man3/OCSP_sendreq_new.pod +GENERATE[html/man3/OCSP_sendreq_new.html]=man3/OCSP_sendreq_new.pod +DEPEND[man/man3/OCSP_sendreq_new.3]=man3/OCSP_sendreq_new.pod +GENERATE[man/man3/OCSP_sendreq_new.3]=man3/OCSP_sendreq_new.pod +DEPEND[html/man3/OPENSSL_Applink.html]=man3/OPENSSL_Applink.pod +GENERATE[html/man3/OPENSSL_Applink.html]=man3/OPENSSL_Applink.pod +DEPEND[man/man3/OPENSSL_Applink.3]=man3/OPENSSL_Applink.pod +GENERATE[man/man3/OPENSSL_Applink.3]=man3/OPENSSL_Applink.pod +DEPEND[html/man3/OPENSSL_FILE.html]=man3/OPENSSL_FILE.pod +GENERATE[html/man3/OPENSSL_FILE.html]=man3/OPENSSL_FILE.pod +DEPEND[man/man3/OPENSSL_FILE.3]=man3/OPENSSL_FILE.pod +GENERATE[man/man3/OPENSSL_FILE.3]=man3/OPENSSL_FILE.pod +DEPEND[html/man3/OPENSSL_LH_COMPFUNC.html]=man3/OPENSSL_LH_COMPFUNC.pod +GENERATE[html/man3/OPENSSL_LH_COMPFUNC.html]=man3/OPENSSL_LH_COMPFUNC.pod +DEPEND[man/man3/OPENSSL_LH_COMPFUNC.3]=man3/OPENSSL_LH_COMPFUNC.pod +GENERATE[man/man3/OPENSSL_LH_COMPFUNC.3]=man3/OPENSSL_LH_COMPFUNC.pod +DEPEND[html/man3/OPENSSL_LH_stats.html]=man3/OPENSSL_LH_stats.pod +GENERATE[html/man3/OPENSSL_LH_stats.html]=man3/OPENSSL_LH_stats.pod +DEPEND[man/man3/OPENSSL_LH_stats.3]=man3/OPENSSL_LH_stats.pod +GENERATE[man/man3/OPENSSL_LH_stats.3]=man3/OPENSSL_LH_stats.pod +DEPEND[html/man3/OPENSSL_config.html]=man3/OPENSSL_config.pod +GENERATE[html/man3/OPENSSL_config.html]=man3/OPENSSL_config.pod +DEPEND[man/man3/OPENSSL_config.3]=man3/OPENSSL_config.pod +GENERATE[man/man3/OPENSSL_config.3]=man3/OPENSSL_config.pod +DEPEND[html/man3/OPENSSL_fork_prepare.html]=man3/OPENSSL_fork_prepare.pod +GENERATE[html/man3/OPENSSL_fork_prepare.html]=man3/OPENSSL_fork_prepare.pod +DEPEND[man/man3/OPENSSL_fork_prepare.3]=man3/OPENSSL_fork_prepare.pod +GENERATE[man/man3/OPENSSL_fork_prepare.3]=man3/OPENSSL_fork_prepare.pod +DEPEND[html/man3/OPENSSL_gmtime.html]=man3/OPENSSL_gmtime.pod +GENERATE[html/man3/OPENSSL_gmtime.html]=man3/OPENSSL_gmtime.pod +DEPEND[man/man3/OPENSSL_gmtime.3]=man3/OPENSSL_gmtime.pod +GENERATE[man/man3/OPENSSL_gmtime.3]=man3/OPENSSL_gmtime.pod +DEPEND[html/man3/OPENSSL_hexchar2int.html]=man3/OPENSSL_hexchar2int.pod +GENERATE[html/man3/OPENSSL_hexchar2int.html]=man3/OPENSSL_hexchar2int.pod +DEPEND[man/man3/OPENSSL_hexchar2int.3]=man3/OPENSSL_hexchar2int.pod +GENERATE[man/man3/OPENSSL_hexchar2int.3]=man3/OPENSSL_hexchar2int.pod +DEPEND[html/man3/OPENSSL_ia32cap.html]=man3/OPENSSL_ia32cap.pod +GENERATE[html/man3/OPENSSL_ia32cap.html]=man3/OPENSSL_ia32cap.pod +DEPEND[man/man3/OPENSSL_ia32cap.3]=man3/OPENSSL_ia32cap.pod +GENERATE[man/man3/OPENSSL_ia32cap.3]=man3/OPENSSL_ia32cap.pod +DEPEND[html/man3/OPENSSL_init_crypto.html]=man3/OPENSSL_init_crypto.pod +GENERATE[html/man3/OPENSSL_init_crypto.html]=man3/OPENSSL_init_crypto.pod +DEPEND[man/man3/OPENSSL_init_crypto.3]=man3/OPENSSL_init_crypto.pod +GENERATE[man/man3/OPENSSL_init_crypto.3]=man3/OPENSSL_init_crypto.pod +DEPEND[html/man3/OPENSSL_init_ssl.html]=man3/OPENSSL_init_ssl.pod +GENERATE[html/man3/OPENSSL_init_ssl.html]=man3/OPENSSL_init_ssl.pod +DEPEND[man/man3/OPENSSL_init_ssl.3]=man3/OPENSSL_init_ssl.pod +GENERATE[man/man3/OPENSSL_init_ssl.3]=man3/OPENSSL_init_ssl.pod +DEPEND[html/man3/OPENSSL_instrument_bus.html]=man3/OPENSSL_instrument_bus.pod +GENERATE[html/man3/OPENSSL_instrument_bus.html]=man3/OPENSSL_instrument_bus.pod +DEPEND[man/man3/OPENSSL_instrument_bus.3]=man3/OPENSSL_instrument_bus.pod +GENERATE[man/man3/OPENSSL_instrument_bus.3]=man3/OPENSSL_instrument_bus.pod +DEPEND[html/man3/OPENSSL_load_builtin_modules.html]=man3/OPENSSL_load_builtin_modules.pod +GENERATE[html/man3/OPENSSL_load_builtin_modules.html]=man3/OPENSSL_load_builtin_modules.pod +DEPEND[man/man3/OPENSSL_load_builtin_modules.3]=man3/OPENSSL_load_builtin_modules.pod +GENERATE[man/man3/OPENSSL_load_builtin_modules.3]=man3/OPENSSL_load_builtin_modules.pod +DEPEND[html/man3/OPENSSL_malloc.html]=man3/OPENSSL_malloc.pod +GENERATE[html/man3/OPENSSL_malloc.html]=man3/OPENSSL_malloc.pod +DEPEND[man/man3/OPENSSL_malloc.3]=man3/OPENSSL_malloc.pod +GENERATE[man/man3/OPENSSL_malloc.3]=man3/OPENSSL_malloc.pod +DEPEND[html/man3/OPENSSL_s390xcap.html]=man3/OPENSSL_s390xcap.pod +GENERATE[html/man3/OPENSSL_s390xcap.html]=man3/OPENSSL_s390xcap.pod +DEPEND[man/man3/OPENSSL_s390xcap.3]=man3/OPENSSL_s390xcap.pod +GENERATE[man/man3/OPENSSL_s390xcap.3]=man3/OPENSSL_s390xcap.pod +DEPEND[html/man3/OPENSSL_secure_malloc.html]=man3/OPENSSL_secure_malloc.pod +GENERATE[html/man3/OPENSSL_secure_malloc.html]=man3/OPENSSL_secure_malloc.pod +DEPEND[man/man3/OPENSSL_secure_malloc.3]=man3/OPENSSL_secure_malloc.pod +GENERATE[man/man3/OPENSSL_secure_malloc.3]=man3/OPENSSL_secure_malloc.pod +DEPEND[html/man3/OPENSSL_strcasecmp.html]=man3/OPENSSL_strcasecmp.pod +GENERATE[html/man3/OPENSSL_strcasecmp.html]=man3/OPENSSL_strcasecmp.pod +DEPEND[man/man3/OPENSSL_strcasecmp.3]=man3/OPENSSL_strcasecmp.pod +GENERATE[man/man3/OPENSSL_strcasecmp.3]=man3/OPENSSL_strcasecmp.pod +DEPEND[html/man3/OSSL_ALGORITHM.html]=man3/OSSL_ALGORITHM.pod +GENERATE[html/man3/OSSL_ALGORITHM.html]=man3/OSSL_ALGORITHM.pod +DEPEND[man/man3/OSSL_ALGORITHM.3]=man3/OSSL_ALGORITHM.pod +GENERATE[man/man3/OSSL_ALGORITHM.3]=man3/OSSL_ALGORITHM.pod +DEPEND[html/man3/OSSL_CALLBACK.html]=man3/OSSL_CALLBACK.pod +GENERATE[html/man3/OSSL_CALLBACK.html]=man3/OSSL_CALLBACK.pod +DEPEND[man/man3/OSSL_CALLBACK.3]=man3/OSSL_CALLBACK.pod +GENERATE[man/man3/OSSL_CALLBACK.3]=man3/OSSL_CALLBACK.pod +DEPEND[html/man3/OSSL_CMP_CTX_new.html]=man3/OSSL_CMP_CTX_new.pod +GENERATE[html/man3/OSSL_CMP_CTX_new.html]=man3/OSSL_CMP_CTX_new.pod +DEPEND[man/man3/OSSL_CMP_CTX_new.3]=man3/OSSL_CMP_CTX_new.pod +GENERATE[man/man3/OSSL_CMP_CTX_new.3]=man3/OSSL_CMP_CTX_new.pod +DEPEND[html/man3/OSSL_CMP_HDR_get0_transactionID.html]=man3/OSSL_CMP_HDR_get0_transactionID.pod +GENERATE[html/man3/OSSL_CMP_HDR_get0_transactionID.html]=man3/OSSL_CMP_HDR_get0_transactionID.pod +DEPEND[man/man3/OSSL_CMP_HDR_get0_transactionID.3]=man3/OSSL_CMP_HDR_get0_transactionID.pod +GENERATE[man/man3/OSSL_CMP_HDR_get0_transactionID.3]=man3/OSSL_CMP_HDR_get0_transactionID.pod +DEPEND[html/man3/OSSL_CMP_ITAV_set0.html]=man3/OSSL_CMP_ITAV_set0.pod +GENERATE[html/man3/OSSL_CMP_ITAV_set0.html]=man3/OSSL_CMP_ITAV_set0.pod +DEPEND[man/man3/OSSL_CMP_ITAV_set0.3]=man3/OSSL_CMP_ITAV_set0.pod +GENERATE[man/man3/OSSL_CMP_ITAV_set0.3]=man3/OSSL_CMP_ITAV_set0.pod +DEPEND[html/man3/OSSL_CMP_MSG_get0_header.html]=man3/OSSL_CMP_MSG_get0_header.pod +GENERATE[html/man3/OSSL_CMP_MSG_get0_header.html]=man3/OSSL_CMP_MSG_get0_header.pod +DEPEND[man/man3/OSSL_CMP_MSG_get0_header.3]=man3/OSSL_CMP_MSG_get0_header.pod +GENERATE[man/man3/OSSL_CMP_MSG_get0_header.3]=man3/OSSL_CMP_MSG_get0_header.pod +DEPEND[html/man3/OSSL_CMP_MSG_http_perform.html]=man3/OSSL_CMP_MSG_http_perform.pod +GENERATE[html/man3/OSSL_CMP_MSG_http_perform.html]=man3/OSSL_CMP_MSG_http_perform.pod +DEPEND[man/man3/OSSL_CMP_MSG_http_perform.3]=man3/OSSL_CMP_MSG_http_perform.pod +GENERATE[man/man3/OSSL_CMP_MSG_http_perform.3]=man3/OSSL_CMP_MSG_http_perform.pod +DEPEND[html/man3/OSSL_CMP_SRV_CTX_new.html]=man3/OSSL_CMP_SRV_CTX_new.pod +GENERATE[html/man3/OSSL_CMP_SRV_CTX_new.html]=man3/OSSL_CMP_SRV_CTX_new.pod +DEPEND[man/man3/OSSL_CMP_SRV_CTX_new.3]=man3/OSSL_CMP_SRV_CTX_new.pod +GENERATE[man/man3/OSSL_CMP_SRV_CTX_new.3]=man3/OSSL_CMP_SRV_CTX_new.pod +DEPEND[html/man3/OSSL_CMP_STATUSINFO_new.html]=man3/OSSL_CMP_STATUSINFO_new.pod +GENERATE[html/man3/OSSL_CMP_STATUSINFO_new.html]=man3/OSSL_CMP_STATUSINFO_new.pod +DEPEND[man/man3/OSSL_CMP_STATUSINFO_new.3]=man3/OSSL_CMP_STATUSINFO_new.pod +GENERATE[man/man3/OSSL_CMP_STATUSINFO_new.3]=man3/OSSL_CMP_STATUSINFO_new.pod +DEPEND[html/man3/OSSL_CMP_exec_certreq.html]=man3/OSSL_CMP_exec_certreq.pod +GENERATE[html/man3/OSSL_CMP_exec_certreq.html]=man3/OSSL_CMP_exec_certreq.pod +DEPEND[man/man3/OSSL_CMP_exec_certreq.3]=man3/OSSL_CMP_exec_certreq.pod +GENERATE[man/man3/OSSL_CMP_exec_certreq.3]=man3/OSSL_CMP_exec_certreq.pod +DEPEND[html/man3/OSSL_CMP_log_open.html]=man3/OSSL_CMP_log_open.pod +GENERATE[html/man3/OSSL_CMP_log_open.html]=man3/OSSL_CMP_log_open.pod +DEPEND[man/man3/OSSL_CMP_log_open.3]=man3/OSSL_CMP_log_open.pod +GENERATE[man/man3/OSSL_CMP_log_open.3]=man3/OSSL_CMP_log_open.pod +DEPEND[html/man3/OSSL_CMP_validate_msg.html]=man3/OSSL_CMP_validate_msg.pod +GENERATE[html/man3/OSSL_CMP_validate_msg.html]=man3/OSSL_CMP_validate_msg.pod +DEPEND[man/man3/OSSL_CMP_validate_msg.3]=man3/OSSL_CMP_validate_msg.pod +GENERATE[man/man3/OSSL_CMP_validate_msg.3]=man3/OSSL_CMP_validate_msg.pod +DEPEND[html/man3/OSSL_CORE_MAKE_FUNC.html]=man3/OSSL_CORE_MAKE_FUNC.pod +GENERATE[html/man3/OSSL_CORE_MAKE_FUNC.html]=man3/OSSL_CORE_MAKE_FUNC.pod +DEPEND[man/man3/OSSL_CORE_MAKE_FUNC.3]=man3/OSSL_CORE_MAKE_FUNC.pod +GENERATE[man/man3/OSSL_CORE_MAKE_FUNC.3]=man3/OSSL_CORE_MAKE_FUNC.pod +DEPEND[html/man3/OSSL_CRMF_MSG_get0_tmpl.html]=man3/OSSL_CRMF_MSG_get0_tmpl.pod +GENERATE[html/man3/OSSL_CRMF_MSG_get0_tmpl.html]=man3/OSSL_CRMF_MSG_get0_tmpl.pod +DEPEND[man/man3/OSSL_CRMF_MSG_get0_tmpl.3]=man3/OSSL_CRMF_MSG_get0_tmpl.pod +GENERATE[man/man3/OSSL_CRMF_MSG_get0_tmpl.3]=man3/OSSL_CRMF_MSG_get0_tmpl.pod +DEPEND[html/man3/OSSL_CRMF_MSG_set0_validity.html]=man3/OSSL_CRMF_MSG_set0_validity.pod +GENERATE[html/man3/OSSL_CRMF_MSG_set0_validity.html]=man3/OSSL_CRMF_MSG_set0_validity.pod +DEPEND[man/man3/OSSL_CRMF_MSG_set0_validity.3]=man3/OSSL_CRMF_MSG_set0_validity.pod +GENERATE[man/man3/OSSL_CRMF_MSG_set0_validity.3]=man3/OSSL_CRMF_MSG_set0_validity.pod +DEPEND[html/man3/OSSL_CRMF_MSG_set1_regCtrl_regToken.html]=man3/OSSL_CRMF_MSG_set1_regCtrl_regToken.pod +GENERATE[html/man3/OSSL_CRMF_MSG_set1_regCtrl_regToken.html]=man3/OSSL_CRMF_MSG_set1_regCtrl_regToken.pod +DEPEND[man/man3/OSSL_CRMF_MSG_set1_regCtrl_regToken.3]=man3/OSSL_CRMF_MSG_set1_regCtrl_regToken.pod +GENERATE[man/man3/OSSL_CRMF_MSG_set1_regCtrl_regToken.3]=man3/OSSL_CRMF_MSG_set1_regCtrl_regToken.pod +DEPEND[html/man3/OSSL_CRMF_MSG_set1_regInfo_certReq.html]=man3/OSSL_CRMF_MSG_set1_regInfo_certReq.pod +GENERATE[html/man3/OSSL_CRMF_MSG_set1_regInfo_certReq.html]=man3/OSSL_CRMF_MSG_set1_regInfo_certReq.pod +DEPEND[man/man3/OSSL_CRMF_MSG_set1_regInfo_certReq.3]=man3/OSSL_CRMF_MSG_set1_regInfo_certReq.pod +GENERATE[man/man3/OSSL_CRMF_MSG_set1_regInfo_certReq.3]=man3/OSSL_CRMF_MSG_set1_regInfo_certReq.pod +DEPEND[html/man3/OSSL_CRMF_pbmp_new.html]=man3/OSSL_CRMF_pbmp_new.pod +GENERATE[html/man3/OSSL_CRMF_pbmp_new.html]=man3/OSSL_CRMF_pbmp_new.pod +DEPEND[man/man3/OSSL_CRMF_pbmp_new.3]=man3/OSSL_CRMF_pbmp_new.pod +GENERATE[man/man3/OSSL_CRMF_pbmp_new.3]=man3/OSSL_CRMF_pbmp_new.pod +DEPEND[html/man3/OSSL_DECODER.html]=man3/OSSL_DECODER.pod +GENERATE[html/man3/OSSL_DECODER.html]=man3/OSSL_DECODER.pod +DEPEND[man/man3/OSSL_DECODER.3]=man3/OSSL_DECODER.pod +GENERATE[man/man3/OSSL_DECODER.3]=man3/OSSL_DECODER.pod +DEPEND[html/man3/OSSL_DECODER_CTX.html]=man3/OSSL_DECODER_CTX.pod +GENERATE[html/man3/OSSL_DECODER_CTX.html]=man3/OSSL_DECODER_CTX.pod +DEPEND[man/man3/OSSL_DECODER_CTX.3]=man3/OSSL_DECODER_CTX.pod +GENERATE[man/man3/OSSL_DECODER_CTX.3]=man3/OSSL_DECODER_CTX.pod +DEPEND[html/man3/OSSL_DECODER_CTX_new_for_pkey.html]=man3/OSSL_DECODER_CTX_new_for_pkey.pod +GENERATE[html/man3/OSSL_DECODER_CTX_new_for_pkey.html]=man3/OSSL_DECODER_CTX_new_for_pkey.pod +DEPEND[man/man3/OSSL_DECODER_CTX_new_for_pkey.3]=man3/OSSL_DECODER_CTX_new_for_pkey.pod +GENERATE[man/man3/OSSL_DECODER_CTX_new_for_pkey.3]=man3/OSSL_DECODER_CTX_new_for_pkey.pod +DEPEND[html/man3/OSSL_DECODER_from_bio.html]=man3/OSSL_DECODER_from_bio.pod +GENERATE[html/man3/OSSL_DECODER_from_bio.html]=man3/OSSL_DECODER_from_bio.pod +DEPEND[man/man3/OSSL_DECODER_from_bio.3]=man3/OSSL_DECODER_from_bio.pod +GENERATE[man/man3/OSSL_DECODER_from_bio.3]=man3/OSSL_DECODER_from_bio.pod +DEPEND[html/man3/OSSL_DISPATCH.html]=man3/OSSL_DISPATCH.pod +GENERATE[html/man3/OSSL_DISPATCH.html]=man3/OSSL_DISPATCH.pod +DEPEND[man/man3/OSSL_DISPATCH.3]=man3/OSSL_DISPATCH.pod +GENERATE[man/man3/OSSL_DISPATCH.3]=man3/OSSL_DISPATCH.pod +DEPEND[html/man3/OSSL_ENCODER.html]=man3/OSSL_ENCODER.pod +GENERATE[html/man3/OSSL_ENCODER.html]=man3/OSSL_ENCODER.pod +DEPEND[man/man3/OSSL_ENCODER.3]=man3/OSSL_ENCODER.pod +GENERATE[man/man3/OSSL_ENCODER.3]=man3/OSSL_ENCODER.pod +DEPEND[html/man3/OSSL_ENCODER_CTX.html]=man3/OSSL_ENCODER_CTX.pod +GENERATE[html/man3/OSSL_ENCODER_CTX.html]=man3/OSSL_ENCODER_CTX.pod +DEPEND[man/man3/OSSL_ENCODER_CTX.3]=man3/OSSL_ENCODER_CTX.pod +GENERATE[man/man3/OSSL_ENCODER_CTX.3]=man3/OSSL_ENCODER_CTX.pod +DEPEND[html/man3/OSSL_ENCODER_CTX_new_for_pkey.html]=man3/OSSL_ENCODER_CTX_new_for_pkey.pod +GENERATE[html/man3/OSSL_ENCODER_CTX_new_for_pkey.html]=man3/OSSL_ENCODER_CTX_new_for_pkey.pod +DEPEND[man/man3/OSSL_ENCODER_CTX_new_for_pkey.3]=man3/OSSL_ENCODER_CTX_new_for_pkey.pod +GENERATE[man/man3/OSSL_ENCODER_CTX_new_for_pkey.3]=man3/OSSL_ENCODER_CTX_new_for_pkey.pod +DEPEND[html/man3/OSSL_ENCODER_to_bio.html]=man3/OSSL_ENCODER_to_bio.pod +GENERATE[html/man3/OSSL_ENCODER_to_bio.html]=man3/OSSL_ENCODER_to_bio.pod +DEPEND[man/man3/OSSL_ENCODER_to_bio.3]=man3/OSSL_ENCODER_to_bio.pod +GENERATE[man/man3/OSSL_ENCODER_to_bio.3]=man3/OSSL_ENCODER_to_bio.pod +DEPEND[html/man3/OSSL_ESS_check_signing_certs.html]=man3/OSSL_ESS_check_signing_certs.pod +GENERATE[html/man3/OSSL_ESS_check_signing_certs.html]=man3/OSSL_ESS_check_signing_certs.pod +DEPEND[man/man3/OSSL_ESS_check_signing_certs.3]=man3/OSSL_ESS_check_signing_certs.pod +GENERATE[man/man3/OSSL_ESS_check_signing_certs.3]=man3/OSSL_ESS_check_signing_certs.pod +DEPEND[html/man3/OSSL_HTTP_REQ_CTX.html]=man3/OSSL_HTTP_REQ_CTX.pod +GENERATE[html/man3/OSSL_HTTP_REQ_CTX.html]=man3/OSSL_HTTP_REQ_CTX.pod +DEPEND[man/man3/OSSL_HTTP_REQ_CTX.3]=man3/OSSL_HTTP_REQ_CTX.pod +GENERATE[man/man3/OSSL_HTTP_REQ_CTX.3]=man3/OSSL_HTTP_REQ_CTX.pod +DEPEND[html/man3/OSSL_HTTP_parse_url.html]=man3/OSSL_HTTP_parse_url.pod +GENERATE[html/man3/OSSL_HTTP_parse_url.html]=man3/OSSL_HTTP_parse_url.pod +DEPEND[man/man3/OSSL_HTTP_parse_url.3]=man3/OSSL_HTTP_parse_url.pod +GENERATE[man/man3/OSSL_HTTP_parse_url.3]=man3/OSSL_HTTP_parse_url.pod +DEPEND[html/man3/OSSL_HTTP_transfer.html]=man3/OSSL_HTTP_transfer.pod +GENERATE[html/man3/OSSL_HTTP_transfer.html]=man3/OSSL_HTTP_transfer.pod +DEPEND[man/man3/OSSL_HTTP_transfer.3]=man3/OSSL_HTTP_transfer.pod +GENERATE[man/man3/OSSL_HTTP_transfer.3]=man3/OSSL_HTTP_transfer.pod +DEPEND[html/man3/OSSL_ITEM.html]=man3/OSSL_ITEM.pod +GENERATE[html/man3/OSSL_ITEM.html]=man3/OSSL_ITEM.pod +DEPEND[man/man3/OSSL_ITEM.3]=man3/OSSL_ITEM.pod +GENERATE[man/man3/OSSL_ITEM.3]=man3/OSSL_ITEM.pod +DEPEND[html/man3/OSSL_LIB_CTX.html]=man3/OSSL_LIB_CTX.pod +GENERATE[html/man3/OSSL_LIB_CTX.html]=man3/OSSL_LIB_CTX.pod +DEPEND[man/man3/OSSL_LIB_CTX.3]=man3/OSSL_LIB_CTX.pod +GENERATE[man/man3/OSSL_LIB_CTX.3]=man3/OSSL_LIB_CTX.pod +DEPEND[html/man3/OSSL_PARAM.html]=man3/OSSL_PARAM.pod +GENERATE[html/man3/OSSL_PARAM.html]=man3/OSSL_PARAM.pod +DEPEND[man/man3/OSSL_PARAM.3]=man3/OSSL_PARAM.pod +GENERATE[man/man3/OSSL_PARAM.3]=man3/OSSL_PARAM.pod +DEPEND[html/man3/OSSL_PARAM_BLD.html]=man3/OSSL_PARAM_BLD.pod +GENERATE[html/man3/OSSL_PARAM_BLD.html]=man3/OSSL_PARAM_BLD.pod +DEPEND[man/man3/OSSL_PARAM_BLD.3]=man3/OSSL_PARAM_BLD.pod +GENERATE[man/man3/OSSL_PARAM_BLD.3]=man3/OSSL_PARAM_BLD.pod +DEPEND[html/man3/OSSL_PARAM_allocate_from_text.html]=man3/OSSL_PARAM_allocate_from_text.pod +GENERATE[html/man3/OSSL_PARAM_allocate_from_text.html]=man3/OSSL_PARAM_allocate_from_text.pod +DEPEND[man/man3/OSSL_PARAM_allocate_from_text.3]=man3/OSSL_PARAM_allocate_from_text.pod +GENERATE[man/man3/OSSL_PARAM_allocate_from_text.3]=man3/OSSL_PARAM_allocate_from_text.pod +DEPEND[html/man3/OSSL_PARAM_dup.html]=man3/OSSL_PARAM_dup.pod +GENERATE[html/man3/OSSL_PARAM_dup.html]=man3/OSSL_PARAM_dup.pod +DEPEND[man/man3/OSSL_PARAM_dup.3]=man3/OSSL_PARAM_dup.pod +GENERATE[man/man3/OSSL_PARAM_dup.3]=man3/OSSL_PARAM_dup.pod +DEPEND[html/man3/OSSL_PARAM_int.html]=man3/OSSL_PARAM_int.pod +GENERATE[html/man3/OSSL_PARAM_int.html]=man3/OSSL_PARAM_int.pod +DEPEND[man/man3/OSSL_PARAM_int.3]=man3/OSSL_PARAM_int.pod +GENERATE[man/man3/OSSL_PARAM_int.3]=man3/OSSL_PARAM_int.pod +DEPEND[html/man3/OSSL_PROVIDER.html]=man3/OSSL_PROVIDER.pod +GENERATE[html/man3/OSSL_PROVIDER.html]=man3/OSSL_PROVIDER.pod +DEPEND[man/man3/OSSL_PROVIDER.3]=man3/OSSL_PROVIDER.pod +GENERATE[man/man3/OSSL_PROVIDER.3]=man3/OSSL_PROVIDER.pod +DEPEND[html/man3/OSSL_SELF_TEST_new.html]=man3/OSSL_SELF_TEST_new.pod +GENERATE[html/man3/OSSL_SELF_TEST_new.html]=man3/OSSL_SELF_TEST_new.pod +DEPEND[man/man3/OSSL_SELF_TEST_new.3]=man3/OSSL_SELF_TEST_new.pod +GENERATE[man/man3/OSSL_SELF_TEST_new.3]=man3/OSSL_SELF_TEST_new.pod +DEPEND[html/man3/OSSL_SELF_TEST_set_callback.html]=man3/OSSL_SELF_TEST_set_callback.pod +GENERATE[html/man3/OSSL_SELF_TEST_set_callback.html]=man3/OSSL_SELF_TEST_set_callback.pod +DEPEND[man/man3/OSSL_SELF_TEST_set_callback.3]=man3/OSSL_SELF_TEST_set_callback.pod +GENERATE[man/man3/OSSL_SELF_TEST_set_callback.3]=man3/OSSL_SELF_TEST_set_callback.pod +DEPEND[html/man3/OSSL_STORE_INFO.html]=man3/OSSL_STORE_INFO.pod +GENERATE[html/man3/OSSL_STORE_INFO.html]=man3/OSSL_STORE_INFO.pod +DEPEND[man/man3/OSSL_STORE_INFO.3]=man3/OSSL_STORE_INFO.pod +GENERATE[man/man3/OSSL_STORE_INFO.3]=man3/OSSL_STORE_INFO.pod +DEPEND[html/man3/OSSL_STORE_LOADER.html]=man3/OSSL_STORE_LOADER.pod +GENERATE[html/man3/OSSL_STORE_LOADER.html]=man3/OSSL_STORE_LOADER.pod +DEPEND[man/man3/OSSL_STORE_LOADER.3]=man3/OSSL_STORE_LOADER.pod +GENERATE[man/man3/OSSL_STORE_LOADER.3]=man3/OSSL_STORE_LOADER.pod +DEPEND[html/man3/OSSL_STORE_SEARCH.html]=man3/OSSL_STORE_SEARCH.pod +GENERATE[html/man3/OSSL_STORE_SEARCH.html]=man3/OSSL_STORE_SEARCH.pod +DEPEND[man/man3/OSSL_STORE_SEARCH.3]=man3/OSSL_STORE_SEARCH.pod +GENERATE[man/man3/OSSL_STORE_SEARCH.3]=man3/OSSL_STORE_SEARCH.pod +DEPEND[html/man3/OSSL_STORE_attach.html]=man3/OSSL_STORE_attach.pod +GENERATE[html/man3/OSSL_STORE_attach.html]=man3/OSSL_STORE_attach.pod +DEPEND[man/man3/OSSL_STORE_attach.3]=man3/OSSL_STORE_attach.pod +GENERATE[man/man3/OSSL_STORE_attach.3]=man3/OSSL_STORE_attach.pod +DEPEND[html/man3/OSSL_STORE_expect.html]=man3/OSSL_STORE_expect.pod +GENERATE[html/man3/OSSL_STORE_expect.html]=man3/OSSL_STORE_expect.pod +DEPEND[man/man3/OSSL_STORE_expect.3]=man3/OSSL_STORE_expect.pod +GENERATE[man/man3/OSSL_STORE_expect.3]=man3/OSSL_STORE_expect.pod +DEPEND[html/man3/OSSL_STORE_open.html]=man3/OSSL_STORE_open.pod +GENERATE[html/man3/OSSL_STORE_open.html]=man3/OSSL_STORE_open.pod +DEPEND[man/man3/OSSL_STORE_open.3]=man3/OSSL_STORE_open.pod +GENERATE[man/man3/OSSL_STORE_open.3]=man3/OSSL_STORE_open.pod +DEPEND[html/man3/OSSL_trace_enabled.html]=man3/OSSL_trace_enabled.pod +GENERATE[html/man3/OSSL_trace_enabled.html]=man3/OSSL_trace_enabled.pod +DEPEND[man/man3/OSSL_trace_enabled.3]=man3/OSSL_trace_enabled.pod +GENERATE[man/man3/OSSL_trace_enabled.3]=man3/OSSL_trace_enabled.pod +DEPEND[html/man3/OSSL_trace_get_category_num.html]=man3/OSSL_trace_get_category_num.pod +GENERATE[html/man3/OSSL_trace_get_category_num.html]=man3/OSSL_trace_get_category_num.pod +DEPEND[man/man3/OSSL_trace_get_category_num.3]=man3/OSSL_trace_get_category_num.pod +GENERATE[man/man3/OSSL_trace_get_category_num.3]=man3/OSSL_trace_get_category_num.pod +DEPEND[html/man3/OSSL_trace_set_channel.html]=man3/OSSL_trace_set_channel.pod +GENERATE[html/man3/OSSL_trace_set_channel.html]=man3/OSSL_trace_set_channel.pod +DEPEND[man/man3/OSSL_trace_set_channel.3]=man3/OSSL_trace_set_channel.pod +GENERATE[man/man3/OSSL_trace_set_channel.3]=man3/OSSL_trace_set_channel.pod +DEPEND[html/man3/OpenSSL_add_all_algorithms.html]=man3/OpenSSL_add_all_algorithms.pod +GENERATE[html/man3/OpenSSL_add_all_algorithms.html]=man3/OpenSSL_add_all_algorithms.pod +DEPEND[man/man3/OpenSSL_add_all_algorithms.3]=man3/OpenSSL_add_all_algorithms.pod +GENERATE[man/man3/OpenSSL_add_all_algorithms.3]=man3/OpenSSL_add_all_algorithms.pod +DEPEND[html/man3/OpenSSL_version.html]=man3/OpenSSL_version.pod +GENERATE[html/man3/OpenSSL_version.html]=man3/OpenSSL_version.pod +DEPEND[man/man3/OpenSSL_version.3]=man3/OpenSSL_version.pod +GENERATE[man/man3/OpenSSL_version.3]=man3/OpenSSL_version.pod +DEPEND[html/man3/PEM_X509_INFO_read_bio_ex.html]=man3/PEM_X509_INFO_read_bio_ex.pod +GENERATE[html/man3/PEM_X509_INFO_read_bio_ex.html]=man3/PEM_X509_INFO_read_bio_ex.pod +DEPEND[man/man3/PEM_X509_INFO_read_bio_ex.3]=man3/PEM_X509_INFO_read_bio_ex.pod +GENERATE[man/man3/PEM_X509_INFO_read_bio_ex.3]=man3/PEM_X509_INFO_read_bio_ex.pod +DEPEND[html/man3/PEM_bytes_read_bio.html]=man3/PEM_bytes_read_bio.pod +GENERATE[html/man3/PEM_bytes_read_bio.html]=man3/PEM_bytes_read_bio.pod +DEPEND[man/man3/PEM_bytes_read_bio.3]=man3/PEM_bytes_read_bio.pod +GENERATE[man/man3/PEM_bytes_read_bio.3]=man3/PEM_bytes_read_bio.pod +DEPEND[html/man3/PEM_read.html]=man3/PEM_read.pod +GENERATE[html/man3/PEM_read.html]=man3/PEM_read.pod +DEPEND[man/man3/PEM_read.3]=man3/PEM_read.pod +GENERATE[man/man3/PEM_read.3]=man3/PEM_read.pod +DEPEND[html/man3/PEM_read_CMS.html]=man3/PEM_read_CMS.pod +GENERATE[html/man3/PEM_read_CMS.html]=man3/PEM_read_CMS.pod +DEPEND[man/man3/PEM_read_CMS.3]=man3/PEM_read_CMS.pod +GENERATE[man/man3/PEM_read_CMS.3]=man3/PEM_read_CMS.pod +DEPEND[html/man3/PEM_read_bio_PrivateKey.html]=man3/PEM_read_bio_PrivateKey.pod +GENERATE[html/man3/PEM_read_bio_PrivateKey.html]=man3/PEM_read_bio_PrivateKey.pod +DEPEND[man/man3/PEM_read_bio_PrivateKey.3]=man3/PEM_read_bio_PrivateKey.pod +GENERATE[man/man3/PEM_read_bio_PrivateKey.3]=man3/PEM_read_bio_PrivateKey.pod +DEPEND[html/man3/PEM_read_bio_ex.html]=man3/PEM_read_bio_ex.pod +GENERATE[html/man3/PEM_read_bio_ex.html]=man3/PEM_read_bio_ex.pod +DEPEND[man/man3/PEM_read_bio_ex.3]=man3/PEM_read_bio_ex.pod +GENERATE[man/man3/PEM_read_bio_ex.3]=man3/PEM_read_bio_ex.pod +DEPEND[html/man3/PEM_write_bio_CMS_stream.html]=man3/PEM_write_bio_CMS_stream.pod +GENERATE[html/man3/PEM_write_bio_CMS_stream.html]=man3/PEM_write_bio_CMS_stream.pod +DEPEND[man/man3/PEM_write_bio_CMS_stream.3]=man3/PEM_write_bio_CMS_stream.pod +GENERATE[man/man3/PEM_write_bio_CMS_stream.3]=man3/PEM_write_bio_CMS_stream.pod +DEPEND[html/man3/PEM_write_bio_PKCS7_stream.html]=man3/PEM_write_bio_PKCS7_stream.pod +GENERATE[html/man3/PEM_write_bio_PKCS7_stream.html]=man3/PEM_write_bio_PKCS7_stream.pod +DEPEND[man/man3/PEM_write_bio_PKCS7_stream.3]=man3/PEM_write_bio_PKCS7_stream.pod +GENERATE[man/man3/PEM_write_bio_PKCS7_stream.3]=man3/PEM_write_bio_PKCS7_stream.pod +DEPEND[html/man3/PKCS12_PBE_keyivgen.html]=man3/PKCS12_PBE_keyivgen.pod +GENERATE[html/man3/PKCS12_PBE_keyivgen.html]=man3/PKCS12_PBE_keyivgen.pod +DEPEND[man/man3/PKCS12_PBE_keyivgen.3]=man3/PKCS12_PBE_keyivgen.pod +GENERATE[man/man3/PKCS12_PBE_keyivgen.3]=man3/PKCS12_PBE_keyivgen.pod +DEPEND[html/man3/PKCS12_SAFEBAG_create_cert.html]=man3/PKCS12_SAFEBAG_create_cert.pod +GENERATE[html/man3/PKCS12_SAFEBAG_create_cert.html]=man3/PKCS12_SAFEBAG_create_cert.pod +DEPEND[man/man3/PKCS12_SAFEBAG_create_cert.3]=man3/PKCS12_SAFEBAG_create_cert.pod +GENERATE[man/man3/PKCS12_SAFEBAG_create_cert.3]=man3/PKCS12_SAFEBAG_create_cert.pod +DEPEND[html/man3/PKCS12_SAFEBAG_get0_attrs.html]=man3/PKCS12_SAFEBAG_get0_attrs.pod +GENERATE[html/man3/PKCS12_SAFEBAG_get0_attrs.html]=man3/PKCS12_SAFEBAG_get0_attrs.pod +DEPEND[man/man3/PKCS12_SAFEBAG_get0_attrs.3]=man3/PKCS12_SAFEBAG_get0_attrs.pod +GENERATE[man/man3/PKCS12_SAFEBAG_get0_attrs.3]=man3/PKCS12_SAFEBAG_get0_attrs.pod +DEPEND[html/man3/PKCS12_SAFEBAG_get1_cert.html]=man3/PKCS12_SAFEBAG_get1_cert.pod +GENERATE[html/man3/PKCS12_SAFEBAG_get1_cert.html]=man3/PKCS12_SAFEBAG_get1_cert.pod +DEPEND[man/man3/PKCS12_SAFEBAG_get1_cert.3]=man3/PKCS12_SAFEBAG_get1_cert.pod +GENERATE[man/man3/PKCS12_SAFEBAG_get1_cert.3]=man3/PKCS12_SAFEBAG_get1_cert.pod +DEPEND[html/man3/PKCS12_add1_attr_by_NID.html]=man3/PKCS12_add1_attr_by_NID.pod +GENERATE[html/man3/PKCS12_add1_attr_by_NID.html]=man3/PKCS12_add1_attr_by_NID.pod +DEPEND[man/man3/PKCS12_add1_attr_by_NID.3]=man3/PKCS12_add1_attr_by_NID.pod +GENERATE[man/man3/PKCS12_add1_attr_by_NID.3]=man3/PKCS12_add1_attr_by_NID.pod +DEPEND[html/man3/PKCS12_add_CSPName_asc.html]=man3/PKCS12_add_CSPName_asc.pod +GENERATE[html/man3/PKCS12_add_CSPName_asc.html]=man3/PKCS12_add_CSPName_asc.pod +DEPEND[man/man3/PKCS12_add_CSPName_asc.3]=man3/PKCS12_add_CSPName_asc.pod +GENERATE[man/man3/PKCS12_add_CSPName_asc.3]=man3/PKCS12_add_CSPName_asc.pod +DEPEND[html/man3/PKCS12_add_cert.html]=man3/PKCS12_add_cert.pod +GENERATE[html/man3/PKCS12_add_cert.html]=man3/PKCS12_add_cert.pod +DEPEND[man/man3/PKCS12_add_cert.3]=man3/PKCS12_add_cert.pod +GENERATE[man/man3/PKCS12_add_cert.3]=man3/PKCS12_add_cert.pod +DEPEND[html/man3/PKCS12_add_friendlyname_asc.html]=man3/PKCS12_add_friendlyname_asc.pod +GENERATE[html/man3/PKCS12_add_friendlyname_asc.html]=man3/PKCS12_add_friendlyname_asc.pod +DEPEND[man/man3/PKCS12_add_friendlyname_asc.3]=man3/PKCS12_add_friendlyname_asc.pod +GENERATE[man/man3/PKCS12_add_friendlyname_asc.3]=man3/PKCS12_add_friendlyname_asc.pod +DEPEND[html/man3/PKCS12_add_localkeyid.html]=man3/PKCS12_add_localkeyid.pod +GENERATE[html/man3/PKCS12_add_localkeyid.html]=man3/PKCS12_add_localkeyid.pod +DEPEND[man/man3/PKCS12_add_localkeyid.3]=man3/PKCS12_add_localkeyid.pod +GENERATE[man/man3/PKCS12_add_localkeyid.3]=man3/PKCS12_add_localkeyid.pod +DEPEND[html/man3/PKCS12_add_safe.html]=man3/PKCS12_add_safe.pod +GENERATE[html/man3/PKCS12_add_safe.html]=man3/PKCS12_add_safe.pod +DEPEND[man/man3/PKCS12_add_safe.3]=man3/PKCS12_add_safe.pod +GENERATE[man/man3/PKCS12_add_safe.3]=man3/PKCS12_add_safe.pod +DEPEND[html/man3/PKCS12_create.html]=man3/PKCS12_create.pod +GENERATE[html/man3/PKCS12_create.html]=man3/PKCS12_create.pod +DEPEND[man/man3/PKCS12_create.3]=man3/PKCS12_create.pod +GENERATE[man/man3/PKCS12_create.3]=man3/PKCS12_create.pod +DEPEND[html/man3/PKCS12_decrypt_skey.html]=man3/PKCS12_decrypt_skey.pod +GENERATE[html/man3/PKCS12_decrypt_skey.html]=man3/PKCS12_decrypt_skey.pod +DEPEND[man/man3/PKCS12_decrypt_skey.3]=man3/PKCS12_decrypt_skey.pod +GENERATE[man/man3/PKCS12_decrypt_skey.3]=man3/PKCS12_decrypt_skey.pod +DEPEND[html/man3/PKCS12_gen_mac.html]=man3/PKCS12_gen_mac.pod +GENERATE[html/man3/PKCS12_gen_mac.html]=man3/PKCS12_gen_mac.pod +DEPEND[man/man3/PKCS12_gen_mac.3]=man3/PKCS12_gen_mac.pod +GENERATE[man/man3/PKCS12_gen_mac.3]=man3/PKCS12_gen_mac.pod +DEPEND[html/man3/PKCS12_get_friendlyname.html]=man3/PKCS12_get_friendlyname.pod +GENERATE[html/man3/PKCS12_get_friendlyname.html]=man3/PKCS12_get_friendlyname.pod +DEPEND[man/man3/PKCS12_get_friendlyname.3]=man3/PKCS12_get_friendlyname.pod +GENERATE[man/man3/PKCS12_get_friendlyname.3]=man3/PKCS12_get_friendlyname.pod +DEPEND[html/man3/PKCS12_init.html]=man3/PKCS12_init.pod +GENERATE[html/man3/PKCS12_init.html]=man3/PKCS12_init.pod +DEPEND[man/man3/PKCS12_init.3]=man3/PKCS12_init.pod +GENERATE[man/man3/PKCS12_init.3]=man3/PKCS12_init.pod +DEPEND[html/man3/PKCS12_item_decrypt_d2i.html]=man3/PKCS12_item_decrypt_d2i.pod +GENERATE[html/man3/PKCS12_item_decrypt_d2i.html]=man3/PKCS12_item_decrypt_d2i.pod +DEPEND[man/man3/PKCS12_item_decrypt_d2i.3]=man3/PKCS12_item_decrypt_d2i.pod +GENERATE[man/man3/PKCS12_item_decrypt_d2i.3]=man3/PKCS12_item_decrypt_d2i.pod +DEPEND[html/man3/PKCS12_key_gen_utf8_ex.html]=man3/PKCS12_key_gen_utf8_ex.pod +GENERATE[html/man3/PKCS12_key_gen_utf8_ex.html]=man3/PKCS12_key_gen_utf8_ex.pod +DEPEND[man/man3/PKCS12_key_gen_utf8_ex.3]=man3/PKCS12_key_gen_utf8_ex.pod +GENERATE[man/man3/PKCS12_key_gen_utf8_ex.3]=man3/PKCS12_key_gen_utf8_ex.pod +DEPEND[html/man3/PKCS12_newpass.html]=man3/PKCS12_newpass.pod +GENERATE[html/man3/PKCS12_newpass.html]=man3/PKCS12_newpass.pod +DEPEND[man/man3/PKCS12_newpass.3]=man3/PKCS12_newpass.pod +GENERATE[man/man3/PKCS12_newpass.3]=man3/PKCS12_newpass.pod +DEPEND[html/man3/PKCS12_pack_p7encdata.html]=man3/PKCS12_pack_p7encdata.pod +GENERATE[html/man3/PKCS12_pack_p7encdata.html]=man3/PKCS12_pack_p7encdata.pod +DEPEND[man/man3/PKCS12_pack_p7encdata.3]=man3/PKCS12_pack_p7encdata.pod +GENERATE[man/man3/PKCS12_pack_p7encdata.3]=man3/PKCS12_pack_p7encdata.pod +DEPEND[html/man3/PKCS12_parse.html]=man3/PKCS12_parse.pod +GENERATE[html/man3/PKCS12_parse.html]=man3/PKCS12_parse.pod +DEPEND[man/man3/PKCS12_parse.3]=man3/PKCS12_parse.pod +GENERATE[man/man3/PKCS12_parse.3]=man3/PKCS12_parse.pod +DEPEND[html/man3/PKCS5_PBE_keyivgen.html]=man3/PKCS5_PBE_keyivgen.pod +GENERATE[html/man3/PKCS5_PBE_keyivgen.html]=man3/PKCS5_PBE_keyivgen.pod +DEPEND[man/man3/PKCS5_PBE_keyivgen.3]=man3/PKCS5_PBE_keyivgen.pod +GENERATE[man/man3/PKCS5_PBE_keyivgen.3]=man3/PKCS5_PBE_keyivgen.pod +DEPEND[html/man3/PKCS5_PBKDF2_HMAC.html]=man3/PKCS5_PBKDF2_HMAC.pod +GENERATE[html/man3/PKCS5_PBKDF2_HMAC.html]=man3/PKCS5_PBKDF2_HMAC.pod +DEPEND[man/man3/PKCS5_PBKDF2_HMAC.3]=man3/PKCS5_PBKDF2_HMAC.pod +GENERATE[man/man3/PKCS5_PBKDF2_HMAC.3]=man3/PKCS5_PBKDF2_HMAC.pod +DEPEND[html/man3/PKCS7_decrypt.html]=man3/PKCS7_decrypt.pod +GENERATE[html/man3/PKCS7_decrypt.html]=man3/PKCS7_decrypt.pod +DEPEND[man/man3/PKCS7_decrypt.3]=man3/PKCS7_decrypt.pod +GENERATE[man/man3/PKCS7_decrypt.3]=man3/PKCS7_decrypt.pod +DEPEND[html/man3/PKCS7_encrypt.html]=man3/PKCS7_encrypt.pod +GENERATE[html/man3/PKCS7_encrypt.html]=man3/PKCS7_encrypt.pod +DEPEND[man/man3/PKCS7_encrypt.3]=man3/PKCS7_encrypt.pod +GENERATE[man/man3/PKCS7_encrypt.3]=man3/PKCS7_encrypt.pod +DEPEND[html/man3/PKCS7_get_octet_string.html]=man3/PKCS7_get_octet_string.pod +GENERATE[html/man3/PKCS7_get_octet_string.html]=man3/PKCS7_get_octet_string.pod +DEPEND[man/man3/PKCS7_get_octet_string.3]=man3/PKCS7_get_octet_string.pod +GENERATE[man/man3/PKCS7_get_octet_string.3]=man3/PKCS7_get_octet_string.pod +DEPEND[html/man3/PKCS7_sign.html]=man3/PKCS7_sign.pod +GENERATE[html/man3/PKCS7_sign.html]=man3/PKCS7_sign.pod +DEPEND[man/man3/PKCS7_sign.3]=man3/PKCS7_sign.pod +GENERATE[man/man3/PKCS7_sign.3]=man3/PKCS7_sign.pod +DEPEND[html/man3/PKCS7_sign_add_signer.html]=man3/PKCS7_sign_add_signer.pod +GENERATE[html/man3/PKCS7_sign_add_signer.html]=man3/PKCS7_sign_add_signer.pod +DEPEND[man/man3/PKCS7_sign_add_signer.3]=man3/PKCS7_sign_add_signer.pod +GENERATE[man/man3/PKCS7_sign_add_signer.3]=man3/PKCS7_sign_add_signer.pod +DEPEND[html/man3/PKCS7_type_is_other.html]=man3/PKCS7_type_is_other.pod +GENERATE[html/man3/PKCS7_type_is_other.html]=man3/PKCS7_type_is_other.pod +DEPEND[man/man3/PKCS7_type_is_other.3]=man3/PKCS7_type_is_other.pod +GENERATE[man/man3/PKCS7_type_is_other.3]=man3/PKCS7_type_is_other.pod +DEPEND[html/man3/PKCS7_verify.html]=man3/PKCS7_verify.pod +GENERATE[html/man3/PKCS7_verify.html]=man3/PKCS7_verify.pod +DEPEND[man/man3/PKCS7_verify.3]=man3/PKCS7_verify.pod +GENERATE[man/man3/PKCS7_verify.3]=man3/PKCS7_verify.pod +DEPEND[html/man3/PKCS8_encrypt.html]=man3/PKCS8_encrypt.pod +GENERATE[html/man3/PKCS8_encrypt.html]=man3/PKCS8_encrypt.pod +DEPEND[man/man3/PKCS8_encrypt.3]=man3/PKCS8_encrypt.pod +GENERATE[man/man3/PKCS8_encrypt.3]=man3/PKCS8_encrypt.pod +DEPEND[html/man3/PKCS8_pkey_add1_attr.html]=man3/PKCS8_pkey_add1_attr.pod +GENERATE[html/man3/PKCS8_pkey_add1_attr.html]=man3/PKCS8_pkey_add1_attr.pod +DEPEND[man/man3/PKCS8_pkey_add1_attr.3]=man3/PKCS8_pkey_add1_attr.pod +GENERATE[man/man3/PKCS8_pkey_add1_attr.3]=man3/PKCS8_pkey_add1_attr.pod +DEPEND[html/man3/RAND_add.html]=man3/RAND_add.pod +GENERATE[html/man3/RAND_add.html]=man3/RAND_add.pod +DEPEND[man/man3/RAND_add.3]=man3/RAND_add.pod +GENERATE[man/man3/RAND_add.3]=man3/RAND_add.pod +DEPEND[html/man3/RAND_bytes.html]=man3/RAND_bytes.pod +GENERATE[html/man3/RAND_bytes.html]=man3/RAND_bytes.pod +DEPEND[man/man3/RAND_bytes.3]=man3/RAND_bytes.pod +GENERATE[man/man3/RAND_bytes.3]=man3/RAND_bytes.pod +DEPEND[html/man3/RAND_cleanup.html]=man3/RAND_cleanup.pod +GENERATE[html/man3/RAND_cleanup.html]=man3/RAND_cleanup.pod +DEPEND[man/man3/RAND_cleanup.3]=man3/RAND_cleanup.pod +GENERATE[man/man3/RAND_cleanup.3]=man3/RAND_cleanup.pod +DEPEND[html/man3/RAND_egd.html]=man3/RAND_egd.pod +GENERATE[html/man3/RAND_egd.html]=man3/RAND_egd.pod +DEPEND[man/man3/RAND_egd.3]=man3/RAND_egd.pod +GENERATE[man/man3/RAND_egd.3]=man3/RAND_egd.pod +DEPEND[html/man3/RAND_get0_primary.html]=man3/RAND_get0_primary.pod +GENERATE[html/man3/RAND_get0_primary.html]=man3/RAND_get0_primary.pod +DEPEND[man/man3/RAND_get0_primary.3]=man3/RAND_get0_primary.pod +GENERATE[man/man3/RAND_get0_primary.3]=man3/RAND_get0_primary.pod +DEPEND[html/man3/RAND_load_file.html]=man3/RAND_load_file.pod +GENERATE[html/man3/RAND_load_file.html]=man3/RAND_load_file.pod +DEPEND[man/man3/RAND_load_file.3]=man3/RAND_load_file.pod +GENERATE[man/man3/RAND_load_file.3]=man3/RAND_load_file.pod +DEPEND[html/man3/RAND_set_DRBG_type.html]=man3/RAND_set_DRBG_type.pod +GENERATE[html/man3/RAND_set_DRBG_type.html]=man3/RAND_set_DRBG_type.pod +DEPEND[man/man3/RAND_set_DRBG_type.3]=man3/RAND_set_DRBG_type.pod +GENERATE[man/man3/RAND_set_DRBG_type.3]=man3/RAND_set_DRBG_type.pod +DEPEND[html/man3/RAND_set_rand_method.html]=man3/RAND_set_rand_method.pod +GENERATE[html/man3/RAND_set_rand_method.html]=man3/RAND_set_rand_method.pod +DEPEND[man/man3/RAND_set_rand_method.3]=man3/RAND_set_rand_method.pod +GENERATE[man/man3/RAND_set_rand_method.3]=man3/RAND_set_rand_method.pod +DEPEND[html/man3/RC4_set_key.html]=man3/RC4_set_key.pod +GENERATE[html/man3/RC4_set_key.html]=man3/RC4_set_key.pod +DEPEND[man/man3/RC4_set_key.3]=man3/RC4_set_key.pod +GENERATE[man/man3/RC4_set_key.3]=man3/RC4_set_key.pod +DEPEND[html/man3/RIPEMD160_Init.html]=man3/RIPEMD160_Init.pod +GENERATE[html/man3/RIPEMD160_Init.html]=man3/RIPEMD160_Init.pod +DEPEND[man/man3/RIPEMD160_Init.3]=man3/RIPEMD160_Init.pod +GENERATE[man/man3/RIPEMD160_Init.3]=man3/RIPEMD160_Init.pod +DEPEND[html/man3/RSA_blinding_on.html]=man3/RSA_blinding_on.pod +GENERATE[html/man3/RSA_blinding_on.html]=man3/RSA_blinding_on.pod +DEPEND[man/man3/RSA_blinding_on.3]=man3/RSA_blinding_on.pod +GENERATE[man/man3/RSA_blinding_on.3]=man3/RSA_blinding_on.pod +DEPEND[html/man3/RSA_check_key.html]=man3/RSA_check_key.pod +GENERATE[html/man3/RSA_check_key.html]=man3/RSA_check_key.pod +DEPEND[man/man3/RSA_check_key.3]=man3/RSA_check_key.pod +GENERATE[man/man3/RSA_check_key.3]=man3/RSA_check_key.pod +DEPEND[html/man3/RSA_generate_key.html]=man3/RSA_generate_key.pod +GENERATE[html/man3/RSA_generate_key.html]=man3/RSA_generate_key.pod +DEPEND[man/man3/RSA_generate_key.3]=man3/RSA_generate_key.pod +GENERATE[man/man3/RSA_generate_key.3]=man3/RSA_generate_key.pod +DEPEND[html/man3/RSA_get0_key.html]=man3/RSA_get0_key.pod +GENERATE[html/man3/RSA_get0_key.html]=man3/RSA_get0_key.pod +DEPEND[man/man3/RSA_get0_key.3]=man3/RSA_get0_key.pod +GENERATE[man/man3/RSA_get0_key.3]=man3/RSA_get0_key.pod +DEPEND[html/man3/RSA_meth_new.html]=man3/RSA_meth_new.pod +GENERATE[html/man3/RSA_meth_new.html]=man3/RSA_meth_new.pod +DEPEND[man/man3/RSA_meth_new.3]=man3/RSA_meth_new.pod +GENERATE[man/man3/RSA_meth_new.3]=man3/RSA_meth_new.pod +DEPEND[html/man3/RSA_new.html]=man3/RSA_new.pod +GENERATE[html/man3/RSA_new.html]=man3/RSA_new.pod +DEPEND[man/man3/RSA_new.3]=man3/RSA_new.pod +GENERATE[man/man3/RSA_new.3]=man3/RSA_new.pod +DEPEND[html/man3/RSA_padding_add_PKCS1_type_1.html]=man3/RSA_padding_add_PKCS1_type_1.pod +GENERATE[html/man3/RSA_padding_add_PKCS1_type_1.html]=man3/RSA_padding_add_PKCS1_type_1.pod +DEPEND[man/man3/RSA_padding_add_PKCS1_type_1.3]=man3/RSA_padding_add_PKCS1_type_1.pod +GENERATE[man/man3/RSA_padding_add_PKCS1_type_1.3]=man3/RSA_padding_add_PKCS1_type_1.pod +DEPEND[html/man3/RSA_print.html]=man3/RSA_print.pod +GENERATE[html/man3/RSA_print.html]=man3/RSA_print.pod +DEPEND[man/man3/RSA_print.3]=man3/RSA_print.pod +GENERATE[man/man3/RSA_print.3]=man3/RSA_print.pod +DEPEND[html/man3/RSA_private_encrypt.html]=man3/RSA_private_encrypt.pod +GENERATE[html/man3/RSA_private_encrypt.html]=man3/RSA_private_encrypt.pod +DEPEND[man/man3/RSA_private_encrypt.3]=man3/RSA_private_encrypt.pod +GENERATE[man/man3/RSA_private_encrypt.3]=man3/RSA_private_encrypt.pod +DEPEND[html/man3/RSA_public_encrypt.html]=man3/RSA_public_encrypt.pod +GENERATE[html/man3/RSA_public_encrypt.html]=man3/RSA_public_encrypt.pod +DEPEND[man/man3/RSA_public_encrypt.3]=man3/RSA_public_encrypt.pod +GENERATE[man/man3/RSA_public_encrypt.3]=man3/RSA_public_encrypt.pod +DEPEND[html/man3/RSA_set_method.html]=man3/RSA_set_method.pod +GENERATE[html/man3/RSA_set_method.html]=man3/RSA_set_method.pod +DEPEND[man/man3/RSA_set_method.3]=man3/RSA_set_method.pod +GENERATE[man/man3/RSA_set_method.3]=man3/RSA_set_method.pod +DEPEND[html/man3/RSA_sign.html]=man3/RSA_sign.pod +GENERATE[html/man3/RSA_sign.html]=man3/RSA_sign.pod +DEPEND[man/man3/RSA_sign.3]=man3/RSA_sign.pod +GENERATE[man/man3/RSA_sign.3]=man3/RSA_sign.pod +DEPEND[html/man3/RSA_sign_ASN1_OCTET_STRING.html]=man3/RSA_sign_ASN1_OCTET_STRING.pod +GENERATE[html/man3/RSA_sign_ASN1_OCTET_STRING.html]=man3/RSA_sign_ASN1_OCTET_STRING.pod +DEPEND[man/man3/RSA_sign_ASN1_OCTET_STRING.3]=man3/RSA_sign_ASN1_OCTET_STRING.pod +GENERATE[man/man3/RSA_sign_ASN1_OCTET_STRING.3]=man3/RSA_sign_ASN1_OCTET_STRING.pod +DEPEND[html/man3/RSA_size.html]=man3/RSA_size.pod +GENERATE[html/man3/RSA_size.html]=man3/RSA_size.pod +DEPEND[man/man3/RSA_size.3]=man3/RSA_size.pod +GENERATE[man/man3/RSA_size.3]=man3/RSA_size.pod +DEPEND[html/man3/SCT_new.html]=man3/SCT_new.pod +GENERATE[html/man3/SCT_new.html]=man3/SCT_new.pod +DEPEND[man/man3/SCT_new.3]=man3/SCT_new.pod +GENERATE[man/man3/SCT_new.3]=man3/SCT_new.pod +DEPEND[html/man3/SCT_print.html]=man3/SCT_print.pod +GENERATE[html/man3/SCT_print.html]=man3/SCT_print.pod +DEPEND[man/man3/SCT_print.3]=man3/SCT_print.pod +GENERATE[man/man3/SCT_print.3]=man3/SCT_print.pod +DEPEND[html/man3/SCT_validate.html]=man3/SCT_validate.pod +GENERATE[html/man3/SCT_validate.html]=man3/SCT_validate.pod +DEPEND[man/man3/SCT_validate.3]=man3/SCT_validate.pod +GENERATE[man/man3/SCT_validate.3]=man3/SCT_validate.pod +DEPEND[html/man3/SHA256_Init.html]=man3/SHA256_Init.pod +GENERATE[html/man3/SHA256_Init.html]=man3/SHA256_Init.pod +DEPEND[man/man3/SHA256_Init.3]=man3/SHA256_Init.pod +GENERATE[man/man3/SHA256_Init.3]=man3/SHA256_Init.pod +DEPEND[html/man3/SMIME_read_ASN1.html]=man3/SMIME_read_ASN1.pod +GENERATE[html/man3/SMIME_read_ASN1.html]=man3/SMIME_read_ASN1.pod +DEPEND[man/man3/SMIME_read_ASN1.3]=man3/SMIME_read_ASN1.pod +GENERATE[man/man3/SMIME_read_ASN1.3]=man3/SMIME_read_ASN1.pod +DEPEND[html/man3/SMIME_read_CMS.html]=man3/SMIME_read_CMS.pod +GENERATE[html/man3/SMIME_read_CMS.html]=man3/SMIME_read_CMS.pod +DEPEND[man/man3/SMIME_read_CMS.3]=man3/SMIME_read_CMS.pod +GENERATE[man/man3/SMIME_read_CMS.3]=man3/SMIME_read_CMS.pod +DEPEND[html/man3/SMIME_read_PKCS7.html]=man3/SMIME_read_PKCS7.pod +GENERATE[html/man3/SMIME_read_PKCS7.html]=man3/SMIME_read_PKCS7.pod +DEPEND[man/man3/SMIME_read_PKCS7.3]=man3/SMIME_read_PKCS7.pod +GENERATE[man/man3/SMIME_read_PKCS7.3]=man3/SMIME_read_PKCS7.pod +DEPEND[html/man3/SMIME_write_ASN1.html]=man3/SMIME_write_ASN1.pod +GENERATE[html/man3/SMIME_write_ASN1.html]=man3/SMIME_write_ASN1.pod +DEPEND[man/man3/SMIME_write_ASN1.3]=man3/SMIME_write_ASN1.pod +GENERATE[man/man3/SMIME_write_ASN1.3]=man3/SMIME_write_ASN1.pod +DEPEND[html/man3/SMIME_write_CMS.html]=man3/SMIME_write_CMS.pod +GENERATE[html/man3/SMIME_write_CMS.html]=man3/SMIME_write_CMS.pod +DEPEND[man/man3/SMIME_write_CMS.3]=man3/SMIME_write_CMS.pod +GENERATE[man/man3/SMIME_write_CMS.3]=man3/SMIME_write_CMS.pod +DEPEND[html/man3/SMIME_write_PKCS7.html]=man3/SMIME_write_PKCS7.pod +GENERATE[html/man3/SMIME_write_PKCS7.html]=man3/SMIME_write_PKCS7.pod +DEPEND[man/man3/SMIME_write_PKCS7.3]=man3/SMIME_write_PKCS7.pod +GENERATE[man/man3/SMIME_write_PKCS7.3]=man3/SMIME_write_PKCS7.pod +DEPEND[html/man3/SRP_Calc_B.html]=man3/SRP_Calc_B.pod +GENERATE[html/man3/SRP_Calc_B.html]=man3/SRP_Calc_B.pod +DEPEND[man/man3/SRP_Calc_B.3]=man3/SRP_Calc_B.pod +GENERATE[man/man3/SRP_Calc_B.3]=man3/SRP_Calc_B.pod +DEPEND[html/man3/SRP_VBASE_new.html]=man3/SRP_VBASE_new.pod +GENERATE[html/man3/SRP_VBASE_new.html]=man3/SRP_VBASE_new.pod +DEPEND[man/man3/SRP_VBASE_new.3]=man3/SRP_VBASE_new.pod +GENERATE[man/man3/SRP_VBASE_new.3]=man3/SRP_VBASE_new.pod +DEPEND[html/man3/SRP_create_verifier.html]=man3/SRP_create_verifier.pod +GENERATE[html/man3/SRP_create_verifier.html]=man3/SRP_create_verifier.pod +DEPEND[man/man3/SRP_create_verifier.3]=man3/SRP_create_verifier.pod +GENERATE[man/man3/SRP_create_verifier.3]=man3/SRP_create_verifier.pod +DEPEND[html/man3/SRP_user_pwd_new.html]=man3/SRP_user_pwd_new.pod +GENERATE[html/man3/SRP_user_pwd_new.html]=man3/SRP_user_pwd_new.pod +DEPEND[man/man3/SRP_user_pwd_new.3]=man3/SRP_user_pwd_new.pod +GENERATE[man/man3/SRP_user_pwd_new.3]=man3/SRP_user_pwd_new.pod +DEPEND[html/man3/SSL_CIPHER_get_name.html]=man3/SSL_CIPHER_get_name.pod +GENERATE[html/man3/SSL_CIPHER_get_name.html]=man3/SSL_CIPHER_get_name.pod +DEPEND[man/man3/SSL_CIPHER_get_name.3]=man3/SSL_CIPHER_get_name.pod +GENERATE[man/man3/SSL_CIPHER_get_name.3]=man3/SSL_CIPHER_get_name.pod +DEPEND[html/man3/SSL_COMP_add_compression_method.html]=man3/SSL_COMP_add_compression_method.pod +GENERATE[html/man3/SSL_COMP_add_compression_method.html]=man3/SSL_COMP_add_compression_method.pod +DEPEND[man/man3/SSL_COMP_add_compression_method.3]=man3/SSL_COMP_add_compression_method.pod +GENERATE[man/man3/SSL_COMP_add_compression_method.3]=man3/SSL_COMP_add_compression_method.pod +DEPEND[html/man3/SSL_CONF_CTX_new.html]=man3/SSL_CONF_CTX_new.pod +GENERATE[html/man3/SSL_CONF_CTX_new.html]=man3/SSL_CONF_CTX_new.pod +DEPEND[man/man3/SSL_CONF_CTX_new.3]=man3/SSL_CONF_CTX_new.pod +GENERATE[man/man3/SSL_CONF_CTX_new.3]=man3/SSL_CONF_CTX_new.pod +DEPEND[html/man3/SSL_CONF_CTX_set1_prefix.html]=man3/SSL_CONF_CTX_set1_prefix.pod +GENERATE[html/man3/SSL_CONF_CTX_set1_prefix.html]=man3/SSL_CONF_CTX_set1_prefix.pod +DEPEND[man/man3/SSL_CONF_CTX_set1_prefix.3]=man3/SSL_CONF_CTX_set1_prefix.pod +GENERATE[man/man3/SSL_CONF_CTX_set1_prefix.3]=man3/SSL_CONF_CTX_set1_prefix.pod +DEPEND[html/man3/SSL_CONF_CTX_set_flags.html]=man3/SSL_CONF_CTX_set_flags.pod +GENERATE[html/man3/SSL_CONF_CTX_set_flags.html]=man3/SSL_CONF_CTX_set_flags.pod +DEPEND[man/man3/SSL_CONF_CTX_set_flags.3]=man3/SSL_CONF_CTX_set_flags.pod +GENERATE[man/man3/SSL_CONF_CTX_set_flags.3]=man3/SSL_CONF_CTX_set_flags.pod +DEPEND[html/man3/SSL_CONF_CTX_set_ssl_ctx.html]=man3/SSL_CONF_CTX_set_ssl_ctx.pod +GENERATE[html/man3/SSL_CONF_CTX_set_ssl_ctx.html]=man3/SSL_CONF_CTX_set_ssl_ctx.pod +DEPEND[man/man3/SSL_CONF_CTX_set_ssl_ctx.3]=man3/SSL_CONF_CTX_set_ssl_ctx.pod +GENERATE[man/man3/SSL_CONF_CTX_set_ssl_ctx.3]=man3/SSL_CONF_CTX_set_ssl_ctx.pod +DEPEND[html/man3/SSL_CONF_cmd.html]=man3/SSL_CONF_cmd.pod +GENERATE[html/man3/SSL_CONF_cmd.html]=man3/SSL_CONF_cmd.pod +DEPEND[man/man3/SSL_CONF_cmd.3]=man3/SSL_CONF_cmd.pod +GENERATE[man/man3/SSL_CONF_cmd.3]=man3/SSL_CONF_cmd.pod +DEPEND[html/man3/SSL_CONF_cmd_argv.html]=man3/SSL_CONF_cmd_argv.pod +GENERATE[html/man3/SSL_CONF_cmd_argv.html]=man3/SSL_CONF_cmd_argv.pod +DEPEND[man/man3/SSL_CONF_cmd_argv.3]=man3/SSL_CONF_cmd_argv.pod +GENERATE[man/man3/SSL_CONF_cmd_argv.3]=man3/SSL_CONF_cmd_argv.pod +DEPEND[html/man3/SSL_CTX_add1_chain_cert.html]=man3/SSL_CTX_add1_chain_cert.pod +GENERATE[html/man3/SSL_CTX_add1_chain_cert.html]=man3/SSL_CTX_add1_chain_cert.pod +DEPEND[man/man3/SSL_CTX_add1_chain_cert.3]=man3/SSL_CTX_add1_chain_cert.pod +GENERATE[man/man3/SSL_CTX_add1_chain_cert.3]=man3/SSL_CTX_add1_chain_cert.pod +DEPEND[html/man3/SSL_CTX_add_extra_chain_cert.html]=man3/SSL_CTX_add_extra_chain_cert.pod +GENERATE[html/man3/SSL_CTX_add_extra_chain_cert.html]=man3/SSL_CTX_add_extra_chain_cert.pod +DEPEND[man/man3/SSL_CTX_add_extra_chain_cert.3]=man3/SSL_CTX_add_extra_chain_cert.pod +GENERATE[man/man3/SSL_CTX_add_extra_chain_cert.3]=man3/SSL_CTX_add_extra_chain_cert.pod +DEPEND[html/man3/SSL_CTX_add_session.html]=man3/SSL_CTX_add_session.pod +GENERATE[html/man3/SSL_CTX_add_session.html]=man3/SSL_CTX_add_session.pod +DEPEND[man/man3/SSL_CTX_add_session.3]=man3/SSL_CTX_add_session.pod +GENERATE[man/man3/SSL_CTX_add_session.3]=man3/SSL_CTX_add_session.pod +DEPEND[html/man3/SSL_CTX_config.html]=man3/SSL_CTX_config.pod +GENERATE[html/man3/SSL_CTX_config.html]=man3/SSL_CTX_config.pod +DEPEND[man/man3/SSL_CTX_config.3]=man3/SSL_CTX_config.pod +GENERATE[man/man3/SSL_CTX_config.3]=man3/SSL_CTX_config.pod +DEPEND[html/man3/SSL_CTX_ctrl.html]=man3/SSL_CTX_ctrl.pod +GENERATE[html/man3/SSL_CTX_ctrl.html]=man3/SSL_CTX_ctrl.pod +DEPEND[man/man3/SSL_CTX_ctrl.3]=man3/SSL_CTX_ctrl.pod +GENERATE[man/man3/SSL_CTX_ctrl.3]=man3/SSL_CTX_ctrl.pod +DEPEND[html/man3/SSL_CTX_dane_enable.html]=man3/SSL_CTX_dane_enable.pod +GENERATE[html/man3/SSL_CTX_dane_enable.html]=man3/SSL_CTX_dane_enable.pod +DEPEND[man/man3/SSL_CTX_dane_enable.3]=man3/SSL_CTX_dane_enable.pod +GENERATE[man/man3/SSL_CTX_dane_enable.3]=man3/SSL_CTX_dane_enable.pod +DEPEND[html/man3/SSL_CTX_flush_sessions.html]=man3/SSL_CTX_flush_sessions.pod +GENERATE[html/man3/SSL_CTX_flush_sessions.html]=man3/SSL_CTX_flush_sessions.pod +DEPEND[man/man3/SSL_CTX_flush_sessions.3]=man3/SSL_CTX_flush_sessions.pod +GENERATE[man/man3/SSL_CTX_flush_sessions.3]=man3/SSL_CTX_flush_sessions.pod +DEPEND[html/man3/SSL_CTX_free.html]=man3/SSL_CTX_free.pod +GENERATE[html/man3/SSL_CTX_free.html]=man3/SSL_CTX_free.pod +DEPEND[man/man3/SSL_CTX_free.3]=man3/SSL_CTX_free.pod +GENERATE[man/man3/SSL_CTX_free.3]=man3/SSL_CTX_free.pod +DEPEND[html/man3/SSL_CTX_get0_param.html]=man3/SSL_CTX_get0_param.pod +GENERATE[html/man3/SSL_CTX_get0_param.html]=man3/SSL_CTX_get0_param.pod +DEPEND[man/man3/SSL_CTX_get0_param.3]=man3/SSL_CTX_get0_param.pod +GENERATE[man/man3/SSL_CTX_get0_param.3]=man3/SSL_CTX_get0_param.pod +DEPEND[html/man3/SSL_CTX_get_verify_mode.html]=man3/SSL_CTX_get_verify_mode.pod +GENERATE[html/man3/SSL_CTX_get_verify_mode.html]=man3/SSL_CTX_get_verify_mode.pod +DEPEND[man/man3/SSL_CTX_get_verify_mode.3]=man3/SSL_CTX_get_verify_mode.pod +GENERATE[man/man3/SSL_CTX_get_verify_mode.3]=man3/SSL_CTX_get_verify_mode.pod +DEPEND[html/man3/SSL_CTX_has_client_custom_ext.html]=man3/SSL_CTX_has_client_custom_ext.pod +GENERATE[html/man3/SSL_CTX_has_client_custom_ext.html]=man3/SSL_CTX_has_client_custom_ext.pod +DEPEND[man/man3/SSL_CTX_has_client_custom_ext.3]=man3/SSL_CTX_has_client_custom_ext.pod +GENERATE[man/man3/SSL_CTX_has_client_custom_ext.3]=man3/SSL_CTX_has_client_custom_ext.pod +DEPEND[html/man3/SSL_CTX_load_verify_locations.html]=man3/SSL_CTX_load_verify_locations.pod +GENERATE[html/man3/SSL_CTX_load_verify_locations.html]=man3/SSL_CTX_load_verify_locations.pod +DEPEND[man/man3/SSL_CTX_load_verify_locations.3]=man3/SSL_CTX_load_verify_locations.pod +GENERATE[man/man3/SSL_CTX_load_verify_locations.3]=man3/SSL_CTX_load_verify_locations.pod +DEPEND[html/man3/SSL_CTX_new.html]=man3/SSL_CTX_new.pod +GENERATE[html/man3/SSL_CTX_new.html]=man3/SSL_CTX_new.pod +DEPEND[man/man3/SSL_CTX_new.3]=man3/SSL_CTX_new.pod +GENERATE[man/man3/SSL_CTX_new.3]=man3/SSL_CTX_new.pod +DEPEND[html/man3/SSL_CTX_sess_number.html]=man3/SSL_CTX_sess_number.pod +GENERATE[html/man3/SSL_CTX_sess_number.html]=man3/SSL_CTX_sess_number.pod +DEPEND[man/man3/SSL_CTX_sess_number.3]=man3/SSL_CTX_sess_number.pod +GENERATE[man/man3/SSL_CTX_sess_number.3]=man3/SSL_CTX_sess_number.pod +DEPEND[html/man3/SSL_CTX_sess_set_cache_size.html]=man3/SSL_CTX_sess_set_cache_size.pod +GENERATE[html/man3/SSL_CTX_sess_set_cache_size.html]=man3/SSL_CTX_sess_set_cache_size.pod +DEPEND[man/man3/SSL_CTX_sess_set_cache_size.3]=man3/SSL_CTX_sess_set_cache_size.pod +GENERATE[man/man3/SSL_CTX_sess_set_cache_size.3]=man3/SSL_CTX_sess_set_cache_size.pod +DEPEND[html/man3/SSL_CTX_sess_set_get_cb.html]=man3/SSL_CTX_sess_set_get_cb.pod +GENERATE[html/man3/SSL_CTX_sess_set_get_cb.html]=man3/SSL_CTX_sess_set_get_cb.pod +DEPEND[man/man3/SSL_CTX_sess_set_get_cb.3]=man3/SSL_CTX_sess_set_get_cb.pod +GENERATE[man/man3/SSL_CTX_sess_set_get_cb.3]=man3/SSL_CTX_sess_set_get_cb.pod +DEPEND[html/man3/SSL_CTX_sessions.html]=man3/SSL_CTX_sessions.pod +GENERATE[html/man3/SSL_CTX_sessions.html]=man3/SSL_CTX_sessions.pod +DEPEND[man/man3/SSL_CTX_sessions.3]=man3/SSL_CTX_sessions.pod +GENERATE[man/man3/SSL_CTX_sessions.3]=man3/SSL_CTX_sessions.pod +DEPEND[html/man3/SSL_CTX_set0_CA_list.html]=man3/SSL_CTX_set0_CA_list.pod +GENERATE[html/man3/SSL_CTX_set0_CA_list.html]=man3/SSL_CTX_set0_CA_list.pod +DEPEND[man/man3/SSL_CTX_set0_CA_list.3]=man3/SSL_CTX_set0_CA_list.pod +GENERATE[man/man3/SSL_CTX_set0_CA_list.3]=man3/SSL_CTX_set0_CA_list.pod +DEPEND[html/man3/SSL_CTX_set1_curves.html]=man3/SSL_CTX_set1_curves.pod +GENERATE[html/man3/SSL_CTX_set1_curves.html]=man3/SSL_CTX_set1_curves.pod +DEPEND[man/man3/SSL_CTX_set1_curves.3]=man3/SSL_CTX_set1_curves.pod +GENERATE[man/man3/SSL_CTX_set1_curves.3]=man3/SSL_CTX_set1_curves.pod +DEPEND[html/man3/SSL_CTX_set1_sigalgs.html]=man3/SSL_CTX_set1_sigalgs.pod +GENERATE[html/man3/SSL_CTX_set1_sigalgs.html]=man3/SSL_CTX_set1_sigalgs.pod +DEPEND[man/man3/SSL_CTX_set1_sigalgs.3]=man3/SSL_CTX_set1_sigalgs.pod +GENERATE[man/man3/SSL_CTX_set1_sigalgs.3]=man3/SSL_CTX_set1_sigalgs.pod +DEPEND[html/man3/SSL_CTX_set1_verify_cert_store.html]=man3/SSL_CTX_set1_verify_cert_store.pod +GENERATE[html/man3/SSL_CTX_set1_verify_cert_store.html]=man3/SSL_CTX_set1_verify_cert_store.pod +DEPEND[man/man3/SSL_CTX_set1_verify_cert_store.3]=man3/SSL_CTX_set1_verify_cert_store.pod +GENERATE[man/man3/SSL_CTX_set1_verify_cert_store.3]=man3/SSL_CTX_set1_verify_cert_store.pod +DEPEND[html/man3/SSL_CTX_set_alpn_select_cb.html]=man3/SSL_CTX_set_alpn_select_cb.pod +GENERATE[html/man3/SSL_CTX_set_alpn_select_cb.html]=man3/SSL_CTX_set_alpn_select_cb.pod +DEPEND[man/man3/SSL_CTX_set_alpn_select_cb.3]=man3/SSL_CTX_set_alpn_select_cb.pod +GENERATE[man/man3/SSL_CTX_set_alpn_select_cb.3]=man3/SSL_CTX_set_alpn_select_cb.pod +DEPEND[html/man3/SSL_CTX_set_cert_cb.html]=man3/SSL_CTX_set_cert_cb.pod +GENERATE[html/man3/SSL_CTX_set_cert_cb.html]=man3/SSL_CTX_set_cert_cb.pod +DEPEND[man/man3/SSL_CTX_set_cert_cb.3]=man3/SSL_CTX_set_cert_cb.pod +GENERATE[man/man3/SSL_CTX_set_cert_cb.3]=man3/SSL_CTX_set_cert_cb.pod +DEPEND[html/man3/SSL_CTX_set_cert_store.html]=man3/SSL_CTX_set_cert_store.pod +GENERATE[html/man3/SSL_CTX_set_cert_store.html]=man3/SSL_CTX_set_cert_store.pod +DEPEND[man/man3/SSL_CTX_set_cert_store.3]=man3/SSL_CTX_set_cert_store.pod +GENERATE[man/man3/SSL_CTX_set_cert_store.3]=man3/SSL_CTX_set_cert_store.pod +DEPEND[html/man3/SSL_CTX_set_cert_verify_callback.html]=man3/SSL_CTX_set_cert_verify_callback.pod +GENERATE[html/man3/SSL_CTX_set_cert_verify_callback.html]=man3/SSL_CTX_set_cert_verify_callback.pod +DEPEND[man/man3/SSL_CTX_set_cert_verify_callback.3]=man3/SSL_CTX_set_cert_verify_callback.pod +GENERATE[man/man3/SSL_CTX_set_cert_verify_callback.3]=man3/SSL_CTX_set_cert_verify_callback.pod +DEPEND[html/man3/SSL_CTX_set_cipher_list.html]=man3/SSL_CTX_set_cipher_list.pod +GENERATE[html/man3/SSL_CTX_set_cipher_list.html]=man3/SSL_CTX_set_cipher_list.pod +DEPEND[man/man3/SSL_CTX_set_cipher_list.3]=man3/SSL_CTX_set_cipher_list.pod +GENERATE[man/man3/SSL_CTX_set_cipher_list.3]=man3/SSL_CTX_set_cipher_list.pod +DEPEND[html/man3/SSL_CTX_set_client_cert_cb.html]=man3/SSL_CTX_set_client_cert_cb.pod +GENERATE[html/man3/SSL_CTX_set_client_cert_cb.html]=man3/SSL_CTX_set_client_cert_cb.pod +DEPEND[man/man3/SSL_CTX_set_client_cert_cb.3]=man3/SSL_CTX_set_client_cert_cb.pod +GENERATE[man/man3/SSL_CTX_set_client_cert_cb.3]=man3/SSL_CTX_set_client_cert_cb.pod +DEPEND[html/man3/SSL_CTX_set_client_hello_cb.html]=man3/SSL_CTX_set_client_hello_cb.pod +GENERATE[html/man3/SSL_CTX_set_client_hello_cb.html]=man3/SSL_CTX_set_client_hello_cb.pod +DEPEND[man/man3/SSL_CTX_set_client_hello_cb.3]=man3/SSL_CTX_set_client_hello_cb.pod +GENERATE[man/man3/SSL_CTX_set_client_hello_cb.3]=man3/SSL_CTX_set_client_hello_cb.pod +DEPEND[html/man3/SSL_CTX_set_ct_validation_callback.html]=man3/SSL_CTX_set_ct_validation_callback.pod +GENERATE[html/man3/SSL_CTX_set_ct_validation_callback.html]=man3/SSL_CTX_set_ct_validation_callback.pod +DEPEND[man/man3/SSL_CTX_set_ct_validation_callback.3]=man3/SSL_CTX_set_ct_validation_callback.pod +GENERATE[man/man3/SSL_CTX_set_ct_validation_callback.3]=man3/SSL_CTX_set_ct_validation_callback.pod +DEPEND[html/man3/SSL_CTX_set_ctlog_list_file.html]=man3/SSL_CTX_set_ctlog_list_file.pod +GENERATE[html/man3/SSL_CTX_set_ctlog_list_file.html]=man3/SSL_CTX_set_ctlog_list_file.pod +DEPEND[man/man3/SSL_CTX_set_ctlog_list_file.3]=man3/SSL_CTX_set_ctlog_list_file.pod +GENERATE[man/man3/SSL_CTX_set_ctlog_list_file.3]=man3/SSL_CTX_set_ctlog_list_file.pod +DEPEND[html/man3/SSL_CTX_set_default_passwd_cb.html]=man3/SSL_CTX_set_default_passwd_cb.pod +GENERATE[html/man3/SSL_CTX_set_default_passwd_cb.html]=man3/SSL_CTX_set_default_passwd_cb.pod +DEPEND[man/man3/SSL_CTX_set_default_passwd_cb.3]=man3/SSL_CTX_set_default_passwd_cb.pod +GENERATE[man/man3/SSL_CTX_set_default_passwd_cb.3]=man3/SSL_CTX_set_default_passwd_cb.pod +DEPEND[html/man3/SSL_CTX_set_generate_session_id.html]=man3/SSL_CTX_set_generate_session_id.pod +GENERATE[html/man3/SSL_CTX_set_generate_session_id.html]=man3/SSL_CTX_set_generate_session_id.pod +DEPEND[man/man3/SSL_CTX_set_generate_session_id.3]=man3/SSL_CTX_set_generate_session_id.pod +GENERATE[man/man3/SSL_CTX_set_generate_session_id.3]=man3/SSL_CTX_set_generate_session_id.pod +DEPEND[html/man3/SSL_CTX_set_info_callback.html]=man3/SSL_CTX_set_info_callback.pod +GENERATE[html/man3/SSL_CTX_set_info_callback.html]=man3/SSL_CTX_set_info_callback.pod +DEPEND[man/man3/SSL_CTX_set_info_callback.3]=man3/SSL_CTX_set_info_callback.pod +GENERATE[man/man3/SSL_CTX_set_info_callback.3]=man3/SSL_CTX_set_info_callback.pod +DEPEND[html/man3/SSL_CTX_set_keylog_callback.html]=man3/SSL_CTX_set_keylog_callback.pod +GENERATE[html/man3/SSL_CTX_set_keylog_callback.html]=man3/SSL_CTX_set_keylog_callback.pod +DEPEND[man/man3/SSL_CTX_set_keylog_callback.3]=man3/SSL_CTX_set_keylog_callback.pod +GENERATE[man/man3/SSL_CTX_set_keylog_callback.3]=man3/SSL_CTX_set_keylog_callback.pod +DEPEND[html/man3/SSL_CTX_set_max_cert_list.html]=man3/SSL_CTX_set_max_cert_list.pod +GENERATE[html/man3/SSL_CTX_set_max_cert_list.html]=man3/SSL_CTX_set_max_cert_list.pod +DEPEND[man/man3/SSL_CTX_set_max_cert_list.3]=man3/SSL_CTX_set_max_cert_list.pod +GENERATE[man/man3/SSL_CTX_set_max_cert_list.3]=man3/SSL_CTX_set_max_cert_list.pod +DEPEND[html/man3/SSL_CTX_set_min_proto_version.html]=man3/SSL_CTX_set_min_proto_version.pod +GENERATE[html/man3/SSL_CTX_set_min_proto_version.html]=man3/SSL_CTX_set_min_proto_version.pod +DEPEND[man/man3/SSL_CTX_set_min_proto_version.3]=man3/SSL_CTX_set_min_proto_version.pod +GENERATE[man/man3/SSL_CTX_set_min_proto_version.3]=man3/SSL_CTX_set_min_proto_version.pod +DEPEND[html/man3/SSL_CTX_set_mode.html]=man3/SSL_CTX_set_mode.pod +GENERATE[html/man3/SSL_CTX_set_mode.html]=man3/SSL_CTX_set_mode.pod +DEPEND[man/man3/SSL_CTX_set_mode.3]=man3/SSL_CTX_set_mode.pod +GENERATE[man/man3/SSL_CTX_set_mode.3]=man3/SSL_CTX_set_mode.pod +DEPEND[html/man3/SSL_CTX_set_msg_callback.html]=man3/SSL_CTX_set_msg_callback.pod +GENERATE[html/man3/SSL_CTX_set_msg_callback.html]=man3/SSL_CTX_set_msg_callback.pod +DEPEND[man/man3/SSL_CTX_set_msg_callback.3]=man3/SSL_CTX_set_msg_callback.pod +GENERATE[man/man3/SSL_CTX_set_msg_callback.3]=man3/SSL_CTX_set_msg_callback.pod +DEPEND[html/man3/SSL_CTX_set_num_tickets.html]=man3/SSL_CTX_set_num_tickets.pod +GENERATE[html/man3/SSL_CTX_set_num_tickets.html]=man3/SSL_CTX_set_num_tickets.pod +DEPEND[man/man3/SSL_CTX_set_num_tickets.3]=man3/SSL_CTX_set_num_tickets.pod +GENERATE[man/man3/SSL_CTX_set_num_tickets.3]=man3/SSL_CTX_set_num_tickets.pod +DEPEND[html/man3/SSL_CTX_set_options.html]=man3/SSL_CTX_set_options.pod +GENERATE[html/man3/SSL_CTX_set_options.html]=man3/SSL_CTX_set_options.pod +DEPEND[man/man3/SSL_CTX_set_options.3]=man3/SSL_CTX_set_options.pod +GENERATE[man/man3/SSL_CTX_set_options.3]=man3/SSL_CTX_set_options.pod +DEPEND[html/man3/SSL_CTX_set_psk_client_callback.html]=man3/SSL_CTX_set_psk_client_callback.pod +GENERATE[html/man3/SSL_CTX_set_psk_client_callback.html]=man3/SSL_CTX_set_psk_client_callback.pod +DEPEND[man/man3/SSL_CTX_set_psk_client_callback.3]=man3/SSL_CTX_set_psk_client_callback.pod +GENERATE[man/man3/SSL_CTX_set_psk_client_callback.3]=man3/SSL_CTX_set_psk_client_callback.pod +DEPEND[html/man3/SSL_CTX_set_quiet_shutdown.html]=man3/SSL_CTX_set_quiet_shutdown.pod +GENERATE[html/man3/SSL_CTX_set_quiet_shutdown.html]=man3/SSL_CTX_set_quiet_shutdown.pod +DEPEND[man/man3/SSL_CTX_set_quiet_shutdown.3]=man3/SSL_CTX_set_quiet_shutdown.pod +GENERATE[man/man3/SSL_CTX_set_quiet_shutdown.3]=man3/SSL_CTX_set_quiet_shutdown.pod +DEPEND[html/man3/SSL_CTX_set_read_ahead.html]=man3/SSL_CTX_set_read_ahead.pod +GENERATE[html/man3/SSL_CTX_set_read_ahead.html]=man3/SSL_CTX_set_read_ahead.pod +DEPEND[man/man3/SSL_CTX_set_read_ahead.3]=man3/SSL_CTX_set_read_ahead.pod +GENERATE[man/man3/SSL_CTX_set_read_ahead.3]=man3/SSL_CTX_set_read_ahead.pod +DEPEND[html/man3/SSL_CTX_set_record_padding_callback.html]=man3/SSL_CTX_set_record_padding_callback.pod +GENERATE[html/man3/SSL_CTX_set_record_padding_callback.html]=man3/SSL_CTX_set_record_padding_callback.pod +DEPEND[man/man3/SSL_CTX_set_record_padding_callback.3]=man3/SSL_CTX_set_record_padding_callback.pod +GENERATE[man/man3/SSL_CTX_set_record_padding_callback.3]=man3/SSL_CTX_set_record_padding_callback.pod +DEPEND[html/man3/SSL_CTX_set_security_level.html]=man3/SSL_CTX_set_security_level.pod +GENERATE[html/man3/SSL_CTX_set_security_level.html]=man3/SSL_CTX_set_security_level.pod +DEPEND[man/man3/SSL_CTX_set_security_level.3]=man3/SSL_CTX_set_security_level.pod +GENERATE[man/man3/SSL_CTX_set_security_level.3]=man3/SSL_CTX_set_security_level.pod +DEPEND[html/man3/SSL_CTX_set_session_cache_mode.html]=man3/SSL_CTX_set_session_cache_mode.pod +GENERATE[html/man3/SSL_CTX_set_session_cache_mode.html]=man3/SSL_CTX_set_session_cache_mode.pod +DEPEND[man/man3/SSL_CTX_set_session_cache_mode.3]=man3/SSL_CTX_set_session_cache_mode.pod +GENERATE[man/man3/SSL_CTX_set_session_cache_mode.3]=man3/SSL_CTX_set_session_cache_mode.pod +DEPEND[html/man3/SSL_CTX_set_session_id_context.html]=man3/SSL_CTX_set_session_id_context.pod +GENERATE[html/man3/SSL_CTX_set_session_id_context.html]=man3/SSL_CTX_set_session_id_context.pod +DEPEND[man/man3/SSL_CTX_set_session_id_context.3]=man3/SSL_CTX_set_session_id_context.pod +GENERATE[man/man3/SSL_CTX_set_session_id_context.3]=man3/SSL_CTX_set_session_id_context.pod +DEPEND[html/man3/SSL_CTX_set_session_ticket_cb.html]=man3/SSL_CTX_set_session_ticket_cb.pod +GENERATE[html/man3/SSL_CTX_set_session_ticket_cb.html]=man3/SSL_CTX_set_session_ticket_cb.pod +DEPEND[man/man3/SSL_CTX_set_session_ticket_cb.3]=man3/SSL_CTX_set_session_ticket_cb.pod +GENERATE[man/man3/SSL_CTX_set_session_ticket_cb.3]=man3/SSL_CTX_set_session_ticket_cb.pod +DEPEND[html/man3/SSL_CTX_set_split_send_fragment.html]=man3/SSL_CTX_set_split_send_fragment.pod +GENERATE[html/man3/SSL_CTX_set_split_send_fragment.html]=man3/SSL_CTX_set_split_send_fragment.pod +DEPEND[man/man3/SSL_CTX_set_split_send_fragment.3]=man3/SSL_CTX_set_split_send_fragment.pod +GENERATE[man/man3/SSL_CTX_set_split_send_fragment.3]=man3/SSL_CTX_set_split_send_fragment.pod +DEPEND[html/man3/SSL_CTX_set_srp_password.html]=man3/SSL_CTX_set_srp_password.pod +GENERATE[html/man3/SSL_CTX_set_srp_password.html]=man3/SSL_CTX_set_srp_password.pod +DEPEND[man/man3/SSL_CTX_set_srp_password.3]=man3/SSL_CTX_set_srp_password.pod +GENERATE[man/man3/SSL_CTX_set_srp_password.3]=man3/SSL_CTX_set_srp_password.pod +DEPEND[html/man3/SSL_CTX_set_ssl_version.html]=man3/SSL_CTX_set_ssl_version.pod +GENERATE[html/man3/SSL_CTX_set_ssl_version.html]=man3/SSL_CTX_set_ssl_version.pod +DEPEND[man/man3/SSL_CTX_set_ssl_version.3]=man3/SSL_CTX_set_ssl_version.pod +GENERATE[man/man3/SSL_CTX_set_ssl_version.3]=man3/SSL_CTX_set_ssl_version.pod +DEPEND[html/man3/SSL_CTX_set_stateless_cookie_generate_cb.html]=man3/SSL_CTX_set_stateless_cookie_generate_cb.pod +GENERATE[html/man3/SSL_CTX_set_stateless_cookie_generate_cb.html]=man3/SSL_CTX_set_stateless_cookie_generate_cb.pod +DEPEND[man/man3/SSL_CTX_set_stateless_cookie_generate_cb.3]=man3/SSL_CTX_set_stateless_cookie_generate_cb.pod +GENERATE[man/man3/SSL_CTX_set_stateless_cookie_generate_cb.3]=man3/SSL_CTX_set_stateless_cookie_generate_cb.pod +DEPEND[html/man3/SSL_CTX_set_timeout.html]=man3/SSL_CTX_set_timeout.pod +GENERATE[html/man3/SSL_CTX_set_timeout.html]=man3/SSL_CTX_set_timeout.pod +DEPEND[man/man3/SSL_CTX_set_timeout.3]=man3/SSL_CTX_set_timeout.pod +GENERATE[man/man3/SSL_CTX_set_timeout.3]=man3/SSL_CTX_set_timeout.pod +DEPEND[html/man3/SSL_CTX_set_tlsext_servername_callback.html]=man3/SSL_CTX_set_tlsext_servername_callback.pod +GENERATE[html/man3/SSL_CTX_set_tlsext_servername_callback.html]=man3/SSL_CTX_set_tlsext_servername_callback.pod +DEPEND[man/man3/SSL_CTX_set_tlsext_servername_callback.3]=man3/SSL_CTX_set_tlsext_servername_callback.pod +GENERATE[man/man3/SSL_CTX_set_tlsext_servername_callback.3]=man3/SSL_CTX_set_tlsext_servername_callback.pod +DEPEND[html/man3/SSL_CTX_set_tlsext_status_cb.html]=man3/SSL_CTX_set_tlsext_status_cb.pod +GENERATE[html/man3/SSL_CTX_set_tlsext_status_cb.html]=man3/SSL_CTX_set_tlsext_status_cb.pod +DEPEND[man/man3/SSL_CTX_set_tlsext_status_cb.3]=man3/SSL_CTX_set_tlsext_status_cb.pod +GENERATE[man/man3/SSL_CTX_set_tlsext_status_cb.3]=man3/SSL_CTX_set_tlsext_status_cb.pod +DEPEND[html/man3/SSL_CTX_set_tlsext_ticket_key_cb.html]=man3/SSL_CTX_set_tlsext_ticket_key_cb.pod +GENERATE[html/man3/SSL_CTX_set_tlsext_ticket_key_cb.html]=man3/SSL_CTX_set_tlsext_ticket_key_cb.pod +DEPEND[man/man3/SSL_CTX_set_tlsext_ticket_key_cb.3]=man3/SSL_CTX_set_tlsext_ticket_key_cb.pod +GENERATE[man/man3/SSL_CTX_set_tlsext_ticket_key_cb.3]=man3/SSL_CTX_set_tlsext_ticket_key_cb.pod +DEPEND[html/man3/SSL_CTX_set_tlsext_use_srtp.html]=man3/SSL_CTX_set_tlsext_use_srtp.pod +GENERATE[html/man3/SSL_CTX_set_tlsext_use_srtp.html]=man3/SSL_CTX_set_tlsext_use_srtp.pod +DEPEND[man/man3/SSL_CTX_set_tlsext_use_srtp.3]=man3/SSL_CTX_set_tlsext_use_srtp.pod +GENERATE[man/man3/SSL_CTX_set_tlsext_use_srtp.3]=man3/SSL_CTX_set_tlsext_use_srtp.pod +DEPEND[html/man3/SSL_CTX_set_tmp_dh_callback.html]=man3/SSL_CTX_set_tmp_dh_callback.pod +GENERATE[html/man3/SSL_CTX_set_tmp_dh_callback.html]=man3/SSL_CTX_set_tmp_dh_callback.pod +DEPEND[man/man3/SSL_CTX_set_tmp_dh_callback.3]=man3/SSL_CTX_set_tmp_dh_callback.pod +GENERATE[man/man3/SSL_CTX_set_tmp_dh_callback.3]=man3/SSL_CTX_set_tmp_dh_callback.pod +DEPEND[html/man3/SSL_CTX_set_tmp_ecdh.html]=man3/SSL_CTX_set_tmp_ecdh.pod +GENERATE[html/man3/SSL_CTX_set_tmp_ecdh.html]=man3/SSL_CTX_set_tmp_ecdh.pod +DEPEND[man/man3/SSL_CTX_set_tmp_ecdh.3]=man3/SSL_CTX_set_tmp_ecdh.pod +GENERATE[man/man3/SSL_CTX_set_tmp_ecdh.3]=man3/SSL_CTX_set_tmp_ecdh.pod +DEPEND[html/man3/SSL_CTX_set_verify.html]=man3/SSL_CTX_set_verify.pod +GENERATE[html/man3/SSL_CTX_set_verify.html]=man3/SSL_CTX_set_verify.pod +DEPEND[man/man3/SSL_CTX_set_verify.3]=man3/SSL_CTX_set_verify.pod +GENERATE[man/man3/SSL_CTX_set_verify.3]=man3/SSL_CTX_set_verify.pod +DEPEND[html/man3/SSL_CTX_use_certificate.html]=man3/SSL_CTX_use_certificate.pod +GENERATE[html/man3/SSL_CTX_use_certificate.html]=man3/SSL_CTX_use_certificate.pod +DEPEND[man/man3/SSL_CTX_use_certificate.3]=man3/SSL_CTX_use_certificate.pod +GENERATE[man/man3/SSL_CTX_use_certificate.3]=man3/SSL_CTX_use_certificate.pod +DEPEND[html/man3/SSL_CTX_use_psk_identity_hint.html]=man3/SSL_CTX_use_psk_identity_hint.pod +GENERATE[html/man3/SSL_CTX_use_psk_identity_hint.html]=man3/SSL_CTX_use_psk_identity_hint.pod +DEPEND[man/man3/SSL_CTX_use_psk_identity_hint.3]=man3/SSL_CTX_use_psk_identity_hint.pod +GENERATE[man/man3/SSL_CTX_use_psk_identity_hint.3]=man3/SSL_CTX_use_psk_identity_hint.pod +DEPEND[html/man3/SSL_CTX_use_serverinfo.html]=man3/SSL_CTX_use_serverinfo.pod +GENERATE[html/man3/SSL_CTX_use_serverinfo.html]=man3/SSL_CTX_use_serverinfo.pod +DEPEND[man/man3/SSL_CTX_use_serverinfo.3]=man3/SSL_CTX_use_serverinfo.pod +GENERATE[man/man3/SSL_CTX_use_serverinfo.3]=man3/SSL_CTX_use_serverinfo.pod +DEPEND[html/man3/SSL_SESSION_free.html]=man3/SSL_SESSION_free.pod +GENERATE[html/man3/SSL_SESSION_free.html]=man3/SSL_SESSION_free.pod +DEPEND[man/man3/SSL_SESSION_free.3]=man3/SSL_SESSION_free.pod +GENERATE[man/man3/SSL_SESSION_free.3]=man3/SSL_SESSION_free.pod +DEPEND[html/man3/SSL_SESSION_get0_cipher.html]=man3/SSL_SESSION_get0_cipher.pod +GENERATE[html/man3/SSL_SESSION_get0_cipher.html]=man3/SSL_SESSION_get0_cipher.pod +DEPEND[man/man3/SSL_SESSION_get0_cipher.3]=man3/SSL_SESSION_get0_cipher.pod +GENERATE[man/man3/SSL_SESSION_get0_cipher.3]=man3/SSL_SESSION_get0_cipher.pod +DEPEND[html/man3/SSL_SESSION_get0_hostname.html]=man3/SSL_SESSION_get0_hostname.pod +GENERATE[html/man3/SSL_SESSION_get0_hostname.html]=man3/SSL_SESSION_get0_hostname.pod +DEPEND[man/man3/SSL_SESSION_get0_hostname.3]=man3/SSL_SESSION_get0_hostname.pod +GENERATE[man/man3/SSL_SESSION_get0_hostname.3]=man3/SSL_SESSION_get0_hostname.pod +DEPEND[html/man3/SSL_SESSION_get0_id_context.html]=man3/SSL_SESSION_get0_id_context.pod +GENERATE[html/man3/SSL_SESSION_get0_id_context.html]=man3/SSL_SESSION_get0_id_context.pod +DEPEND[man/man3/SSL_SESSION_get0_id_context.3]=man3/SSL_SESSION_get0_id_context.pod +GENERATE[man/man3/SSL_SESSION_get0_id_context.3]=man3/SSL_SESSION_get0_id_context.pod +DEPEND[html/man3/SSL_SESSION_get0_peer.html]=man3/SSL_SESSION_get0_peer.pod +GENERATE[html/man3/SSL_SESSION_get0_peer.html]=man3/SSL_SESSION_get0_peer.pod +DEPEND[man/man3/SSL_SESSION_get0_peer.3]=man3/SSL_SESSION_get0_peer.pod +GENERATE[man/man3/SSL_SESSION_get0_peer.3]=man3/SSL_SESSION_get0_peer.pod +DEPEND[html/man3/SSL_SESSION_get_compress_id.html]=man3/SSL_SESSION_get_compress_id.pod +GENERATE[html/man3/SSL_SESSION_get_compress_id.html]=man3/SSL_SESSION_get_compress_id.pod +DEPEND[man/man3/SSL_SESSION_get_compress_id.3]=man3/SSL_SESSION_get_compress_id.pod +GENERATE[man/man3/SSL_SESSION_get_compress_id.3]=man3/SSL_SESSION_get_compress_id.pod +DEPEND[html/man3/SSL_SESSION_get_protocol_version.html]=man3/SSL_SESSION_get_protocol_version.pod +GENERATE[html/man3/SSL_SESSION_get_protocol_version.html]=man3/SSL_SESSION_get_protocol_version.pod +DEPEND[man/man3/SSL_SESSION_get_protocol_version.3]=man3/SSL_SESSION_get_protocol_version.pod +GENERATE[man/man3/SSL_SESSION_get_protocol_version.3]=man3/SSL_SESSION_get_protocol_version.pod +DEPEND[html/man3/SSL_SESSION_get_time.html]=man3/SSL_SESSION_get_time.pod +GENERATE[html/man3/SSL_SESSION_get_time.html]=man3/SSL_SESSION_get_time.pod +DEPEND[man/man3/SSL_SESSION_get_time.3]=man3/SSL_SESSION_get_time.pod +GENERATE[man/man3/SSL_SESSION_get_time.3]=man3/SSL_SESSION_get_time.pod +DEPEND[html/man3/SSL_SESSION_has_ticket.html]=man3/SSL_SESSION_has_ticket.pod +GENERATE[html/man3/SSL_SESSION_has_ticket.html]=man3/SSL_SESSION_has_ticket.pod +DEPEND[man/man3/SSL_SESSION_has_ticket.3]=man3/SSL_SESSION_has_ticket.pod +GENERATE[man/man3/SSL_SESSION_has_ticket.3]=man3/SSL_SESSION_has_ticket.pod +DEPEND[html/man3/SSL_SESSION_is_resumable.html]=man3/SSL_SESSION_is_resumable.pod +GENERATE[html/man3/SSL_SESSION_is_resumable.html]=man3/SSL_SESSION_is_resumable.pod +DEPEND[man/man3/SSL_SESSION_is_resumable.3]=man3/SSL_SESSION_is_resumable.pod +GENERATE[man/man3/SSL_SESSION_is_resumable.3]=man3/SSL_SESSION_is_resumable.pod +DEPEND[html/man3/SSL_SESSION_print.html]=man3/SSL_SESSION_print.pod +GENERATE[html/man3/SSL_SESSION_print.html]=man3/SSL_SESSION_print.pod +DEPEND[man/man3/SSL_SESSION_print.3]=man3/SSL_SESSION_print.pod +GENERATE[man/man3/SSL_SESSION_print.3]=man3/SSL_SESSION_print.pod +DEPEND[html/man3/SSL_SESSION_set1_id.html]=man3/SSL_SESSION_set1_id.pod +GENERATE[html/man3/SSL_SESSION_set1_id.html]=man3/SSL_SESSION_set1_id.pod +DEPEND[man/man3/SSL_SESSION_set1_id.3]=man3/SSL_SESSION_set1_id.pod +GENERATE[man/man3/SSL_SESSION_set1_id.3]=man3/SSL_SESSION_set1_id.pod +DEPEND[html/man3/SSL_accept.html]=man3/SSL_accept.pod +GENERATE[html/man3/SSL_accept.html]=man3/SSL_accept.pod +DEPEND[man/man3/SSL_accept.3]=man3/SSL_accept.pod +GENERATE[man/man3/SSL_accept.3]=man3/SSL_accept.pod +DEPEND[html/man3/SSL_alert_type_string.html]=man3/SSL_alert_type_string.pod +GENERATE[html/man3/SSL_alert_type_string.html]=man3/SSL_alert_type_string.pod +DEPEND[man/man3/SSL_alert_type_string.3]=man3/SSL_alert_type_string.pod +GENERATE[man/man3/SSL_alert_type_string.3]=man3/SSL_alert_type_string.pod +DEPEND[html/man3/SSL_alloc_buffers.html]=man3/SSL_alloc_buffers.pod +GENERATE[html/man3/SSL_alloc_buffers.html]=man3/SSL_alloc_buffers.pod +DEPEND[man/man3/SSL_alloc_buffers.3]=man3/SSL_alloc_buffers.pod +GENERATE[man/man3/SSL_alloc_buffers.3]=man3/SSL_alloc_buffers.pod +DEPEND[html/man3/SSL_check_chain.html]=man3/SSL_check_chain.pod +GENERATE[html/man3/SSL_check_chain.html]=man3/SSL_check_chain.pod +DEPEND[man/man3/SSL_check_chain.3]=man3/SSL_check_chain.pod +GENERATE[man/man3/SSL_check_chain.3]=man3/SSL_check_chain.pod +DEPEND[html/man3/SSL_clear.html]=man3/SSL_clear.pod +GENERATE[html/man3/SSL_clear.html]=man3/SSL_clear.pod +DEPEND[man/man3/SSL_clear.3]=man3/SSL_clear.pod +GENERATE[man/man3/SSL_clear.3]=man3/SSL_clear.pod +DEPEND[html/man3/SSL_connect.html]=man3/SSL_connect.pod +GENERATE[html/man3/SSL_connect.html]=man3/SSL_connect.pod +DEPEND[man/man3/SSL_connect.3]=man3/SSL_connect.pod +GENERATE[man/man3/SSL_connect.3]=man3/SSL_connect.pod +DEPEND[html/man3/SSL_do_handshake.html]=man3/SSL_do_handshake.pod +GENERATE[html/man3/SSL_do_handshake.html]=man3/SSL_do_handshake.pod +DEPEND[man/man3/SSL_do_handshake.3]=man3/SSL_do_handshake.pod +GENERATE[man/man3/SSL_do_handshake.3]=man3/SSL_do_handshake.pod +DEPEND[html/man3/SSL_export_keying_material.html]=man3/SSL_export_keying_material.pod +GENERATE[html/man3/SSL_export_keying_material.html]=man3/SSL_export_keying_material.pod +DEPEND[man/man3/SSL_export_keying_material.3]=man3/SSL_export_keying_material.pod +GENERATE[man/man3/SSL_export_keying_material.3]=man3/SSL_export_keying_material.pod +DEPEND[html/man3/SSL_extension_supported.html]=man3/SSL_extension_supported.pod +GENERATE[html/man3/SSL_extension_supported.html]=man3/SSL_extension_supported.pod +DEPEND[man/man3/SSL_extension_supported.3]=man3/SSL_extension_supported.pod +GENERATE[man/man3/SSL_extension_supported.3]=man3/SSL_extension_supported.pod +DEPEND[html/man3/SSL_free.html]=man3/SSL_free.pod +GENERATE[html/man3/SSL_free.html]=man3/SSL_free.pod +DEPEND[man/man3/SSL_free.3]=man3/SSL_free.pod +GENERATE[man/man3/SSL_free.3]=man3/SSL_free.pod +DEPEND[html/man3/SSL_get0_peer_scts.html]=man3/SSL_get0_peer_scts.pod +GENERATE[html/man3/SSL_get0_peer_scts.html]=man3/SSL_get0_peer_scts.pod +DEPEND[man/man3/SSL_get0_peer_scts.3]=man3/SSL_get0_peer_scts.pod +GENERATE[man/man3/SSL_get0_peer_scts.3]=man3/SSL_get0_peer_scts.pod +DEPEND[html/man3/SSL_get_SSL_CTX.html]=man3/SSL_get_SSL_CTX.pod +GENERATE[html/man3/SSL_get_SSL_CTX.html]=man3/SSL_get_SSL_CTX.pod +DEPEND[man/man3/SSL_get_SSL_CTX.3]=man3/SSL_get_SSL_CTX.pod +GENERATE[man/man3/SSL_get_SSL_CTX.3]=man3/SSL_get_SSL_CTX.pod +DEPEND[html/man3/SSL_get_all_async_fds.html]=man3/SSL_get_all_async_fds.pod +GENERATE[html/man3/SSL_get_all_async_fds.html]=man3/SSL_get_all_async_fds.pod +DEPEND[man/man3/SSL_get_all_async_fds.3]=man3/SSL_get_all_async_fds.pod +GENERATE[man/man3/SSL_get_all_async_fds.3]=man3/SSL_get_all_async_fds.pod +DEPEND[html/man3/SSL_get_certificate.html]=man3/SSL_get_certificate.pod +GENERATE[html/man3/SSL_get_certificate.html]=man3/SSL_get_certificate.pod +DEPEND[man/man3/SSL_get_certificate.3]=man3/SSL_get_certificate.pod +GENERATE[man/man3/SSL_get_certificate.3]=man3/SSL_get_certificate.pod +DEPEND[html/man3/SSL_get_ciphers.html]=man3/SSL_get_ciphers.pod +GENERATE[html/man3/SSL_get_ciphers.html]=man3/SSL_get_ciphers.pod +DEPEND[man/man3/SSL_get_ciphers.3]=man3/SSL_get_ciphers.pod +GENERATE[man/man3/SSL_get_ciphers.3]=man3/SSL_get_ciphers.pod +DEPEND[html/man3/SSL_get_client_random.html]=man3/SSL_get_client_random.pod +GENERATE[html/man3/SSL_get_client_random.html]=man3/SSL_get_client_random.pod +DEPEND[man/man3/SSL_get_client_random.3]=man3/SSL_get_client_random.pod +GENERATE[man/man3/SSL_get_client_random.3]=man3/SSL_get_client_random.pod +DEPEND[html/man3/SSL_get_current_cipher.html]=man3/SSL_get_current_cipher.pod +GENERATE[html/man3/SSL_get_current_cipher.html]=man3/SSL_get_current_cipher.pod +DEPEND[man/man3/SSL_get_current_cipher.3]=man3/SSL_get_current_cipher.pod +GENERATE[man/man3/SSL_get_current_cipher.3]=man3/SSL_get_current_cipher.pod +DEPEND[html/man3/SSL_get_default_timeout.html]=man3/SSL_get_default_timeout.pod +GENERATE[html/man3/SSL_get_default_timeout.html]=man3/SSL_get_default_timeout.pod +DEPEND[man/man3/SSL_get_default_timeout.3]=man3/SSL_get_default_timeout.pod +GENERATE[man/man3/SSL_get_default_timeout.3]=man3/SSL_get_default_timeout.pod +DEPEND[html/man3/SSL_get_error.html]=man3/SSL_get_error.pod +GENERATE[html/man3/SSL_get_error.html]=man3/SSL_get_error.pod +DEPEND[man/man3/SSL_get_error.3]=man3/SSL_get_error.pod +GENERATE[man/man3/SSL_get_error.3]=man3/SSL_get_error.pod +DEPEND[html/man3/SSL_get_extms_support.html]=man3/SSL_get_extms_support.pod +GENERATE[html/man3/SSL_get_extms_support.html]=man3/SSL_get_extms_support.pod +DEPEND[man/man3/SSL_get_extms_support.3]=man3/SSL_get_extms_support.pod +GENERATE[man/man3/SSL_get_extms_support.3]=man3/SSL_get_extms_support.pod +DEPEND[html/man3/SSL_get_fd.html]=man3/SSL_get_fd.pod +GENERATE[html/man3/SSL_get_fd.html]=man3/SSL_get_fd.pod +DEPEND[man/man3/SSL_get_fd.3]=man3/SSL_get_fd.pod +GENERATE[man/man3/SSL_get_fd.3]=man3/SSL_get_fd.pod +DEPEND[html/man3/SSL_get_peer_cert_chain.html]=man3/SSL_get_peer_cert_chain.pod +GENERATE[html/man3/SSL_get_peer_cert_chain.html]=man3/SSL_get_peer_cert_chain.pod +DEPEND[man/man3/SSL_get_peer_cert_chain.3]=man3/SSL_get_peer_cert_chain.pod +GENERATE[man/man3/SSL_get_peer_cert_chain.3]=man3/SSL_get_peer_cert_chain.pod +DEPEND[html/man3/SSL_get_peer_certificate.html]=man3/SSL_get_peer_certificate.pod +GENERATE[html/man3/SSL_get_peer_certificate.html]=man3/SSL_get_peer_certificate.pod +DEPEND[man/man3/SSL_get_peer_certificate.3]=man3/SSL_get_peer_certificate.pod +GENERATE[man/man3/SSL_get_peer_certificate.3]=man3/SSL_get_peer_certificate.pod +DEPEND[html/man3/SSL_get_peer_signature_nid.html]=man3/SSL_get_peer_signature_nid.pod +GENERATE[html/man3/SSL_get_peer_signature_nid.html]=man3/SSL_get_peer_signature_nid.pod +DEPEND[man/man3/SSL_get_peer_signature_nid.3]=man3/SSL_get_peer_signature_nid.pod +GENERATE[man/man3/SSL_get_peer_signature_nid.3]=man3/SSL_get_peer_signature_nid.pod +DEPEND[html/man3/SSL_get_peer_tmp_key.html]=man3/SSL_get_peer_tmp_key.pod +GENERATE[html/man3/SSL_get_peer_tmp_key.html]=man3/SSL_get_peer_tmp_key.pod +DEPEND[man/man3/SSL_get_peer_tmp_key.3]=man3/SSL_get_peer_tmp_key.pod +GENERATE[man/man3/SSL_get_peer_tmp_key.3]=man3/SSL_get_peer_tmp_key.pod +DEPEND[html/man3/SSL_get_psk_identity.html]=man3/SSL_get_psk_identity.pod +GENERATE[html/man3/SSL_get_psk_identity.html]=man3/SSL_get_psk_identity.pod +DEPEND[man/man3/SSL_get_psk_identity.3]=man3/SSL_get_psk_identity.pod +GENERATE[man/man3/SSL_get_psk_identity.3]=man3/SSL_get_psk_identity.pod +DEPEND[html/man3/SSL_get_rbio.html]=man3/SSL_get_rbio.pod +GENERATE[html/man3/SSL_get_rbio.html]=man3/SSL_get_rbio.pod +DEPEND[man/man3/SSL_get_rbio.3]=man3/SSL_get_rbio.pod +GENERATE[man/man3/SSL_get_rbio.3]=man3/SSL_get_rbio.pod +DEPEND[html/man3/SSL_get_session.html]=man3/SSL_get_session.pod +GENERATE[html/man3/SSL_get_session.html]=man3/SSL_get_session.pod +DEPEND[man/man3/SSL_get_session.3]=man3/SSL_get_session.pod +GENERATE[man/man3/SSL_get_session.3]=man3/SSL_get_session.pod +DEPEND[html/man3/SSL_get_shared_sigalgs.html]=man3/SSL_get_shared_sigalgs.pod +GENERATE[html/man3/SSL_get_shared_sigalgs.html]=man3/SSL_get_shared_sigalgs.pod +DEPEND[man/man3/SSL_get_shared_sigalgs.3]=man3/SSL_get_shared_sigalgs.pod +GENERATE[man/man3/SSL_get_shared_sigalgs.3]=man3/SSL_get_shared_sigalgs.pod +DEPEND[html/man3/SSL_get_verify_result.html]=man3/SSL_get_verify_result.pod +GENERATE[html/man3/SSL_get_verify_result.html]=man3/SSL_get_verify_result.pod +DEPEND[man/man3/SSL_get_verify_result.3]=man3/SSL_get_verify_result.pod +GENERATE[man/man3/SSL_get_verify_result.3]=man3/SSL_get_verify_result.pod +DEPEND[html/man3/SSL_get_version.html]=man3/SSL_get_version.pod +GENERATE[html/man3/SSL_get_version.html]=man3/SSL_get_version.pod +DEPEND[man/man3/SSL_get_version.3]=man3/SSL_get_version.pod +GENERATE[man/man3/SSL_get_version.3]=man3/SSL_get_version.pod +DEPEND[html/man3/SSL_group_to_name.html]=man3/SSL_group_to_name.pod +GENERATE[html/man3/SSL_group_to_name.html]=man3/SSL_group_to_name.pod +DEPEND[man/man3/SSL_group_to_name.3]=man3/SSL_group_to_name.pod +GENERATE[man/man3/SSL_group_to_name.3]=man3/SSL_group_to_name.pod +DEPEND[html/man3/SSL_in_init.html]=man3/SSL_in_init.pod +GENERATE[html/man3/SSL_in_init.html]=man3/SSL_in_init.pod +DEPEND[man/man3/SSL_in_init.3]=man3/SSL_in_init.pod +GENERATE[man/man3/SSL_in_init.3]=man3/SSL_in_init.pod +DEPEND[html/man3/SSL_key_update.html]=man3/SSL_key_update.pod +GENERATE[html/man3/SSL_key_update.html]=man3/SSL_key_update.pod +DEPEND[man/man3/SSL_key_update.3]=man3/SSL_key_update.pod +GENERATE[man/man3/SSL_key_update.3]=man3/SSL_key_update.pod +DEPEND[html/man3/SSL_library_init.html]=man3/SSL_library_init.pod +GENERATE[html/man3/SSL_library_init.html]=man3/SSL_library_init.pod +DEPEND[man/man3/SSL_library_init.3]=man3/SSL_library_init.pod +GENERATE[man/man3/SSL_library_init.3]=man3/SSL_library_init.pod +DEPEND[html/man3/SSL_load_client_CA_file.html]=man3/SSL_load_client_CA_file.pod +GENERATE[html/man3/SSL_load_client_CA_file.html]=man3/SSL_load_client_CA_file.pod +DEPEND[man/man3/SSL_load_client_CA_file.3]=man3/SSL_load_client_CA_file.pod +GENERATE[man/man3/SSL_load_client_CA_file.3]=man3/SSL_load_client_CA_file.pod +DEPEND[html/man3/SSL_new.html]=man3/SSL_new.pod +GENERATE[html/man3/SSL_new.html]=man3/SSL_new.pod +DEPEND[man/man3/SSL_new.3]=man3/SSL_new.pod +GENERATE[man/man3/SSL_new.3]=man3/SSL_new.pod +DEPEND[html/man3/SSL_pending.html]=man3/SSL_pending.pod +GENERATE[html/man3/SSL_pending.html]=man3/SSL_pending.pod +DEPEND[man/man3/SSL_pending.3]=man3/SSL_pending.pod +GENERATE[man/man3/SSL_pending.3]=man3/SSL_pending.pod +DEPEND[html/man3/SSL_read.html]=man3/SSL_read.pod +GENERATE[html/man3/SSL_read.html]=man3/SSL_read.pod +DEPEND[man/man3/SSL_read.3]=man3/SSL_read.pod +GENERATE[man/man3/SSL_read.3]=man3/SSL_read.pod +DEPEND[html/man3/SSL_read_early_data.html]=man3/SSL_read_early_data.pod +GENERATE[html/man3/SSL_read_early_data.html]=man3/SSL_read_early_data.pod +DEPEND[man/man3/SSL_read_early_data.3]=man3/SSL_read_early_data.pod +GENERATE[man/man3/SSL_read_early_data.3]=man3/SSL_read_early_data.pod +DEPEND[html/man3/SSL_rstate_string.html]=man3/SSL_rstate_string.pod +GENERATE[html/man3/SSL_rstate_string.html]=man3/SSL_rstate_string.pod +DEPEND[man/man3/SSL_rstate_string.3]=man3/SSL_rstate_string.pod +GENERATE[man/man3/SSL_rstate_string.3]=man3/SSL_rstate_string.pod +DEPEND[html/man3/SSL_session_reused.html]=man3/SSL_session_reused.pod +GENERATE[html/man3/SSL_session_reused.html]=man3/SSL_session_reused.pod +DEPEND[man/man3/SSL_session_reused.3]=man3/SSL_session_reused.pod +GENERATE[man/man3/SSL_session_reused.3]=man3/SSL_session_reused.pod +DEPEND[html/man3/SSL_set1_host.html]=man3/SSL_set1_host.pod +GENERATE[html/man3/SSL_set1_host.html]=man3/SSL_set1_host.pod +DEPEND[man/man3/SSL_set1_host.3]=man3/SSL_set1_host.pod +GENERATE[man/man3/SSL_set1_host.3]=man3/SSL_set1_host.pod +DEPEND[html/man3/SSL_set_async_callback.html]=man3/SSL_set_async_callback.pod +GENERATE[html/man3/SSL_set_async_callback.html]=man3/SSL_set_async_callback.pod +DEPEND[man/man3/SSL_set_async_callback.3]=man3/SSL_set_async_callback.pod +GENERATE[man/man3/SSL_set_async_callback.3]=man3/SSL_set_async_callback.pod +DEPEND[html/man3/SSL_set_bio.html]=man3/SSL_set_bio.pod +GENERATE[html/man3/SSL_set_bio.html]=man3/SSL_set_bio.pod +DEPEND[man/man3/SSL_set_bio.3]=man3/SSL_set_bio.pod +GENERATE[man/man3/SSL_set_bio.3]=man3/SSL_set_bio.pod +DEPEND[html/man3/SSL_set_connect_state.html]=man3/SSL_set_connect_state.pod +GENERATE[html/man3/SSL_set_connect_state.html]=man3/SSL_set_connect_state.pod +DEPEND[man/man3/SSL_set_connect_state.3]=man3/SSL_set_connect_state.pod +GENERATE[man/man3/SSL_set_connect_state.3]=man3/SSL_set_connect_state.pod +DEPEND[html/man3/SSL_set_fd.html]=man3/SSL_set_fd.pod +GENERATE[html/man3/SSL_set_fd.html]=man3/SSL_set_fd.pod +DEPEND[man/man3/SSL_set_fd.3]=man3/SSL_set_fd.pod +GENERATE[man/man3/SSL_set_fd.3]=man3/SSL_set_fd.pod +DEPEND[html/man3/SSL_set_retry_verify.html]=man3/SSL_set_retry_verify.pod +GENERATE[html/man3/SSL_set_retry_verify.html]=man3/SSL_set_retry_verify.pod +DEPEND[man/man3/SSL_set_retry_verify.3]=man3/SSL_set_retry_verify.pod +GENERATE[man/man3/SSL_set_retry_verify.3]=man3/SSL_set_retry_verify.pod +DEPEND[html/man3/SSL_set_session.html]=man3/SSL_set_session.pod +GENERATE[html/man3/SSL_set_session.html]=man3/SSL_set_session.pod +DEPEND[man/man3/SSL_set_session.3]=man3/SSL_set_session.pod +GENERATE[man/man3/SSL_set_session.3]=man3/SSL_set_session.pod +DEPEND[html/man3/SSL_set_shutdown.html]=man3/SSL_set_shutdown.pod +GENERATE[html/man3/SSL_set_shutdown.html]=man3/SSL_set_shutdown.pod +DEPEND[man/man3/SSL_set_shutdown.3]=man3/SSL_set_shutdown.pod +GENERATE[man/man3/SSL_set_shutdown.3]=man3/SSL_set_shutdown.pod +DEPEND[html/man3/SSL_set_verify_result.html]=man3/SSL_set_verify_result.pod +GENERATE[html/man3/SSL_set_verify_result.html]=man3/SSL_set_verify_result.pod +DEPEND[man/man3/SSL_set_verify_result.3]=man3/SSL_set_verify_result.pod +GENERATE[man/man3/SSL_set_verify_result.3]=man3/SSL_set_verify_result.pod +DEPEND[html/man3/SSL_shutdown.html]=man3/SSL_shutdown.pod +GENERATE[html/man3/SSL_shutdown.html]=man3/SSL_shutdown.pod +DEPEND[man/man3/SSL_shutdown.3]=man3/SSL_shutdown.pod +GENERATE[man/man3/SSL_shutdown.3]=man3/SSL_shutdown.pod +DEPEND[html/man3/SSL_state_string.html]=man3/SSL_state_string.pod +GENERATE[html/man3/SSL_state_string.html]=man3/SSL_state_string.pod +DEPEND[man/man3/SSL_state_string.3]=man3/SSL_state_string.pod +GENERATE[man/man3/SSL_state_string.3]=man3/SSL_state_string.pod +DEPEND[html/man3/SSL_want.html]=man3/SSL_want.pod +GENERATE[html/man3/SSL_want.html]=man3/SSL_want.pod +DEPEND[man/man3/SSL_want.3]=man3/SSL_want.pod +GENERATE[man/man3/SSL_want.3]=man3/SSL_want.pod +DEPEND[html/man3/SSL_write.html]=man3/SSL_write.pod +GENERATE[html/man3/SSL_write.html]=man3/SSL_write.pod +DEPEND[man/man3/SSL_write.3]=man3/SSL_write.pod +GENERATE[man/man3/SSL_write.3]=man3/SSL_write.pod +DEPEND[html/man3/TS_RESP_CTX_new.html]=man3/TS_RESP_CTX_new.pod +GENERATE[html/man3/TS_RESP_CTX_new.html]=man3/TS_RESP_CTX_new.pod +DEPEND[man/man3/TS_RESP_CTX_new.3]=man3/TS_RESP_CTX_new.pod +GENERATE[man/man3/TS_RESP_CTX_new.3]=man3/TS_RESP_CTX_new.pod +DEPEND[html/man3/TS_VERIFY_CTX_set_certs.html]=man3/TS_VERIFY_CTX_set_certs.pod +GENERATE[html/man3/TS_VERIFY_CTX_set_certs.html]=man3/TS_VERIFY_CTX_set_certs.pod +DEPEND[man/man3/TS_VERIFY_CTX_set_certs.3]=man3/TS_VERIFY_CTX_set_certs.pod +GENERATE[man/man3/TS_VERIFY_CTX_set_certs.3]=man3/TS_VERIFY_CTX_set_certs.pod +DEPEND[html/man3/UI_STRING.html]=man3/UI_STRING.pod +GENERATE[html/man3/UI_STRING.html]=man3/UI_STRING.pod +DEPEND[man/man3/UI_STRING.3]=man3/UI_STRING.pod +GENERATE[man/man3/UI_STRING.3]=man3/UI_STRING.pod +DEPEND[html/man3/UI_UTIL_read_pw.html]=man3/UI_UTIL_read_pw.pod +GENERATE[html/man3/UI_UTIL_read_pw.html]=man3/UI_UTIL_read_pw.pod +DEPEND[man/man3/UI_UTIL_read_pw.3]=man3/UI_UTIL_read_pw.pod +GENERATE[man/man3/UI_UTIL_read_pw.3]=man3/UI_UTIL_read_pw.pod +DEPEND[html/man3/UI_create_method.html]=man3/UI_create_method.pod +GENERATE[html/man3/UI_create_method.html]=man3/UI_create_method.pod +DEPEND[man/man3/UI_create_method.3]=man3/UI_create_method.pod +GENERATE[man/man3/UI_create_method.3]=man3/UI_create_method.pod +DEPEND[html/man3/UI_new.html]=man3/UI_new.pod +GENERATE[html/man3/UI_new.html]=man3/UI_new.pod +DEPEND[man/man3/UI_new.3]=man3/UI_new.pod +GENERATE[man/man3/UI_new.3]=man3/UI_new.pod +DEPEND[html/man3/X509V3_get_d2i.html]=man3/X509V3_get_d2i.pod +GENERATE[html/man3/X509V3_get_d2i.html]=man3/X509V3_get_d2i.pod +DEPEND[man/man3/X509V3_get_d2i.3]=man3/X509V3_get_d2i.pod +GENERATE[man/man3/X509V3_get_d2i.3]=man3/X509V3_get_d2i.pod +DEPEND[html/man3/X509V3_set_ctx.html]=man3/X509V3_set_ctx.pod +GENERATE[html/man3/X509V3_set_ctx.html]=man3/X509V3_set_ctx.pod +DEPEND[man/man3/X509V3_set_ctx.3]=man3/X509V3_set_ctx.pod +GENERATE[man/man3/X509V3_set_ctx.3]=man3/X509V3_set_ctx.pod +DEPEND[html/man3/X509_ALGOR_dup.html]=man3/X509_ALGOR_dup.pod +GENERATE[html/man3/X509_ALGOR_dup.html]=man3/X509_ALGOR_dup.pod +DEPEND[man/man3/X509_ALGOR_dup.3]=man3/X509_ALGOR_dup.pod +GENERATE[man/man3/X509_ALGOR_dup.3]=man3/X509_ALGOR_dup.pod +DEPEND[html/man3/X509_ATTRIBUTE.html]=man3/X509_ATTRIBUTE.pod +GENERATE[html/man3/X509_ATTRIBUTE.html]=man3/X509_ATTRIBUTE.pod +DEPEND[man/man3/X509_ATTRIBUTE.3]=man3/X509_ATTRIBUTE.pod +GENERATE[man/man3/X509_ATTRIBUTE.3]=man3/X509_ATTRIBUTE.pod +DEPEND[html/man3/X509_CRL_get0_by_serial.html]=man3/X509_CRL_get0_by_serial.pod +GENERATE[html/man3/X509_CRL_get0_by_serial.html]=man3/X509_CRL_get0_by_serial.pod +DEPEND[man/man3/X509_CRL_get0_by_serial.3]=man3/X509_CRL_get0_by_serial.pod +GENERATE[man/man3/X509_CRL_get0_by_serial.3]=man3/X509_CRL_get0_by_serial.pod +DEPEND[html/man3/X509_EXTENSION_set_object.html]=man3/X509_EXTENSION_set_object.pod +GENERATE[html/man3/X509_EXTENSION_set_object.html]=man3/X509_EXTENSION_set_object.pod +DEPEND[man/man3/X509_EXTENSION_set_object.3]=man3/X509_EXTENSION_set_object.pod +GENERATE[man/man3/X509_EXTENSION_set_object.3]=man3/X509_EXTENSION_set_object.pod +DEPEND[html/man3/X509_LOOKUP.html]=man3/X509_LOOKUP.pod +GENERATE[html/man3/X509_LOOKUP.html]=man3/X509_LOOKUP.pod +DEPEND[man/man3/X509_LOOKUP.3]=man3/X509_LOOKUP.pod +GENERATE[man/man3/X509_LOOKUP.3]=man3/X509_LOOKUP.pod +DEPEND[html/man3/X509_LOOKUP_hash_dir.html]=man3/X509_LOOKUP_hash_dir.pod +GENERATE[html/man3/X509_LOOKUP_hash_dir.html]=man3/X509_LOOKUP_hash_dir.pod +DEPEND[man/man3/X509_LOOKUP_hash_dir.3]=man3/X509_LOOKUP_hash_dir.pod +GENERATE[man/man3/X509_LOOKUP_hash_dir.3]=man3/X509_LOOKUP_hash_dir.pod +DEPEND[html/man3/X509_LOOKUP_meth_new.html]=man3/X509_LOOKUP_meth_new.pod +GENERATE[html/man3/X509_LOOKUP_meth_new.html]=man3/X509_LOOKUP_meth_new.pod +DEPEND[man/man3/X509_LOOKUP_meth_new.3]=man3/X509_LOOKUP_meth_new.pod +GENERATE[man/man3/X509_LOOKUP_meth_new.3]=man3/X509_LOOKUP_meth_new.pod +DEPEND[html/man3/X509_NAME_ENTRY_get_object.html]=man3/X509_NAME_ENTRY_get_object.pod +GENERATE[html/man3/X509_NAME_ENTRY_get_object.html]=man3/X509_NAME_ENTRY_get_object.pod +DEPEND[man/man3/X509_NAME_ENTRY_get_object.3]=man3/X509_NAME_ENTRY_get_object.pod +GENERATE[man/man3/X509_NAME_ENTRY_get_object.3]=man3/X509_NAME_ENTRY_get_object.pod +DEPEND[html/man3/X509_NAME_add_entry_by_txt.html]=man3/X509_NAME_add_entry_by_txt.pod +GENERATE[html/man3/X509_NAME_add_entry_by_txt.html]=man3/X509_NAME_add_entry_by_txt.pod +DEPEND[man/man3/X509_NAME_add_entry_by_txt.3]=man3/X509_NAME_add_entry_by_txt.pod +GENERATE[man/man3/X509_NAME_add_entry_by_txt.3]=man3/X509_NAME_add_entry_by_txt.pod +DEPEND[html/man3/X509_NAME_get0_der.html]=man3/X509_NAME_get0_der.pod +GENERATE[html/man3/X509_NAME_get0_der.html]=man3/X509_NAME_get0_der.pod +DEPEND[man/man3/X509_NAME_get0_der.3]=man3/X509_NAME_get0_der.pod +GENERATE[man/man3/X509_NAME_get0_der.3]=man3/X509_NAME_get0_der.pod +DEPEND[html/man3/X509_NAME_get_index_by_NID.html]=man3/X509_NAME_get_index_by_NID.pod +GENERATE[html/man3/X509_NAME_get_index_by_NID.html]=man3/X509_NAME_get_index_by_NID.pod +DEPEND[man/man3/X509_NAME_get_index_by_NID.3]=man3/X509_NAME_get_index_by_NID.pod +GENERATE[man/man3/X509_NAME_get_index_by_NID.3]=man3/X509_NAME_get_index_by_NID.pod +DEPEND[html/man3/X509_NAME_print_ex.html]=man3/X509_NAME_print_ex.pod +GENERATE[html/man3/X509_NAME_print_ex.html]=man3/X509_NAME_print_ex.pod +DEPEND[man/man3/X509_NAME_print_ex.3]=man3/X509_NAME_print_ex.pod +GENERATE[man/man3/X509_NAME_print_ex.3]=man3/X509_NAME_print_ex.pod +DEPEND[html/man3/X509_PUBKEY_new.html]=man3/X509_PUBKEY_new.pod +GENERATE[html/man3/X509_PUBKEY_new.html]=man3/X509_PUBKEY_new.pod +DEPEND[man/man3/X509_PUBKEY_new.3]=man3/X509_PUBKEY_new.pod +GENERATE[man/man3/X509_PUBKEY_new.3]=man3/X509_PUBKEY_new.pod +DEPEND[html/man3/X509_REQ_get_attr.html]=man3/X509_REQ_get_attr.pod +GENERATE[html/man3/X509_REQ_get_attr.html]=man3/X509_REQ_get_attr.pod +DEPEND[man/man3/X509_REQ_get_attr.3]=man3/X509_REQ_get_attr.pod +GENERATE[man/man3/X509_REQ_get_attr.3]=man3/X509_REQ_get_attr.pod +DEPEND[html/man3/X509_REQ_get_extensions.html]=man3/X509_REQ_get_extensions.pod +GENERATE[html/man3/X509_REQ_get_extensions.html]=man3/X509_REQ_get_extensions.pod +DEPEND[man/man3/X509_REQ_get_extensions.3]=man3/X509_REQ_get_extensions.pod +GENERATE[man/man3/X509_REQ_get_extensions.3]=man3/X509_REQ_get_extensions.pod +DEPEND[html/man3/X509_SIG_get0.html]=man3/X509_SIG_get0.pod +GENERATE[html/man3/X509_SIG_get0.html]=man3/X509_SIG_get0.pod +DEPEND[man/man3/X509_SIG_get0.3]=man3/X509_SIG_get0.pod +GENERATE[man/man3/X509_SIG_get0.3]=man3/X509_SIG_get0.pod +DEPEND[html/man3/X509_STORE_CTX_get_error.html]=man3/X509_STORE_CTX_get_error.pod +GENERATE[html/man3/X509_STORE_CTX_get_error.html]=man3/X509_STORE_CTX_get_error.pod +DEPEND[man/man3/X509_STORE_CTX_get_error.3]=man3/X509_STORE_CTX_get_error.pod +GENERATE[man/man3/X509_STORE_CTX_get_error.3]=man3/X509_STORE_CTX_get_error.pod +DEPEND[html/man3/X509_STORE_CTX_new.html]=man3/X509_STORE_CTX_new.pod +GENERATE[html/man3/X509_STORE_CTX_new.html]=man3/X509_STORE_CTX_new.pod +DEPEND[man/man3/X509_STORE_CTX_new.3]=man3/X509_STORE_CTX_new.pod +GENERATE[man/man3/X509_STORE_CTX_new.3]=man3/X509_STORE_CTX_new.pod +DEPEND[html/man3/X509_STORE_CTX_set_verify_cb.html]=man3/X509_STORE_CTX_set_verify_cb.pod +GENERATE[html/man3/X509_STORE_CTX_set_verify_cb.html]=man3/X509_STORE_CTX_set_verify_cb.pod +DEPEND[man/man3/X509_STORE_CTX_set_verify_cb.3]=man3/X509_STORE_CTX_set_verify_cb.pod +GENERATE[man/man3/X509_STORE_CTX_set_verify_cb.3]=man3/X509_STORE_CTX_set_verify_cb.pod +DEPEND[html/man3/X509_STORE_add_cert.html]=man3/X509_STORE_add_cert.pod +GENERATE[html/man3/X509_STORE_add_cert.html]=man3/X509_STORE_add_cert.pod +DEPEND[man/man3/X509_STORE_add_cert.3]=man3/X509_STORE_add_cert.pod +GENERATE[man/man3/X509_STORE_add_cert.3]=man3/X509_STORE_add_cert.pod +DEPEND[html/man3/X509_STORE_get0_param.html]=man3/X509_STORE_get0_param.pod +GENERATE[html/man3/X509_STORE_get0_param.html]=man3/X509_STORE_get0_param.pod +DEPEND[man/man3/X509_STORE_get0_param.3]=man3/X509_STORE_get0_param.pod +GENERATE[man/man3/X509_STORE_get0_param.3]=man3/X509_STORE_get0_param.pod +DEPEND[html/man3/X509_STORE_new.html]=man3/X509_STORE_new.pod +GENERATE[html/man3/X509_STORE_new.html]=man3/X509_STORE_new.pod +DEPEND[man/man3/X509_STORE_new.3]=man3/X509_STORE_new.pod +GENERATE[man/man3/X509_STORE_new.3]=man3/X509_STORE_new.pod +DEPEND[html/man3/X509_STORE_set_verify_cb_func.html]=man3/X509_STORE_set_verify_cb_func.pod +GENERATE[html/man3/X509_STORE_set_verify_cb_func.html]=man3/X509_STORE_set_verify_cb_func.pod +DEPEND[man/man3/X509_STORE_set_verify_cb_func.3]=man3/X509_STORE_set_verify_cb_func.pod +GENERATE[man/man3/X509_STORE_set_verify_cb_func.3]=man3/X509_STORE_set_verify_cb_func.pod +DEPEND[html/man3/X509_VERIFY_PARAM_set_flags.html]=man3/X509_VERIFY_PARAM_set_flags.pod +GENERATE[html/man3/X509_VERIFY_PARAM_set_flags.html]=man3/X509_VERIFY_PARAM_set_flags.pod +DEPEND[man/man3/X509_VERIFY_PARAM_set_flags.3]=man3/X509_VERIFY_PARAM_set_flags.pod +GENERATE[man/man3/X509_VERIFY_PARAM_set_flags.3]=man3/X509_VERIFY_PARAM_set_flags.pod +DEPEND[html/man3/X509_add_cert.html]=man3/X509_add_cert.pod +GENERATE[html/man3/X509_add_cert.html]=man3/X509_add_cert.pod +DEPEND[man/man3/X509_add_cert.3]=man3/X509_add_cert.pod +GENERATE[man/man3/X509_add_cert.3]=man3/X509_add_cert.pod +DEPEND[html/man3/X509_check_ca.html]=man3/X509_check_ca.pod +GENERATE[html/man3/X509_check_ca.html]=man3/X509_check_ca.pod +DEPEND[man/man3/X509_check_ca.3]=man3/X509_check_ca.pod +GENERATE[man/man3/X509_check_ca.3]=man3/X509_check_ca.pod +DEPEND[html/man3/X509_check_host.html]=man3/X509_check_host.pod +GENERATE[html/man3/X509_check_host.html]=man3/X509_check_host.pod +DEPEND[man/man3/X509_check_host.3]=man3/X509_check_host.pod +GENERATE[man/man3/X509_check_host.3]=man3/X509_check_host.pod +DEPEND[html/man3/X509_check_issued.html]=man3/X509_check_issued.pod +GENERATE[html/man3/X509_check_issued.html]=man3/X509_check_issued.pod +DEPEND[man/man3/X509_check_issued.3]=man3/X509_check_issued.pod +GENERATE[man/man3/X509_check_issued.3]=man3/X509_check_issued.pod +DEPEND[html/man3/X509_check_private_key.html]=man3/X509_check_private_key.pod +GENERATE[html/man3/X509_check_private_key.html]=man3/X509_check_private_key.pod +DEPEND[man/man3/X509_check_private_key.3]=man3/X509_check_private_key.pod +GENERATE[man/man3/X509_check_private_key.3]=man3/X509_check_private_key.pod +DEPEND[html/man3/X509_check_purpose.html]=man3/X509_check_purpose.pod +GENERATE[html/man3/X509_check_purpose.html]=man3/X509_check_purpose.pod +DEPEND[man/man3/X509_check_purpose.3]=man3/X509_check_purpose.pod +GENERATE[man/man3/X509_check_purpose.3]=man3/X509_check_purpose.pod +DEPEND[html/man3/X509_cmp.html]=man3/X509_cmp.pod +GENERATE[html/man3/X509_cmp.html]=man3/X509_cmp.pod +DEPEND[man/man3/X509_cmp.3]=man3/X509_cmp.pod +GENERATE[man/man3/X509_cmp.3]=man3/X509_cmp.pod +DEPEND[html/man3/X509_cmp_time.html]=man3/X509_cmp_time.pod +GENERATE[html/man3/X509_cmp_time.html]=man3/X509_cmp_time.pod +DEPEND[man/man3/X509_cmp_time.3]=man3/X509_cmp_time.pod +GENERATE[man/man3/X509_cmp_time.3]=man3/X509_cmp_time.pod +DEPEND[html/man3/X509_digest.html]=man3/X509_digest.pod +GENERATE[html/man3/X509_digest.html]=man3/X509_digest.pod +DEPEND[man/man3/X509_digest.3]=man3/X509_digest.pod +GENERATE[man/man3/X509_digest.3]=man3/X509_digest.pod +DEPEND[html/man3/X509_dup.html]=man3/X509_dup.pod +GENERATE[html/man3/X509_dup.html]=man3/X509_dup.pod +DEPEND[man/man3/X509_dup.3]=man3/X509_dup.pod +GENERATE[man/man3/X509_dup.3]=man3/X509_dup.pod +DEPEND[html/man3/X509_get0_distinguishing_id.html]=man3/X509_get0_distinguishing_id.pod +GENERATE[html/man3/X509_get0_distinguishing_id.html]=man3/X509_get0_distinguishing_id.pod +DEPEND[man/man3/X509_get0_distinguishing_id.3]=man3/X509_get0_distinguishing_id.pod +GENERATE[man/man3/X509_get0_distinguishing_id.3]=man3/X509_get0_distinguishing_id.pod +DEPEND[html/man3/X509_get0_notBefore.html]=man3/X509_get0_notBefore.pod +GENERATE[html/man3/X509_get0_notBefore.html]=man3/X509_get0_notBefore.pod +DEPEND[man/man3/X509_get0_notBefore.3]=man3/X509_get0_notBefore.pod +GENERATE[man/man3/X509_get0_notBefore.3]=man3/X509_get0_notBefore.pod +DEPEND[html/man3/X509_get0_signature.html]=man3/X509_get0_signature.pod +GENERATE[html/man3/X509_get0_signature.html]=man3/X509_get0_signature.pod +DEPEND[man/man3/X509_get0_signature.3]=man3/X509_get0_signature.pod +GENERATE[man/man3/X509_get0_signature.3]=man3/X509_get0_signature.pod +DEPEND[html/man3/X509_get0_uids.html]=man3/X509_get0_uids.pod +GENERATE[html/man3/X509_get0_uids.html]=man3/X509_get0_uids.pod +DEPEND[man/man3/X509_get0_uids.3]=man3/X509_get0_uids.pod +GENERATE[man/man3/X509_get0_uids.3]=man3/X509_get0_uids.pod +DEPEND[html/man3/X509_get_extension_flags.html]=man3/X509_get_extension_flags.pod +GENERATE[html/man3/X509_get_extension_flags.html]=man3/X509_get_extension_flags.pod +DEPEND[man/man3/X509_get_extension_flags.3]=man3/X509_get_extension_flags.pod +GENERATE[man/man3/X509_get_extension_flags.3]=man3/X509_get_extension_flags.pod +DEPEND[html/man3/X509_get_pubkey.html]=man3/X509_get_pubkey.pod +GENERATE[html/man3/X509_get_pubkey.html]=man3/X509_get_pubkey.pod +DEPEND[man/man3/X509_get_pubkey.3]=man3/X509_get_pubkey.pod +GENERATE[man/man3/X509_get_pubkey.3]=man3/X509_get_pubkey.pod +DEPEND[html/man3/X509_get_serialNumber.html]=man3/X509_get_serialNumber.pod +GENERATE[html/man3/X509_get_serialNumber.html]=man3/X509_get_serialNumber.pod +DEPEND[man/man3/X509_get_serialNumber.3]=man3/X509_get_serialNumber.pod +GENERATE[man/man3/X509_get_serialNumber.3]=man3/X509_get_serialNumber.pod +DEPEND[html/man3/X509_get_subject_name.html]=man3/X509_get_subject_name.pod +GENERATE[html/man3/X509_get_subject_name.html]=man3/X509_get_subject_name.pod +DEPEND[man/man3/X509_get_subject_name.3]=man3/X509_get_subject_name.pod +GENERATE[man/man3/X509_get_subject_name.3]=man3/X509_get_subject_name.pod +DEPEND[html/man3/X509_get_version.html]=man3/X509_get_version.pod +GENERATE[html/man3/X509_get_version.html]=man3/X509_get_version.pod +DEPEND[man/man3/X509_get_version.3]=man3/X509_get_version.pod +GENERATE[man/man3/X509_get_version.3]=man3/X509_get_version.pod +DEPEND[html/man3/X509_load_http.html]=man3/X509_load_http.pod +GENERATE[html/man3/X509_load_http.html]=man3/X509_load_http.pod +DEPEND[man/man3/X509_load_http.3]=man3/X509_load_http.pod +GENERATE[man/man3/X509_load_http.3]=man3/X509_load_http.pod +DEPEND[html/man3/X509_new.html]=man3/X509_new.pod +GENERATE[html/man3/X509_new.html]=man3/X509_new.pod +DEPEND[man/man3/X509_new.3]=man3/X509_new.pod +GENERATE[man/man3/X509_new.3]=man3/X509_new.pod +DEPEND[html/man3/X509_sign.html]=man3/X509_sign.pod +GENERATE[html/man3/X509_sign.html]=man3/X509_sign.pod +DEPEND[man/man3/X509_sign.3]=man3/X509_sign.pod +GENERATE[man/man3/X509_sign.3]=man3/X509_sign.pod +DEPEND[html/man3/X509_verify.html]=man3/X509_verify.pod +GENERATE[html/man3/X509_verify.html]=man3/X509_verify.pod +DEPEND[man/man3/X509_verify.3]=man3/X509_verify.pod +GENERATE[man/man3/X509_verify.3]=man3/X509_verify.pod +DEPEND[html/man3/X509_verify_cert.html]=man3/X509_verify_cert.pod +GENERATE[html/man3/X509_verify_cert.html]=man3/X509_verify_cert.pod +DEPEND[man/man3/X509_verify_cert.3]=man3/X509_verify_cert.pod +GENERATE[man/man3/X509_verify_cert.3]=man3/X509_verify_cert.pod +DEPEND[html/man3/X509v3_get_ext_by_NID.html]=man3/X509v3_get_ext_by_NID.pod +GENERATE[html/man3/X509v3_get_ext_by_NID.html]=man3/X509v3_get_ext_by_NID.pod +DEPEND[man/man3/X509v3_get_ext_by_NID.3]=man3/X509v3_get_ext_by_NID.pod +GENERATE[man/man3/X509v3_get_ext_by_NID.3]=man3/X509v3_get_ext_by_NID.pod +DEPEND[html/man3/b2i_PVK_bio_ex.html]=man3/b2i_PVK_bio_ex.pod +GENERATE[html/man3/b2i_PVK_bio_ex.html]=man3/b2i_PVK_bio_ex.pod +DEPEND[man/man3/b2i_PVK_bio_ex.3]=man3/b2i_PVK_bio_ex.pod +GENERATE[man/man3/b2i_PVK_bio_ex.3]=man3/b2i_PVK_bio_ex.pod +DEPEND[html/man3/d2i_PKCS8PrivateKey_bio.html]=man3/d2i_PKCS8PrivateKey_bio.pod +GENERATE[html/man3/d2i_PKCS8PrivateKey_bio.html]=man3/d2i_PKCS8PrivateKey_bio.pod +DEPEND[man/man3/d2i_PKCS8PrivateKey_bio.3]=man3/d2i_PKCS8PrivateKey_bio.pod +GENERATE[man/man3/d2i_PKCS8PrivateKey_bio.3]=man3/d2i_PKCS8PrivateKey_bio.pod +DEPEND[html/man3/d2i_PrivateKey.html]=man3/d2i_PrivateKey.pod +GENERATE[html/man3/d2i_PrivateKey.html]=man3/d2i_PrivateKey.pod +DEPEND[man/man3/d2i_PrivateKey.3]=man3/d2i_PrivateKey.pod +GENERATE[man/man3/d2i_PrivateKey.3]=man3/d2i_PrivateKey.pod +DEPEND[html/man3/d2i_RSAPrivateKey.html]=man3/d2i_RSAPrivateKey.pod +GENERATE[html/man3/d2i_RSAPrivateKey.html]=man3/d2i_RSAPrivateKey.pod +DEPEND[man/man3/d2i_RSAPrivateKey.3]=man3/d2i_RSAPrivateKey.pod +GENERATE[man/man3/d2i_RSAPrivateKey.3]=man3/d2i_RSAPrivateKey.pod +DEPEND[html/man3/d2i_SSL_SESSION.html]=man3/d2i_SSL_SESSION.pod +GENERATE[html/man3/d2i_SSL_SESSION.html]=man3/d2i_SSL_SESSION.pod +DEPEND[man/man3/d2i_SSL_SESSION.3]=man3/d2i_SSL_SESSION.pod +GENERATE[man/man3/d2i_SSL_SESSION.3]=man3/d2i_SSL_SESSION.pod +DEPEND[html/man3/d2i_X509.html]=man3/d2i_X509.pod +GENERATE[html/man3/d2i_X509.html]=man3/d2i_X509.pod +DEPEND[man/man3/d2i_X509.3]=man3/d2i_X509.pod +GENERATE[man/man3/d2i_X509.3]=man3/d2i_X509.pod +DEPEND[html/man3/i2d_CMS_bio_stream.html]=man3/i2d_CMS_bio_stream.pod +GENERATE[html/man3/i2d_CMS_bio_stream.html]=man3/i2d_CMS_bio_stream.pod +DEPEND[man/man3/i2d_CMS_bio_stream.3]=man3/i2d_CMS_bio_stream.pod +GENERATE[man/man3/i2d_CMS_bio_stream.3]=man3/i2d_CMS_bio_stream.pod +DEPEND[html/man3/i2d_PKCS7_bio_stream.html]=man3/i2d_PKCS7_bio_stream.pod +GENERATE[html/man3/i2d_PKCS7_bio_stream.html]=man3/i2d_PKCS7_bio_stream.pod +DEPEND[man/man3/i2d_PKCS7_bio_stream.3]=man3/i2d_PKCS7_bio_stream.pod +GENERATE[man/man3/i2d_PKCS7_bio_stream.3]=man3/i2d_PKCS7_bio_stream.pod +DEPEND[html/man3/i2d_re_X509_tbs.html]=man3/i2d_re_X509_tbs.pod +GENERATE[html/man3/i2d_re_X509_tbs.html]=man3/i2d_re_X509_tbs.pod +DEPEND[man/man3/i2d_re_X509_tbs.3]=man3/i2d_re_X509_tbs.pod +GENERATE[man/man3/i2d_re_X509_tbs.3]=man3/i2d_re_X509_tbs.pod +DEPEND[html/man3/o2i_SCT_LIST.html]=man3/o2i_SCT_LIST.pod +GENERATE[html/man3/o2i_SCT_LIST.html]=man3/o2i_SCT_LIST.pod +DEPEND[man/man3/o2i_SCT_LIST.3]=man3/o2i_SCT_LIST.pod +GENERATE[man/man3/o2i_SCT_LIST.3]=man3/o2i_SCT_LIST.pod +DEPEND[html/man3/s2i_ASN1_IA5STRING.html]=man3/s2i_ASN1_IA5STRING.pod +GENERATE[html/man3/s2i_ASN1_IA5STRING.html]=man3/s2i_ASN1_IA5STRING.pod +DEPEND[man/man3/s2i_ASN1_IA5STRING.3]=man3/s2i_ASN1_IA5STRING.pod +GENERATE[man/man3/s2i_ASN1_IA5STRING.3]=man3/s2i_ASN1_IA5STRING.pod +IMAGEDOCS[man3]= +HTMLDOCS[man3]=html/man3/ADMISSIONS.html \ +html/man3/ASN1_EXTERN_FUNCS.html \ +html/man3/ASN1_INTEGER_get_int64.html \ +html/man3/ASN1_INTEGER_new.html \ +html/man3/ASN1_ITEM_lookup.html \ +html/man3/ASN1_OBJECT_new.html \ +html/man3/ASN1_STRING_TABLE_add.html \ +html/man3/ASN1_STRING_length.html \ +html/man3/ASN1_STRING_new.html \ +html/man3/ASN1_STRING_print_ex.html \ +html/man3/ASN1_TIME_set.html \ +html/man3/ASN1_TYPE_get.html \ +html/man3/ASN1_aux_cb.html \ +html/man3/ASN1_generate_nconf.html \ +html/man3/ASN1_item_d2i_bio.html \ +html/man3/ASN1_item_new.html \ +html/man3/ASN1_item_sign.html \ +html/man3/ASYNC_WAIT_CTX_new.html \ +html/man3/ASYNC_start_job.html \ +html/man3/BF_encrypt.html \ +html/man3/BIO_ADDR.html \ +html/man3/BIO_ADDRINFO.html \ +html/man3/BIO_connect.html \ +html/man3/BIO_ctrl.html \ +html/man3/BIO_f_base64.html \ +html/man3/BIO_f_buffer.html \ +html/man3/BIO_f_cipher.html \ +html/man3/BIO_f_md.html \ +html/man3/BIO_f_null.html \ +html/man3/BIO_f_prefix.html \ +html/man3/BIO_f_readbuffer.html \ +html/man3/BIO_f_ssl.html \ +html/man3/BIO_find_type.html \ +html/man3/BIO_get_data.html \ +html/man3/BIO_get_ex_new_index.html \ +html/man3/BIO_meth_new.html \ +html/man3/BIO_new.html \ +html/man3/BIO_new_CMS.html \ +html/man3/BIO_parse_hostserv.html \ +html/man3/BIO_printf.html \ +html/man3/BIO_push.html \ +html/man3/BIO_read.html \ +html/man3/BIO_s_accept.html \ +html/man3/BIO_s_bio.html \ +html/man3/BIO_s_connect.html \ +html/man3/BIO_s_core.html \ +html/man3/BIO_s_datagram.html \ +html/man3/BIO_s_fd.html \ +html/man3/BIO_s_file.html \ +html/man3/BIO_s_mem.html \ +html/man3/BIO_s_null.html \ +html/man3/BIO_s_socket.html \ +html/man3/BIO_set_callback.html \ +html/man3/BIO_should_retry.html \ +html/man3/BIO_socket_wait.html \ +html/man3/BN_BLINDING_new.html \ +html/man3/BN_CTX_new.html \ +html/man3/BN_CTX_start.html \ +html/man3/BN_add.html \ +html/man3/BN_add_word.html \ +html/man3/BN_bn2bin.html \ +html/man3/BN_cmp.html \ +html/man3/BN_copy.html \ +html/man3/BN_generate_prime.html \ +html/man3/BN_mod_exp_mont.html \ +html/man3/BN_mod_inverse.html \ +html/man3/BN_mod_mul_montgomery.html \ +html/man3/BN_mod_mul_reciprocal.html \ +html/man3/BN_new.html \ +html/man3/BN_num_bytes.html \ +html/man3/BN_rand.html \ +html/man3/BN_security_bits.html \ +html/man3/BN_set_bit.html \ +html/man3/BN_swap.html \ +html/man3/BN_zero.html \ +html/man3/BUF_MEM_new.html \ +html/man3/CMS_EncryptedData_decrypt.html \ +html/man3/CMS_EncryptedData_encrypt.html \ +html/man3/CMS_EnvelopedData_create.html \ +html/man3/CMS_add0_cert.html \ +html/man3/CMS_add1_recipient_cert.html \ +html/man3/CMS_add1_signer.html \ +html/man3/CMS_compress.html \ +html/man3/CMS_data_create.html \ +html/man3/CMS_decrypt.html \ +html/man3/CMS_digest_create.html \ +html/man3/CMS_encrypt.html \ +html/man3/CMS_final.html \ +html/man3/CMS_get0_RecipientInfos.html \ +html/man3/CMS_get0_SignerInfos.html \ +html/man3/CMS_get0_type.html \ +html/man3/CMS_get1_ReceiptRequest.html \ +html/man3/CMS_sign.html \ +html/man3/CMS_sign_receipt.html \ +html/man3/CMS_signed_get_attr.html \ +html/man3/CMS_uncompress.html \ +html/man3/CMS_verify.html \ +html/man3/CMS_verify_receipt.html \ +html/man3/CONF_modules_free.html \ +html/man3/CONF_modules_load_file.html \ +html/man3/CRYPTO_THREAD_run_once.html \ +html/man3/CRYPTO_get_ex_new_index.html \ +html/man3/CRYPTO_memcmp.html \ +html/man3/CTLOG_STORE_get0_log_by_id.html \ +html/man3/CTLOG_STORE_new.html \ +html/man3/CTLOG_new.html \ +html/man3/CT_POLICY_EVAL_CTX_new.html \ +html/man3/DEFINE_STACK_OF.html \ +html/man3/DES_random_key.html \ +html/man3/DH_generate_key.html \ +html/man3/DH_generate_parameters.html \ +html/man3/DH_get0_pqg.html \ +html/man3/DH_get_1024_160.html \ +html/man3/DH_meth_new.html \ +html/man3/DH_new.html \ +html/man3/DH_new_by_nid.html \ +html/man3/DH_set_method.html \ +html/man3/DH_size.html \ +html/man3/DSA_SIG_new.html \ +html/man3/DSA_do_sign.html \ +html/man3/DSA_dup_DH.html \ +html/man3/DSA_generate_key.html \ +html/man3/DSA_generate_parameters.html \ +html/man3/DSA_get0_pqg.html \ +html/man3/DSA_meth_new.html \ +html/man3/DSA_new.html \ +html/man3/DSA_set_method.html \ +html/man3/DSA_sign.html \ +html/man3/DSA_size.html \ +html/man3/DTLS_get_data_mtu.html \ +html/man3/DTLS_set_timer_cb.html \ +html/man3/DTLSv1_listen.html \ +html/man3/ECDSA_SIG_new.html \ +html/man3/ECDSA_sign.html \ +html/man3/ECPKParameters_print.html \ +html/man3/EC_GFp_simple_method.html \ +html/man3/EC_GROUP_copy.html \ +html/man3/EC_GROUP_new.html \ +html/man3/EC_KEY_get_enc_flags.html \ +html/man3/EC_KEY_new.html \ +html/man3/EC_POINT_add.html \ +html/man3/EC_POINT_new.html \ +html/man3/ENGINE_add.html \ +html/man3/ERR_GET_LIB.html \ +html/man3/ERR_clear_error.html \ +html/man3/ERR_error_string.html \ +html/man3/ERR_get_error.html \ +html/man3/ERR_load_crypto_strings.html \ +html/man3/ERR_load_strings.html \ +html/man3/ERR_new.html \ +html/man3/ERR_print_errors.html \ +html/man3/ERR_put_error.html \ +html/man3/ERR_remove_state.html \ +html/man3/ERR_set_mark.html \ +html/man3/EVP_ASYM_CIPHER_free.html \ +html/man3/EVP_BytesToKey.html \ +html/man3/EVP_CIPHER_CTX_get_cipher_data.html \ +html/man3/EVP_CIPHER_CTX_get_original_iv.html \ +html/man3/EVP_CIPHER_meth_new.html \ +html/man3/EVP_DigestInit.html \ +html/man3/EVP_DigestSignInit.html \ +html/man3/EVP_DigestVerifyInit.html \ +html/man3/EVP_EncodeInit.html \ +html/man3/EVP_EncryptInit.html \ +html/man3/EVP_KDF.html \ +html/man3/EVP_KEM_free.html \ +html/man3/EVP_KEYEXCH_free.html \ +html/man3/EVP_KEYMGMT.html \ +html/man3/EVP_MAC.html \ +html/man3/EVP_MD_meth_new.html \ +html/man3/EVP_OpenInit.html \ +html/man3/EVP_PBE_CipherInit.html \ +html/man3/EVP_PKEY2PKCS8.html \ +html/man3/EVP_PKEY_ASN1_METHOD.html \ +html/man3/EVP_PKEY_CTX_ctrl.html \ +html/man3/EVP_PKEY_CTX_get0_libctx.html \ +html/man3/EVP_PKEY_CTX_get0_pkey.html \ +html/man3/EVP_PKEY_CTX_new.html \ +html/man3/EVP_PKEY_CTX_set1_pbe_pass.html \ +html/man3/EVP_PKEY_CTX_set_hkdf_md.html \ +html/man3/EVP_PKEY_CTX_set_params.html \ +html/man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.html \ +html/man3/EVP_PKEY_CTX_set_scrypt_N.html \ +html/man3/EVP_PKEY_CTX_set_tls1_prf_md.html \ +html/man3/EVP_PKEY_asn1_get_count.html \ +html/man3/EVP_PKEY_check.html \ +html/man3/EVP_PKEY_copy_parameters.html \ +html/man3/EVP_PKEY_decapsulate.html \ +html/man3/EVP_PKEY_decrypt.html \ +html/man3/EVP_PKEY_derive.html \ +html/man3/EVP_PKEY_digestsign_supports_digest.html \ +html/man3/EVP_PKEY_encapsulate.html \ +html/man3/EVP_PKEY_encrypt.html \ +html/man3/EVP_PKEY_fromdata.html \ +html/man3/EVP_PKEY_get_attr.html \ +html/man3/EVP_PKEY_get_default_digest_nid.html \ +html/man3/EVP_PKEY_get_field_type.html \ +html/man3/EVP_PKEY_get_group_name.html \ +html/man3/EVP_PKEY_get_size.html \ +html/man3/EVP_PKEY_gettable_params.html \ +html/man3/EVP_PKEY_is_a.html \ +html/man3/EVP_PKEY_keygen.html \ +html/man3/EVP_PKEY_meth_get_count.html \ +html/man3/EVP_PKEY_meth_new.html \ +html/man3/EVP_PKEY_new.html \ +html/man3/EVP_PKEY_print_private.html \ +html/man3/EVP_PKEY_set1_RSA.html \ +html/man3/EVP_PKEY_set1_encoded_public_key.html \ +html/man3/EVP_PKEY_set_type.html \ +html/man3/EVP_PKEY_settable_params.html \ +html/man3/EVP_PKEY_sign.html \ +html/man3/EVP_PKEY_todata.html \ +html/man3/EVP_PKEY_verify.html \ +html/man3/EVP_PKEY_verify_recover.html \ +html/man3/EVP_RAND.html \ +html/man3/EVP_SIGNATURE.html \ +html/man3/EVP_SealInit.html \ +html/man3/EVP_SignInit.html \ +html/man3/EVP_VerifyInit.html \ +html/man3/EVP_aes_128_gcm.html \ +html/man3/EVP_aria_128_gcm.html \ +html/man3/EVP_bf_cbc.html \ +html/man3/EVP_blake2b512.html \ +html/man3/EVP_camellia_128_ecb.html \ +html/man3/EVP_cast5_cbc.html \ +html/man3/EVP_chacha20.html \ +html/man3/EVP_des_cbc.html \ +html/man3/EVP_desx_cbc.html \ +html/man3/EVP_idea_cbc.html \ +html/man3/EVP_md2.html \ +html/man3/EVP_md4.html \ +html/man3/EVP_md5.html \ +html/man3/EVP_mdc2.html \ +html/man3/EVP_rc2_cbc.html \ +html/man3/EVP_rc4.html \ +html/man3/EVP_rc5_32_12_16_cbc.html \ +html/man3/EVP_ripemd160.html \ +html/man3/EVP_seed_cbc.html \ +html/man3/EVP_set_default_properties.html \ +html/man3/EVP_sha1.html \ +html/man3/EVP_sha224.html \ +html/man3/EVP_sha3_224.html \ +html/man3/EVP_sm3.html \ +html/man3/EVP_sm4_cbc.html \ +html/man3/EVP_whirlpool.html \ +html/man3/HMAC.html \ +html/man3/MD5.html \ +html/man3/MDC2_Init.html \ +html/man3/NCONF_new_ex.html \ +html/man3/OBJ_nid2obj.html \ +html/man3/OCSP_REQUEST_new.html \ +html/man3/OCSP_cert_to_id.html \ +html/man3/OCSP_request_add1_nonce.html \ +html/man3/OCSP_resp_find_status.html \ +html/man3/OCSP_response_status.html \ +html/man3/OCSP_sendreq_new.html \ +html/man3/OPENSSL_Applink.html \ +html/man3/OPENSSL_FILE.html \ +html/man3/OPENSSL_LH_COMPFUNC.html \ +html/man3/OPENSSL_LH_stats.html \ +html/man3/OPENSSL_config.html \ +html/man3/OPENSSL_fork_prepare.html \ +html/man3/OPENSSL_gmtime.html \ +html/man3/OPENSSL_hexchar2int.html \ +html/man3/OPENSSL_ia32cap.html \ +html/man3/OPENSSL_init_crypto.html \ +html/man3/OPENSSL_init_ssl.html \ +html/man3/OPENSSL_instrument_bus.html \ +html/man3/OPENSSL_load_builtin_modules.html \ +html/man3/OPENSSL_malloc.html \ +html/man3/OPENSSL_s390xcap.html \ +html/man3/OPENSSL_secure_malloc.html \ +html/man3/OPENSSL_strcasecmp.html \ +html/man3/OSSL_ALGORITHM.html \ +html/man3/OSSL_CALLBACK.html \ +html/man3/OSSL_CMP_CTX_new.html \ +html/man3/OSSL_CMP_HDR_get0_transactionID.html \ +html/man3/OSSL_CMP_ITAV_set0.html \ +html/man3/OSSL_CMP_MSG_get0_header.html \ +html/man3/OSSL_CMP_MSG_http_perform.html \ +html/man3/OSSL_CMP_SRV_CTX_new.html \ +html/man3/OSSL_CMP_STATUSINFO_new.html \ +html/man3/OSSL_CMP_exec_certreq.html \ +html/man3/OSSL_CMP_log_open.html \ +html/man3/OSSL_CMP_validate_msg.html \ +html/man3/OSSL_CORE_MAKE_FUNC.html \ +html/man3/OSSL_CRMF_MSG_get0_tmpl.html \ +html/man3/OSSL_CRMF_MSG_set0_validity.html \ +html/man3/OSSL_CRMF_MSG_set1_regCtrl_regToken.html \ +html/man3/OSSL_CRMF_MSG_set1_regInfo_certReq.html \ +html/man3/OSSL_CRMF_pbmp_new.html \ +html/man3/OSSL_DECODER.html \ +html/man3/OSSL_DECODER_CTX.html \ +html/man3/OSSL_DECODER_CTX_new_for_pkey.html \ +html/man3/OSSL_DECODER_from_bio.html \ +html/man3/OSSL_DISPATCH.html \ +html/man3/OSSL_ENCODER.html \ +html/man3/OSSL_ENCODER_CTX.html \ +html/man3/OSSL_ENCODER_CTX_new_for_pkey.html \ +html/man3/OSSL_ENCODER_to_bio.html \ +html/man3/OSSL_ESS_check_signing_certs.html \ +html/man3/OSSL_HTTP_REQ_CTX.html \ +html/man3/OSSL_HTTP_parse_url.html \ +html/man3/OSSL_HTTP_transfer.html \ +html/man3/OSSL_ITEM.html \ +html/man3/OSSL_LIB_CTX.html \ +html/man3/OSSL_PARAM.html \ +html/man3/OSSL_PARAM_BLD.html \ +html/man3/OSSL_PARAM_allocate_from_text.html \ +html/man3/OSSL_PARAM_dup.html \ +html/man3/OSSL_PARAM_int.html \ +html/man3/OSSL_PROVIDER.html \ +html/man3/OSSL_SELF_TEST_new.html \ +html/man3/OSSL_SELF_TEST_set_callback.html \ +html/man3/OSSL_STORE_INFO.html \ +html/man3/OSSL_STORE_LOADER.html \ +html/man3/OSSL_STORE_SEARCH.html \ +html/man3/OSSL_STORE_attach.html \ +html/man3/OSSL_STORE_expect.html \ +html/man3/OSSL_STORE_open.html \ +html/man3/OSSL_trace_enabled.html \ +html/man3/OSSL_trace_get_category_num.html \ +html/man3/OSSL_trace_set_channel.html \ +html/man3/OpenSSL_add_all_algorithms.html \ +html/man3/OpenSSL_version.html \ +html/man3/PEM_X509_INFO_read_bio_ex.html \ +html/man3/PEM_bytes_read_bio.html \ +html/man3/PEM_read.html \ +html/man3/PEM_read_CMS.html \ +html/man3/PEM_read_bio_PrivateKey.html \ +html/man3/PEM_read_bio_ex.html \ +html/man3/PEM_write_bio_CMS_stream.html \ +html/man3/PEM_write_bio_PKCS7_stream.html \ +html/man3/PKCS12_PBE_keyivgen.html \ +html/man3/PKCS12_SAFEBAG_create_cert.html \ +html/man3/PKCS12_SAFEBAG_get0_attrs.html \ +html/man3/PKCS12_SAFEBAG_get1_cert.html \ +html/man3/PKCS12_add1_attr_by_NID.html \ +html/man3/PKCS12_add_CSPName_asc.html \ +html/man3/PKCS12_add_cert.html \ +html/man3/PKCS12_add_friendlyname_asc.html \ +html/man3/PKCS12_add_localkeyid.html \ +html/man3/PKCS12_add_safe.html \ +html/man3/PKCS12_create.html \ +html/man3/PKCS12_decrypt_skey.html \ +html/man3/PKCS12_gen_mac.html \ +html/man3/PKCS12_get_friendlyname.html \ +html/man3/PKCS12_init.html \ +html/man3/PKCS12_item_decrypt_d2i.html \ +html/man3/PKCS12_key_gen_utf8_ex.html \ +html/man3/PKCS12_newpass.html \ +html/man3/PKCS12_pack_p7encdata.html \ +html/man3/PKCS12_parse.html \ +html/man3/PKCS5_PBE_keyivgen.html \ +html/man3/PKCS5_PBKDF2_HMAC.html \ +html/man3/PKCS7_decrypt.html \ +html/man3/PKCS7_encrypt.html \ +html/man3/PKCS7_get_octet_string.html \ +html/man3/PKCS7_sign.html \ +html/man3/PKCS7_sign_add_signer.html \ +html/man3/PKCS7_type_is_other.html \ +html/man3/PKCS7_verify.html \ +html/man3/PKCS8_encrypt.html \ +html/man3/PKCS8_pkey_add1_attr.html \ +html/man3/RAND_add.html \ +html/man3/RAND_bytes.html \ +html/man3/RAND_cleanup.html \ +html/man3/RAND_egd.html \ +html/man3/RAND_get0_primary.html \ +html/man3/RAND_load_file.html \ +html/man3/RAND_set_DRBG_type.html \ +html/man3/RAND_set_rand_method.html \ +html/man3/RC4_set_key.html \ +html/man3/RIPEMD160_Init.html \ +html/man3/RSA_blinding_on.html \ +html/man3/RSA_check_key.html \ +html/man3/RSA_generate_key.html \ +html/man3/RSA_get0_key.html \ +html/man3/RSA_meth_new.html \ +html/man3/RSA_new.html \ +html/man3/RSA_padding_add_PKCS1_type_1.html \ +html/man3/RSA_print.html \ +html/man3/RSA_private_encrypt.html \ +html/man3/RSA_public_encrypt.html \ +html/man3/RSA_set_method.html \ +html/man3/RSA_sign.html \ +html/man3/RSA_sign_ASN1_OCTET_STRING.html \ +html/man3/RSA_size.html \ +html/man3/SCT_new.html \ +html/man3/SCT_print.html \ +html/man3/SCT_validate.html \ +html/man3/SHA256_Init.html \ +html/man3/SMIME_read_ASN1.html \ +html/man3/SMIME_read_CMS.html \ +html/man3/SMIME_read_PKCS7.html \ +html/man3/SMIME_write_ASN1.html \ +html/man3/SMIME_write_CMS.html \ +html/man3/SMIME_write_PKCS7.html \ +html/man3/SRP_Calc_B.html \ +html/man3/SRP_VBASE_new.html \ +html/man3/SRP_create_verifier.html \ +html/man3/SRP_user_pwd_new.html \ +html/man3/SSL_CIPHER_get_name.html \ +html/man3/SSL_COMP_add_compression_method.html \ +html/man3/SSL_CONF_CTX_new.html \ +html/man3/SSL_CONF_CTX_set1_prefix.html \ +html/man3/SSL_CONF_CTX_set_flags.html \ +html/man3/SSL_CONF_CTX_set_ssl_ctx.html \ +html/man3/SSL_CONF_cmd.html \ +html/man3/SSL_CONF_cmd_argv.html \ +html/man3/SSL_CTX_add1_chain_cert.html \ +html/man3/SSL_CTX_add_extra_chain_cert.html \ +html/man3/SSL_CTX_add_session.html \ +html/man3/SSL_CTX_config.html \ +html/man3/SSL_CTX_ctrl.html \ +html/man3/SSL_CTX_dane_enable.html \ +html/man3/SSL_CTX_flush_sessions.html \ +html/man3/SSL_CTX_free.html \ +html/man3/SSL_CTX_get0_param.html \ +html/man3/SSL_CTX_get_verify_mode.html \ +html/man3/SSL_CTX_has_client_custom_ext.html \ +html/man3/SSL_CTX_load_verify_locations.html \ +html/man3/SSL_CTX_new.html \ +html/man3/SSL_CTX_sess_number.html \ +html/man3/SSL_CTX_sess_set_cache_size.html \ +html/man3/SSL_CTX_sess_set_get_cb.html \ +html/man3/SSL_CTX_sessions.html \ +html/man3/SSL_CTX_set0_CA_list.html \ +html/man3/SSL_CTX_set1_curves.html \ +html/man3/SSL_CTX_set1_sigalgs.html \ +html/man3/SSL_CTX_set1_verify_cert_store.html \ +html/man3/SSL_CTX_set_alpn_select_cb.html \ +html/man3/SSL_CTX_set_cert_cb.html \ +html/man3/SSL_CTX_set_cert_store.html \ +html/man3/SSL_CTX_set_cert_verify_callback.html \ +html/man3/SSL_CTX_set_cipher_list.html \ +html/man3/SSL_CTX_set_client_cert_cb.html \ +html/man3/SSL_CTX_set_client_hello_cb.html \ +html/man3/SSL_CTX_set_ct_validation_callback.html \ +html/man3/SSL_CTX_set_ctlog_list_file.html \ +html/man3/SSL_CTX_set_default_passwd_cb.html \ +html/man3/SSL_CTX_set_generate_session_id.html \ +html/man3/SSL_CTX_set_info_callback.html \ +html/man3/SSL_CTX_set_keylog_callback.html \ +html/man3/SSL_CTX_set_max_cert_list.html \ +html/man3/SSL_CTX_set_min_proto_version.html \ +html/man3/SSL_CTX_set_mode.html \ +html/man3/SSL_CTX_set_msg_callback.html \ +html/man3/SSL_CTX_set_num_tickets.html \ +html/man3/SSL_CTX_set_options.html \ +html/man3/SSL_CTX_set_psk_client_callback.html \ +html/man3/SSL_CTX_set_quiet_shutdown.html \ +html/man3/SSL_CTX_set_read_ahead.html \ +html/man3/SSL_CTX_set_record_padding_callback.html \ +html/man3/SSL_CTX_set_security_level.html \ +html/man3/SSL_CTX_set_session_cache_mode.html \ +html/man3/SSL_CTX_set_session_id_context.html \ +html/man3/SSL_CTX_set_session_ticket_cb.html \ +html/man3/SSL_CTX_set_split_send_fragment.html \ +html/man3/SSL_CTX_set_srp_password.html \ +html/man3/SSL_CTX_set_ssl_version.html \ +html/man3/SSL_CTX_set_stateless_cookie_generate_cb.html \ +html/man3/SSL_CTX_set_timeout.html \ +html/man3/SSL_CTX_set_tlsext_servername_callback.html \ +html/man3/SSL_CTX_set_tlsext_status_cb.html \ +html/man3/SSL_CTX_set_tlsext_ticket_key_cb.html \ +html/man3/SSL_CTX_set_tlsext_use_srtp.html \ +html/man3/SSL_CTX_set_tmp_dh_callback.html \ +html/man3/SSL_CTX_set_tmp_ecdh.html \ +html/man3/SSL_CTX_set_verify.html \ +html/man3/SSL_CTX_use_certificate.html \ +html/man3/SSL_CTX_use_psk_identity_hint.html \ +html/man3/SSL_CTX_use_serverinfo.html \ +html/man3/SSL_SESSION_free.html \ +html/man3/SSL_SESSION_get0_cipher.html \ +html/man3/SSL_SESSION_get0_hostname.html \ +html/man3/SSL_SESSION_get0_id_context.html \ +html/man3/SSL_SESSION_get0_peer.html \ +html/man3/SSL_SESSION_get_compress_id.html \ +html/man3/SSL_SESSION_get_protocol_version.html \ +html/man3/SSL_SESSION_get_time.html \ +html/man3/SSL_SESSION_has_ticket.html \ +html/man3/SSL_SESSION_is_resumable.html \ +html/man3/SSL_SESSION_print.html \ +html/man3/SSL_SESSION_set1_id.html \ +html/man3/SSL_accept.html \ +html/man3/SSL_alert_type_string.html \ +html/man3/SSL_alloc_buffers.html \ +html/man3/SSL_check_chain.html \ +html/man3/SSL_clear.html \ +html/man3/SSL_connect.html \ +html/man3/SSL_do_handshake.html \ +html/man3/SSL_export_keying_material.html \ +html/man3/SSL_extension_supported.html \ +html/man3/SSL_free.html \ +html/man3/SSL_get0_peer_scts.html \ +html/man3/SSL_get_SSL_CTX.html \ +html/man3/SSL_get_all_async_fds.html \ +html/man3/SSL_get_certificate.html \ +html/man3/SSL_get_ciphers.html \ +html/man3/SSL_get_client_random.html \ +html/man3/SSL_get_current_cipher.html \ +html/man3/SSL_get_default_timeout.html \ +html/man3/SSL_get_error.html \ +html/man3/SSL_get_extms_support.html \ +html/man3/SSL_get_fd.html \ +html/man3/SSL_get_peer_cert_chain.html \ +html/man3/SSL_get_peer_certificate.html \ +html/man3/SSL_get_peer_signature_nid.html \ +html/man3/SSL_get_peer_tmp_key.html \ +html/man3/SSL_get_psk_identity.html \ +html/man3/SSL_get_rbio.html \ +html/man3/SSL_get_session.html \ +html/man3/SSL_get_shared_sigalgs.html \ +html/man3/SSL_get_verify_result.html \ +html/man3/SSL_get_version.html \ +html/man3/SSL_group_to_name.html \ +html/man3/SSL_in_init.html \ +html/man3/SSL_key_update.html \ +html/man3/SSL_library_init.html \ +html/man3/SSL_load_client_CA_file.html \ +html/man3/SSL_new.html \ +html/man3/SSL_pending.html \ +html/man3/SSL_read.html \ +html/man3/SSL_read_early_data.html \ +html/man3/SSL_rstate_string.html \ +html/man3/SSL_session_reused.html \ +html/man3/SSL_set1_host.html \ +html/man3/SSL_set_async_callback.html \ +html/man3/SSL_set_bio.html \ +html/man3/SSL_set_connect_state.html \ +html/man3/SSL_set_fd.html \ +html/man3/SSL_set_retry_verify.html \ +html/man3/SSL_set_session.html \ +html/man3/SSL_set_shutdown.html \ +html/man3/SSL_set_verify_result.html \ +html/man3/SSL_shutdown.html \ +html/man3/SSL_state_string.html \ +html/man3/SSL_want.html \ +html/man3/SSL_write.html \ +html/man3/TS_RESP_CTX_new.html \ +html/man3/TS_VERIFY_CTX_set_certs.html \ +html/man3/UI_STRING.html \ +html/man3/UI_UTIL_read_pw.html \ +html/man3/UI_create_method.html \ +html/man3/UI_new.html \ +html/man3/X509V3_get_d2i.html \ +html/man3/X509V3_set_ctx.html \ +html/man3/X509_ALGOR_dup.html \ +html/man3/X509_ATTRIBUTE.html \ +html/man3/X509_CRL_get0_by_serial.html \ +html/man3/X509_EXTENSION_set_object.html \ +html/man3/X509_LOOKUP.html \ +html/man3/X509_LOOKUP_hash_dir.html \ +html/man3/X509_LOOKUP_meth_new.html \ +html/man3/X509_NAME_ENTRY_get_object.html \ +html/man3/X509_NAME_add_entry_by_txt.html \ +html/man3/X509_NAME_get0_der.html \ +html/man3/X509_NAME_get_index_by_NID.html \ +html/man3/X509_NAME_print_ex.html \ +html/man3/X509_PUBKEY_new.html \ +html/man3/X509_REQ_get_attr.html \ +html/man3/X509_REQ_get_extensions.html \ +html/man3/X509_SIG_get0.html \ +html/man3/X509_STORE_CTX_get_error.html \ +html/man3/X509_STORE_CTX_new.html \ +html/man3/X509_STORE_CTX_set_verify_cb.html \ +html/man3/X509_STORE_add_cert.html \ +html/man3/X509_STORE_get0_param.html \ +html/man3/X509_STORE_new.html \ +html/man3/X509_STORE_set_verify_cb_func.html \ +html/man3/X509_VERIFY_PARAM_set_flags.html \ +html/man3/X509_add_cert.html \ +html/man3/X509_check_ca.html \ +html/man3/X509_check_host.html \ +html/man3/X509_check_issued.html \ +html/man3/X509_check_private_key.html \ +html/man3/X509_check_purpose.html \ +html/man3/X509_cmp.html \ +html/man3/X509_cmp_time.html \ +html/man3/X509_digest.html \ +html/man3/X509_dup.html \ +html/man3/X509_get0_distinguishing_id.html \ +html/man3/X509_get0_notBefore.html \ +html/man3/X509_get0_signature.html \ +html/man3/X509_get0_uids.html \ +html/man3/X509_get_extension_flags.html \ +html/man3/X509_get_pubkey.html \ +html/man3/X509_get_serialNumber.html \ +html/man3/X509_get_subject_name.html \ +html/man3/X509_get_version.html \ +html/man3/X509_load_http.html \ +html/man3/X509_new.html \ +html/man3/X509_sign.html \ +html/man3/X509_verify.html \ +html/man3/X509_verify_cert.html \ +html/man3/X509v3_get_ext_by_NID.html \ +html/man3/b2i_PVK_bio_ex.html \ +html/man3/d2i_PKCS8PrivateKey_bio.html \ +html/man3/d2i_PrivateKey.html \ +html/man3/d2i_RSAPrivateKey.html \ +html/man3/d2i_SSL_SESSION.html \ +html/man3/d2i_X509.html \ +html/man3/i2d_CMS_bio_stream.html \ +html/man3/i2d_PKCS7_bio_stream.html \ +html/man3/i2d_re_X509_tbs.html \ +html/man3/o2i_SCT_LIST.html \ +html/man3/s2i_ASN1_IA5STRING.html +MANDOCS[man3]=man/man3/ADMISSIONS.3 \ +man/man3/ASN1_EXTERN_FUNCS.3 \ +man/man3/ASN1_INTEGER_get_int64.3 \ +man/man3/ASN1_INTEGER_new.3 \ +man/man3/ASN1_ITEM_lookup.3 \ +man/man3/ASN1_OBJECT_new.3 \ +man/man3/ASN1_STRING_TABLE_add.3 \ +man/man3/ASN1_STRING_length.3 \ +man/man3/ASN1_STRING_new.3 \ +man/man3/ASN1_STRING_print_ex.3 \ +man/man3/ASN1_TIME_set.3 \ +man/man3/ASN1_TYPE_get.3 \ +man/man3/ASN1_aux_cb.3 \ +man/man3/ASN1_generate_nconf.3 \ +man/man3/ASN1_item_d2i_bio.3 \ +man/man3/ASN1_item_new.3 \ +man/man3/ASN1_item_sign.3 \ +man/man3/ASYNC_WAIT_CTX_new.3 \ +man/man3/ASYNC_start_job.3 \ +man/man3/BF_encrypt.3 \ +man/man3/BIO_ADDR.3 \ +man/man3/BIO_ADDRINFO.3 \ +man/man3/BIO_connect.3 \ +man/man3/BIO_ctrl.3 \ +man/man3/BIO_f_base64.3 \ +man/man3/BIO_f_buffer.3 \ +man/man3/BIO_f_cipher.3 \ +man/man3/BIO_f_md.3 \ +man/man3/BIO_f_null.3 \ +man/man3/BIO_f_prefix.3 \ +man/man3/BIO_f_readbuffer.3 \ +man/man3/BIO_f_ssl.3 \ +man/man3/BIO_find_type.3 \ +man/man3/BIO_get_data.3 \ +man/man3/BIO_get_ex_new_index.3 \ +man/man3/BIO_meth_new.3 \ +man/man3/BIO_new.3 \ +man/man3/BIO_new_CMS.3 \ +man/man3/BIO_parse_hostserv.3 \ +man/man3/BIO_printf.3 \ +man/man3/BIO_push.3 \ +man/man3/BIO_read.3 \ +man/man3/BIO_s_accept.3 \ +man/man3/BIO_s_bio.3 \ +man/man3/BIO_s_connect.3 \ +man/man3/BIO_s_core.3 \ +man/man3/BIO_s_datagram.3 \ +man/man3/BIO_s_fd.3 \ +man/man3/BIO_s_file.3 \ +man/man3/BIO_s_mem.3 \ +man/man3/BIO_s_null.3 \ +man/man3/BIO_s_socket.3 \ +man/man3/BIO_set_callback.3 \ +man/man3/BIO_should_retry.3 \ +man/man3/BIO_socket_wait.3 \ +man/man3/BN_BLINDING_new.3 \ +man/man3/BN_CTX_new.3 \ +man/man3/BN_CTX_start.3 \ +man/man3/BN_add.3 \ +man/man3/BN_add_word.3 \ +man/man3/BN_bn2bin.3 \ +man/man3/BN_cmp.3 \ +man/man3/BN_copy.3 \ +man/man3/BN_generate_prime.3 \ +man/man3/BN_mod_exp_mont.3 \ +man/man3/BN_mod_inverse.3 \ +man/man3/BN_mod_mul_montgomery.3 \ +man/man3/BN_mod_mul_reciprocal.3 \ +man/man3/BN_new.3 \ +man/man3/BN_num_bytes.3 \ +man/man3/BN_rand.3 \ +man/man3/BN_security_bits.3 \ +man/man3/BN_set_bit.3 \ +man/man3/BN_swap.3 \ +man/man3/BN_zero.3 \ +man/man3/BUF_MEM_new.3 \ +man/man3/CMS_EncryptedData_decrypt.3 \ +man/man3/CMS_EncryptedData_encrypt.3 \ +man/man3/CMS_EnvelopedData_create.3 \ +man/man3/CMS_add0_cert.3 \ +man/man3/CMS_add1_recipient_cert.3 \ +man/man3/CMS_add1_signer.3 \ +man/man3/CMS_compress.3 \ +man/man3/CMS_data_create.3 \ +man/man3/CMS_decrypt.3 \ +man/man3/CMS_digest_create.3 \ +man/man3/CMS_encrypt.3 \ +man/man3/CMS_final.3 \ +man/man3/CMS_get0_RecipientInfos.3 \ +man/man3/CMS_get0_SignerInfos.3 \ +man/man3/CMS_get0_type.3 \ +man/man3/CMS_get1_ReceiptRequest.3 \ +man/man3/CMS_sign.3 \ +man/man3/CMS_sign_receipt.3 \ +man/man3/CMS_signed_get_attr.3 \ +man/man3/CMS_uncompress.3 \ +man/man3/CMS_verify.3 \ +man/man3/CMS_verify_receipt.3 \ +man/man3/CONF_modules_free.3 \ +man/man3/CONF_modules_load_file.3 \ +man/man3/CRYPTO_THREAD_run_once.3 \ +man/man3/CRYPTO_get_ex_new_index.3 \ +man/man3/CRYPTO_memcmp.3 \ +man/man3/CTLOG_STORE_get0_log_by_id.3 \ +man/man3/CTLOG_STORE_new.3 \ +man/man3/CTLOG_new.3 \ +man/man3/CT_POLICY_EVAL_CTX_new.3 \ +man/man3/DEFINE_STACK_OF.3 \ +man/man3/DES_random_key.3 \ +man/man3/DH_generate_key.3 \ +man/man3/DH_generate_parameters.3 \ +man/man3/DH_get0_pqg.3 \ +man/man3/DH_get_1024_160.3 \ +man/man3/DH_meth_new.3 \ +man/man3/DH_new.3 \ +man/man3/DH_new_by_nid.3 \ +man/man3/DH_set_method.3 \ +man/man3/DH_size.3 \ +man/man3/DSA_SIG_new.3 \ +man/man3/DSA_do_sign.3 \ +man/man3/DSA_dup_DH.3 \ +man/man3/DSA_generate_key.3 \ +man/man3/DSA_generate_parameters.3 \ +man/man3/DSA_get0_pqg.3 \ +man/man3/DSA_meth_new.3 \ +man/man3/DSA_new.3 \ +man/man3/DSA_set_method.3 \ +man/man3/DSA_sign.3 \ +man/man3/DSA_size.3 \ +man/man3/DTLS_get_data_mtu.3 \ +man/man3/DTLS_set_timer_cb.3 \ +man/man3/DTLSv1_listen.3 \ +man/man3/ECDSA_SIG_new.3 \ +man/man3/ECDSA_sign.3 \ +man/man3/ECPKParameters_print.3 \ +man/man3/EC_GFp_simple_method.3 \ +man/man3/EC_GROUP_copy.3 \ +man/man3/EC_GROUP_new.3 \ +man/man3/EC_KEY_get_enc_flags.3 \ +man/man3/EC_KEY_new.3 \ +man/man3/EC_POINT_add.3 \ +man/man3/EC_POINT_new.3 \ +man/man3/ENGINE_add.3 \ +man/man3/ERR_GET_LIB.3 \ +man/man3/ERR_clear_error.3 \ +man/man3/ERR_error_string.3 \ +man/man3/ERR_get_error.3 \ +man/man3/ERR_load_crypto_strings.3 \ +man/man3/ERR_load_strings.3 \ +man/man3/ERR_new.3 \ +man/man3/ERR_print_errors.3 \ +man/man3/ERR_put_error.3 \ +man/man3/ERR_remove_state.3 \ +man/man3/ERR_set_mark.3 \ +man/man3/EVP_ASYM_CIPHER_free.3 \ +man/man3/EVP_BytesToKey.3 \ +man/man3/EVP_CIPHER_CTX_get_cipher_data.3 \ +man/man3/EVP_CIPHER_CTX_get_original_iv.3 \ +man/man3/EVP_CIPHER_meth_new.3 \ +man/man3/EVP_DigestInit.3 \ +man/man3/EVP_DigestSignInit.3 \ +man/man3/EVP_DigestVerifyInit.3 \ +man/man3/EVP_EncodeInit.3 \ +man/man3/EVP_EncryptInit.3 \ +man/man3/EVP_KDF.3 \ +man/man3/EVP_KEM_free.3 \ +man/man3/EVP_KEYEXCH_free.3 \ +man/man3/EVP_KEYMGMT.3 \ +man/man3/EVP_MAC.3 \ +man/man3/EVP_MD_meth_new.3 \ +man/man3/EVP_OpenInit.3 \ +man/man3/EVP_PBE_CipherInit.3 \ +man/man3/EVP_PKEY2PKCS8.3 \ +man/man3/EVP_PKEY_ASN1_METHOD.3 \ +man/man3/EVP_PKEY_CTX_ctrl.3 \ +man/man3/EVP_PKEY_CTX_get0_libctx.3 \ +man/man3/EVP_PKEY_CTX_get0_pkey.3 \ +man/man3/EVP_PKEY_CTX_new.3 \ +man/man3/EVP_PKEY_CTX_set1_pbe_pass.3 \ +man/man3/EVP_PKEY_CTX_set_hkdf_md.3 \ +man/man3/EVP_PKEY_CTX_set_params.3 \ +man/man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.3 \ +man/man3/EVP_PKEY_CTX_set_scrypt_N.3 \ +man/man3/EVP_PKEY_CTX_set_tls1_prf_md.3 \ +man/man3/EVP_PKEY_asn1_get_count.3 \ +man/man3/EVP_PKEY_check.3 \ +man/man3/EVP_PKEY_copy_parameters.3 \ +man/man3/EVP_PKEY_decapsulate.3 \ +man/man3/EVP_PKEY_decrypt.3 \ +man/man3/EVP_PKEY_derive.3 \ +man/man3/EVP_PKEY_digestsign_supports_digest.3 \ +man/man3/EVP_PKEY_encapsulate.3 \ +man/man3/EVP_PKEY_encrypt.3 \ +man/man3/EVP_PKEY_fromdata.3 \ +man/man3/EVP_PKEY_get_attr.3 \ +man/man3/EVP_PKEY_get_default_digest_nid.3 \ +man/man3/EVP_PKEY_get_field_type.3 \ +man/man3/EVP_PKEY_get_group_name.3 \ +man/man3/EVP_PKEY_get_size.3 \ +man/man3/EVP_PKEY_gettable_params.3 \ +man/man3/EVP_PKEY_is_a.3 \ +man/man3/EVP_PKEY_keygen.3 \ +man/man3/EVP_PKEY_meth_get_count.3 \ +man/man3/EVP_PKEY_meth_new.3 \ +man/man3/EVP_PKEY_new.3 \ +man/man3/EVP_PKEY_print_private.3 \ +man/man3/EVP_PKEY_set1_RSA.3 \ +man/man3/EVP_PKEY_set1_encoded_public_key.3 \ +man/man3/EVP_PKEY_set_type.3 \ +man/man3/EVP_PKEY_settable_params.3 \ +man/man3/EVP_PKEY_sign.3 \ +man/man3/EVP_PKEY_todata.3 \ +man/man3/EVP_PKEY_verify.3 \ +man/man3/EVP_PKEY_verify_recover.3 \ +man/man3/EVP_RAND.3 \ +man/man3/EVP_SIGNATURE.3 \ +man/man3/EVP_SealInit.3 \ +man/man3/EVP_SignInit.3 \ +man/man3/EVP_VerifyInit.3 \ +man/man3/EVP_aes_128_gcm.3 \ +man/man3/EVP_aria_128_gcm.3 \ +man/man3/EVP_bf_cbc.3 \ +man/man3/EVP_blake2b512.3 \ +man/man3/EVP_camellia_128_ecb.3 \ +man/man3/EVP_cast5_cbc.3 \ +man/man3/EVP_chacha20.3 \ +man/man3/EVP_des_cbc.3 \ +man/man3/EVP_desx_cbc.3 \ +man/man3/EVP_idea_cbc.3 \ +man/man3/EVP_md2.3 \ +man/man3/EVP_md4.3 \ +man/man3/EVP_md5.3 \ +man/man3/EVP_mdc2.3 \ +man/man3/EVP_rc2_cbc.3 \ +man/man3/EVP_rc4.3 \ +man/man3/EVP_rc5_32_12_16_cbc.3 \ +man/man3/EVP_ripemd160.3 \ +man/man3/EVP_seed_cbc.3 \ +man/man3/EVP_set_default_properties.3 \ +man/man3/EVP_sha1.3 \ +man/man3/EVP_sha224.3 \ +man/man3/EVP_sha3_224.3 \ +man/man3/EVP_sm3.3 \ +man/man3/EVP_sm4_cbc.3 \ +man/man3/EVP_whirlpool.3 \ +man/man3/HMAC.3 \ +man/man3/MD5.3 \ +man/man3/MDC2_Init.3 \ +man/man3/NCONF_new_ex.3 \ +man/man3/OBJ_nid2obj.3 \ +man/man3/OCSP_REQUEST_new.3 \ +man/man3/OCSP_cert_to_id.3 \ +man/man3/OCSP_request_add1_nonce.3 \ +man/man3/OCSP_resp_find_status.3 \ +man/man3/OCSP_response_status.3 \ +man/man3/OCSP_sendreq_new.3 \ +man/man3/OPENSSL_Applink.3 \ +man/man3/OPENSSL_FILE.3 \ +man/man3/OPENSSL_LH_COMPFUNC.3 \ +man/man3/OPENSSL_LH_stats.3 \ +man/man3/OPENSSL_config.3 \ +man/man3/OPENSSL_fork_prepare.3 \ +man/man3/OPENSSL_gmtime.3 \ +man/man3/OPENSSL_hexchar2int.3 \ +man/man3/OPENSSL_ia32cap.3 \ +man/man3/OPENSSL_init_crypto.3 \ +man/man3/OPENSSL_init_ssl.3 \ +man/man3/OPENSSL_instrument_bus.3 \ +man/man3/OPENSSL_load_builtin_modules.3 \ +man/man3/OPENSSL_malloc.3 \ +man/man3/OPENSSL_s390xcap.3 \ +man/man3/OPENSSL_secure_malloc.3 \ +man/man3/OPENSSL_strcasecmp.3 \ +man/man3/OSSL_ALGORITHM.3 \ +man/man3/OSSL_CALLBACK.3 \ +man/man3/OSSL_CMP_CTX_new.3 \ +man/man3/OSSL_CMP_HDR_get0_transactionID.3 \ +man/man3/OSSL_CMP_ITAV_set0.3 \ +man/man3/OSSL_CMP_MSG_get0_header.3 \ +man/man3/OSSL_CMP_MSG_http_perform.3 \ +man/man3/OSSL_CMP_SRV_CTX_new.3 \ +man/man3/OSSL_CMP_STATUSINFO_new.3 \ +man/man3/OSSL_CMP_exec_certreq.3 \ +man/man3/OSSL_CMP_log_open.3 \ +man/man3/OSSL_CMP_validate_msg.3 \ +man/man3/OSSL_CORE_MAKE_FUNC.3 \ +man/man3/OSSL_CRMF_MSG_get0_tmpl.3 \ +man/man3/OSSL_CRMF_MSG_set0_validity.3 \ +man/man3/OSSL_CRMF_MSG_set1_regCtrl_regToken.3 \ +man/man3/OSSL_CRMF_MSG_set1_regInfo_certReq.3 \ +man/man3/OSSL_CRMF_pbmp_new.3 \ +man/man3/OSSL_DECODER.3 \ +man/man3/OSSL_DECODER_CTX.3 \ +man/man3/OSSL_DECODER_CTX_new_for_pkey.3 \ +man/man3/OSSL_DECODER_from_bio.3 \ +man/man3/OSSL_DISPATCH.3 \ +man/man3/OSSL_ENCODER.3 \ +man/man3/OSSL_ENCODER_CTX.3 \ +man/man3/OSSL_ENCODER_CTX_new_for_pkey.3 \ +man/man3/OSSL_ENCODER_to_bio.3 \ +man/man3/OSSL_ESS_check_signing_certs.3 \ +man/man3/OSSL_HTTP_REQ_CTX.3 \ +man/man3/OSSL_HTTP_parse_url.3 \ +man/man3/OSSL_HTTP_transfer.3 \ +man/man3/OSSL_ITEM.3 \ +man/man3/OSSL_LIB_CTX.3 \ +man/man3/OSSL_PARAM.3 \ +man/man3/OSSL_PARAM_BLD.3 \ +man/man3/OSSL_PARAM_allocate_from_text.3 \ +man/man3/OSSL_PARAM_dup.3 \ +man/man3/OSSL_PARAM_int.3 \ +man/man3/OSSL_PROVIDER.3 \ +man/man3/OSSL_SELF_TEST_new.3 \ +man/man3/OSSL_SELF_TEST_set_callback.3 \ +man/man3/OSSL_STORE_INFO.3 \ +man/man3/OSSL_STORE_LOADER.3 \ +man/man3/OSSL_STORE_SEARCH.3 \ +man/man3/OSSL_STORE_attach.3 \ +man/man3/OSSL_STORE_expect.3 \ +man/man3/OSSL_STORE_open.3 \ +man/man3/OSSL_trace_enabled.3 \ +man/man3/OSSL_trace_get_category_num.3 \ +man/man3/OSSL_trace_set_channel.3 \ +man/man3/OpenSSL_add_all_algorithms.3 \ +man/man3/OpenSSL_version.3 \ +man/man3/PEM_X509_INFO_read_bio_ex.3 \ +man/man3/PEM_bytes_read_bio.3 \ +man/man3/PEM_read.3 \ +man/man3/PEM_read_CMS.3 \ +man/man3/PEM_read_bio_PrivateKey.3 \ +man/man3/PEM_read_bio_ex.3 \ +man/man3/PEM_write_bio_CMS_stream.3 \ +man/man3/PEM_write_bio_PKCS7_stream.3 \ +man/man3/PKCS12_PBE_keyivgen.3 \ +man/man3/PKCS12_SAFEBAG_create_cert.3 \ +man/man3/PKCS12_SAFEBAG_get0_attrs.3 \ +man/man3/PKCS12_SAFEBAG_get1_cert.3 \ +man/man3/PKCS12_add1_attr_by_NID.3 \ +man/man3/PKCS12_add_CSPName_asc.3 \ +man/man3/PKCS12_add_cert.3 \ +man/man3/PKCS12_add_friendlyname_asc.3 \ +man/man3/PKCS12_add_localkeyid.3 \ +man/man3/PKCS12_add_safe.3 \ +man/man3/PKCS12_create.3 \ +man/man3/PKCS12_decrypt_skey.3 \ +man/man3/PKCS12_gen_mac.3 \ +man/man3/PKCS12_get_friendlyname.3 \ +man/man3/PKCS12_init.3 \ +man/man3/PKCS12_item_decrypt_d2i.3 \ +man/man3/PKCS12_key_gen_utf8_ex.3 \ +man/man3/PKCS12_newpass.3 \ +man/man3/PKCS12_pack_p7encdata.3 \ +man/man3/PKCS12_parse.3 \ +man/man3/PKCS5_PBE_keyivgen.3 \ +man/man3/PKCS5_PBKDF2_HMAC.3 \ +man/man3/PKCS7_decrypt.3 \ +man/man3/PKCS7_encrypt.3 \ +man/man3/PKCS7_get_octet_string.3 \ +man/man3/PKCS7_sign.3 \ +man/man3/PKCS7_sign_add_signer.3 \ +man/man3/PKCS7_type_is_other.3 \ +man/man3/PKCS7_verify.3 \ +man/man3/PKCS8_encrypt.3 \ +man/man3/PKCS8_pkey_add1_attr.3 \ +man/man3/RAND_add.3 \ +man/man3/RAND_bytes.3 \ +man/man3/RAND_cleanup.3 \ +man/man3/RAND_egd.3 \ +man/man3/RAND_get0_primary.3 \ +man/man3/RAND_load_file.3 \ +man/man3/RAND_set_DRBG_type.3 \ +man/man3/RAND_set_rand_method.3 \ +man/man3/RC4_set_key.3 \ +man/man3/RIPEMD160_Init.3 \ +man/man3/RSA_blinding_on.3 \ +man/man3/RSA_check_key.3 \ +man/man3/RSA_generate_key.3 \ +man/man3/RSA_get0_key.3 \ +man/man3/RSA_meth_new.3 \ +man/man3/RSA_new.3 \ +man/man3/RSA_padding_add_PKCS1_type_1.3 \ +man/man3/RSA_print.3 \ +man/man3/RSA_private_encrypt.3 \ +man/man3/RSA_public_encrypt.3 \ +man/man3/RSA_set_method.3 \ +man/man3/RSA_sign.3 \ +man/man3/RSA_sign_ASN1_OCTET_STRING.3 \ +man/man3/RSA_size.3 \ +man/man3/SCT_new.3 \ +man/man3/SCT_print.3 \ +man/man3/SCT_validate.3 \ +man/man3/SHA256_Init.3 \ +man/man3/SMIME_read_ASN1.3 \ +man/man3/SMIME_read_CMS.3 \ +man/man3/SMIME_read_PKCS7.3 \ +man/man3/SMIME_write_ASN1.3 \ +man/man3/SMIME_write_CMS.3 \ +man/man3/SMIME_write_PKCS7.3 \ +man/man3/SRP_Calc_B.3 \ +man/man3/SRP_VBASE_new.3 \ +man/man3/SRP_create_verifier.3 \ +man/man3/SRP_user_pwd_new.3 \ +man/man3/SSL_CIPHER_get_name.3 \ +man/man3/SSL_COMP_add_compression_method.3 \ +man/man3/SSL_CONF_CTX_new.3 \ +man/man3/SSL_CONF_CTX_set1_prefix.3 \ +man/man3/SSL_CONF_CTX_set_flags.3 \ +man/man3/SSL_CONF_CTX_set_ssl_ctx.3 \ +man/man3/SSL_CONF_cmd.3 \ +man/man3/SSL_CONF_cmd_argv.3 \ +man/man3/SSL_CTX_add1_chain_cert.3 \ +man/man3/SSL_CTX_add_extra_chain_cert.3 \ +man/man3/SSL_CTX_add_session.3 \ +man/man3/SSL_CTX_config.3 \ +man/man3/SSL_CTX_ctrl.3 \ +man/man3/SSL_CTX_dane_enable.3 \ +man/man3/SSL_CTX_flush_sessions.3 \ +man/man3/SSL_CTX_free.3 \ +man/man3/SSL_CTX_get0_param.3 \ +man/man3/SSL_CTX_get_verify_mode.3 \ +man/man3/SSL_CTX_has_client_custom_ext.3 \ +man/man3/SSL_CTX_load_verify_locations.3 \ +man/man3/SSL_CTX_new.3 \ +man/man3/SSL_CTX_sess_number.3 \ +man/man3/SSL_CTX_sess_set_cache_size.3 \ +man/man3/SSL_CTX_sess_set_get_cb.3 \ +man/man3/SSL_CTX_sessions.3 \ +man/man3/SSL_CTX_set0_CA_list.3 \ +man/man3/SSL_CTX_set1_curves.3 \ +man/man3/SSL_CTX_set1_sigalgs.3 \ +man/man3/SSL_CTX_set1_verify_cert_store.3 \ +man/man3/SSL_CTX_set_alpn_select_cb.3 \ +man/man3/SSL_CTX_set_cert_cb.3 \ +man/man3/SSL_CTX_set_cert_store.3 \ +man/man3/SSL_CTX_set_cert_verify_callback.3 \ +man/man3/SSL_CTX_set_cipher_list.3 \ +man/man3/SSL_CTX_set_client_cert_cb.3 \ +man/man3/SSL_CTX_set_client_hello_cb.3 \ +man/man3/SSL_CTX_set_ct_validation_callback.3 \ +man/man3/SSL_CTX_set_ctlog_list_file.3 \ +man/man3/SSL_CTX_set_default_passwd_cb.3 \ +man/man3/SSL_CTX_set_generate_session_id.3 \ +man/man3/SSL_CTX_set_info_callback.3 \ +man/man3/SSL_CTX_set_keylog_callback.3 \ +man/man3/SSL_CTX_set_max_cert_list.3 \ +man/man3/SSL_CTX_set_min_proto_version.3 \ +man/man3/SSL_CTX_set_mode.3 \ +man/man3/SSL_CTX_set_msg_callback.3 \ +man/man3/SSL_CTX_set_num_tickets.3 \ +man/man3/SSL_CTX_set_options.3 \ +man/man3/SSL_CTX_set_psk_client_callback.3 \ +man/man3/SSL_CTX_set_quiet_shutdown.3 \ +man/man3/SSL_CTX_set_read_ahead.3 \ +man/man3/SSL_CTX_set_record_padding_callback.3 \ +man/man3/SSL_CTX_set_security_level.3 \ +man/man3/SSL_CTX_set_session_cache_mode.3 \ +man/man3/SSL_CTX_set_session_id_context.3 \ +man/man3/SSL_CTX_set_session_ticket_cb.3 \ +man/man3/SSL_CTX_set_split_send_fragment.3 \ +man/man3/SSL_CTX_set_srp_password.3 \ +man/man3/SSL_CTX_set_ssl_version.3 \ +man/man3/SSL_CTX_set_stateless_cookie_generate_cb.3 \ +man/man3/SSL_CTX_set_timeout.3 \ +man/man3/SSL_CTX_set_tlsext_servername_callback.3 \ +man/man3/SSL_CTX_set_tlsext_status_cb.3 \ +man/man3/SSL_CTX_set_tlsext_ticket_key_cb.3 \ +man/man3/SSL_CTX_set_tlsext_use_srtp.3 \ +man/man3/SSL_CTX_set_tmp_dh_callback.3 \ +man/man3/SSL_CTX_set_tmp_ecdh.3 \ +man/man3/SSL_CTX_set_verify.3 \ +man/man3/SSL_CTX_use_certificate.3 \ +man/man3/SSL_CTX_use_psk_identity_hint.3 \ +man/man3/SSL_CTX_use_serverinfo.3 \ +man/man3/SSL_SESSION_free.3 \ +man/man3/SSL_SESSION_get0_cipher.3 \ +man/man3/SSL_SESSION_get0_hostname.3 \ +man/man3/SSL_SESSION_get0_id_context.3 \ +man/man3/SSL_SESSION_get0_peer.3 \ +man/man3/SSL_SESSION_get_compress_id.3 \ +man/man3/SSL_SESSION_get_protocol_version.3 \ +man/man3/SSL_SESSION_get_time.3 \ +man/man3/SSL_SESSION_has_ticket.3 \ +man/man3/SSL_SESSION_is_resumable.3 \ +man/man3/SSL_SESSION_print.3 \ +man/man3/SSL_SESSION_set1_id.3 \ +man/man3/SSL_accept.3 \ +man/man3/SSL_alert_type_string.3 \ +man/man3/SSL_alloc_buffers.3 \ +man/man3/SSL_check_chain.3 \ +man/man3/SSL_clear.3 \ +man/man3/SSL_connect.3 \ +man/man3/SSL_do_handshake.3 \ +man/man3/SSL_export_keying_material.3 \ +man/man3/SSL_extension_supported.3 \ +man/man3/SSL_free.3 \ +man/man3/SSL_get0_peer_scts.3 \ +man/man3/SSL_get_SSL_CTX.3 \ +man/man3/SSL_get_all_async_fds.3 \ +man/man3/SSL_get_certificate.3 \ +man/man3/SSL_get_ciphers.3 \ +man/man3/SSL_get_client_random.3 \ +man/man3/SSL_get_current_cipher.3 \ +man/man3/SSL_get_default_timeout.3 \ +man/man3/SSL_get_error.3 \ +man/man3/SSL_get_extms_support.3 \ +man/man3/SSL_get_fd.3 \ +man/man3/SSL_get_peer_cert_chain.3 \ +man/man3/SSL_get_peer_certificate.3 \ +man/man3/SSL_get_peer_signature_nid.3 \ +man/man3/SSL_get_peer_tmp_key.3 \ +man/man3/SSL_get_psk_identity.3 \ +man/man3/SSL_get_rbio.3 \ +man/man3/SSL_get_session.3 \ +man/man3/SSL_get_shared_sigalgs.3 \ +man/man3/SSL_get_verify_result.3 \ +man/man3/SSL_get_version.3 \ +man/man3/SSL_group_to_name.3 \ +man/man3/SSL_in_init.3 \ +man/man3/SSL_key_update.3 \ +man/man3/SSL_library_init.3 \ +man/man3/SSL_load_client_CA_file.3 \ +man/man3/SSL_new.3 \ +man/man3/SSL_pending.3 \ +man/man3/SSL_read.3 \ +man/man3/SSL_read_early_data.3 \ +man/man3/SSL_rstate_string.3 \ +man/man3/SSL_session_reused.3 \ +man/man3/SSL_set1_host.3 \ +man/man3/SSL_set_async_callback.3 \ +man/man3/SSL_set_bio.3 \ +man/man3/SSL_set_connect_state.3 \ +man/man3/SSL_set_fd.3 \ +man/man3/SSL_set_retry_verify.3 \ +man/man3/SSL_set_session.3 \ +man/man3/SSL_set_shutdown.3 \ +man/man3/SSL_set_verify_result.3 \ +man/man3/SSL_shutdown.3 \ +man/man3/SSL_state_string.3 \ +man/man3/SSL_want.3 \ +man/man3/SSL_write.3 \ +man/man3/TS_RESP_CTX_new.3 \ +man/man3/TS_VERIFY_CTX_set_certs.3 \ +man/man3/UI_STRING.3 \ +man/man3/UI_UTIL_read_pw.3 \ +man/man3/UI_create_method.3 \ +man/man3/UI_new.3 \ +man/man3/X509V3_get_d2i.3 \ +man/man3/X509V3_set_ctx.3 \ +man/man3/X509_ALGOR_dup.3 \ +man/man3/X509_ATTRIBUTE.3 \ +man/man3/X509_CRL_get0_by_serial.3 \ +man/man3/X509_EXTENSION_set_object.3 \ +man/man3/X509_LOOKUP.3 \ +man/man3/X509_LOOKUP_hash_dir.3 \ +man/man3/X509_LOOKUP_meth_new.3 \ +man/man3/X509_NAME_ENTRY_get_object.3 \ +man/man3/X509_NAME_add_entry_by_txt.3 \ +man/man3/X509_NAME_get0_der.3 \ +man/man3/X509_NAME_get_index_by_NID.3 \ +man/man3/X509_NAME_print_ex.3 \ +man/man3/X509_PUBKEY_new.3 \ +man/man3/X509_REQ_get_attr.3 \ +man/man3/X509_REQ_get_extensions.3 \ +man/man3/X509_SIG_get0.3 \ +man/man3/X509_STORE_CTX_get_error.3 \ +man/man3/X509_STORE_CTX_new.3 \ +man/man3/X509_STORE_CTX_set_verify_cb.3 \ +man/man3/X509_STORE_add_cert.3 \ +man/man3/X509_STORE_get0_param.3 \ +man/man3/X509_STORE_new.3 \ +man/man3/X509_STORE_set_verify_cb_func.3 \ +man/man3/X509_VERIFY_PARAM_set_flags.3 \ +man/man3/X509_add_cert.3 \ +man/man3/X509_check_ca.3 \ +man/man3/X509_check_host.3 \ +man/man3/X509_check_issued.3 \ +man/man3/X509_check_private_key.3 \ +man/man3/X509_check_purpose.3 \ +man/man3/X509_cmp.3 \ +man/man3/X509_cmp_time.3 \ +man/man3/X509_digest.3 \ +man/man3/X509_dup.3 \ +man/man3/X509_get0_distinguishing_id.3 \ +man/man3/X509_get0_notBefore.3 \ +man/man3/X509_get0_signature.3 \ +man/man3/X509_get0_uids.3 \ +man/man3/X509_get_extension_flags.3 \ +man/man3/X509_get_pubkey.3 \ +man/man3/X509_get_serialNumber.3 \ +man/man3/X509_get_subject_name.3 \ +man/man3/X509_get_version.3 \ +man/man3/X509_load_http.3 \ +man/man3/X509_new.3 \ +man/man3/X509_sign.3 \ +man/man3/X509_verify.3 \ +man/man3/X509_verify_cert.3 \ +man/man3/X509v3_get_ext_by_NID.3 \ +man/man3/b2i_PVK_bio_ex.3 \ +man/man3/d2i_PKCS8PrivateKey_bio.3 \ +man/man3/d2i_PrivateKey.3 \ +man/man3/d2i_RSAPrivateKey.3 \ +man/man3/d2i_SSL_SESSION.3 \ +man/man3/d2i_X509.3 \ +man/man3/i2d_CMS_bio_stream.3 \ +man/man3/i2d_PKCS7_bio_stream.3 \ +man/man3/i2d_re_X509_tbs.3 \ +man/man3/o2i_SCT_LIST.3 \ +man/man3/s2i_ASN1_IA5STRING.3 +DEPEND[html/man5/config.html]=man5/config.pod +GENERATE[html/man5/config.html]=man5/config.pod +DEPEND[man/man5/config.5]=man5/config.pod +GENERATE[man/man5/config.5]=man5/config.pod +DEPEND[html/man5/fips_config.html]=man5/fips_config.pod +GENERATE[html/man5/fips_config.html]=man5/fips_config.pod +DEPEND[man/man5/fips_config.5]=man5/fips_config.pod +GENERATE[man/man5/fips_config.5]=man5/fips_config.pod +DEPEND[html/man5/x509v3_config.html]=man5/x509v3_config.pod +GENERATE[html/man5/x509v3_config.html]=man5/x509v3_config.pod +DEPEND[man/man5/x509v3_config.5]=man5/x509v3_config.pod +GENERATE[man/man5/x509v3_config.5]=man5/x509v3_config.pod +IMAGEDOCS[man5]= +HTMLDOCS[man5]=html/man5/config.html \ +html/man5/fips_config.html \ +html/man5/x509v3_config.html +MANDOCS[man5]=man/man5/config.5 \ +man/man5/fips_config.5 \ +man/man5/x509v3_config.5 +DEPEND[html/man7/EVP_ASYM_CIPHER-RSA.html]=man7/EVP_ASYM_CIPHER-RSA.pod +GENERATE[html/man7/EVP_ASYM_CIPHER-RSA.html]=man7/EVP_ASYM_CIPHER-RSA.pod +DEPEND[man/man7/EVP_ASYM_CIPHER-RSA.7]=man7/EVP_ASYM_CIPHER-RSA.pod +GENERATE[man/man7/EVP_ASYM_CIPHER-RSA.7]=man7/EVP_ASYM_CIPHER-RSA.pod +DEPEND[html/man7/EVP_ASYM_CIPHER-SM2.html]=man7/EVP_ASYM_CIPHER-SM2.pod +GENERATE[html/man7/EVP_ASYM_CIPHER-SM2.html]=man7/EVP_ASYM_CIPHER-SM2.pod +DEPEND[man/man7/EVP_ASYM_CIPHER-SM2.7]=man7/EVP_ASYM_CIPHER-SM2.pod +GENERATE[man/man7/EVP_ASYM_CIPHER-SM2.7]=man7/EVP_ASYM_CIPHER-SM2.pod +DEPEND[html/man7/EVP_CIPHER-AES.html]=man7/EVP_CIPHER-AES.pod +GENERATE[html/man7/EVP_CIPHER-AES.html]=man7/EVP_CIPHER-AES.pod +DEPEND[man/man7/EVP_CIPHER-AES.7]=man7/EVP_CIPHER-AES.pod +GENERATE[man/man7/EVP_CIPHER-AES.7]=man7/EVP_CIPHER-AES.pod +DEPEND[html/man7/EVP_CIPHER-ARIA.html]=man7/EVP_CIPHER-ARIA.pod +GENERATE[html/man7/EVP_CIPHER-ARIA.html]=man7/EVP_CIPHER-ARIA.pod +DEPEND[man/man7/EVP_CIPHER-ARIA.7]=man7/EVP_CIPHER-ARIA.pod +GENERATE[man/man7/EVP_CIPHER-ARIA.7]=man7/EVP_CIPHER-ARIA.pod +DEPEND[html/man7/EVP_CIPHER-BLOWFISH.html]=man7/EVP_CIPHER-BLOWFISH.pod +GENERATE[html/man7/EVP_CIPHER-BLOWFISH.html]=man7/EVP_CIPHER-BLOWFISH.pod +DEPEND[man/man7/EVP_CIPHER-BLOWFISH.7]=man7/EVP_CIPHER-BLOWFISH.pod +GENERATE[man/man7/EVP_CIPHER-BLOWFISH.7]=man7/EVP_CIPHER-BLOWFISH.pod +DEPEND[html/man7/EVP_CIPHER-CAMELLIA.html]=man7/EVP_CIPHER-CAMELLIA.pod +GENERATE[html/man7/EVP_CIPHER-CAMELLIA.html]=man7/EVP_CIPHER-CAMELLIA.pod +DEPEND[man/man7/EVP_CIPHER-CAMELLIA.7]=man7/EVP_CIPHER-CAMELLIA.pod +GENERATE[man/man7/EVP_CIPHER-CAMELLIA.7]=man7/EVP_CIPHER-CAMELLIA.pod +DEPEND[html/man7/EVP_CIPHER-CAST.html]=man7/EVP_CIPHER-CAST.pod +GENERATE[html/man7/EVP_CIPHER-CAST.html]=man7/EVP_CIPHER-CAST.pod +DEPEND[man/man7/EVP_CIPHER-CAST.7]=man7/EVP_CIPHER-CAST.pod +GENERATE[man/man7/EVP_CIPHER-CAST.7]=man7/EVP_CIPHER-CAST.pod +DEPEND[html/man7/EVP_CIPHER-CHACHA.html]=man7/EVP_CIPHER-CHACHA.pod +GENERATE[html/man7/EVP_CIPHER-CHACHA.html]=man7/EVP_CIPHER-CHACHA.pod +DEPEND[man/man7/EVP_CIPHER-CHACHA.7]=man7/EVP_CIPHER-CHACHA.pod +GENERATE[man/man7/EVP_CIPHER-CHACHA.7]=man7/EVP_CIPHER-CHACHA.pod +DEPEND[html/man7/EVP_CIPHER-DES.html]=man7/EVP_CIPHER-DES.pod +GENERATE[html/man7/EVP_CIPHER-DES.html]=man7/EVP_CIPHER-DES.pod +DEPEND[man/man7/EVP_CIPHER-DES.7]=man7/EVP_CIPHER-DES.pod +GENERATE[man/man7/EVP_CIPHER-DES.7]=man7/EVP_CIPHER-DES.pod +DEPEND[html/man7/EVP_CIPHER-IDEA.html]=man7/EVP_CIPHER-IDEA.pod +GENERATE[html/man7/EVP_CIPHER-IDEA.html]=man7/EVP_CIPHER-IDEA.pod +DEPEND[man/man7/EVP_CIPHER-IDEA.7]=man7/EVP_CIPHER-IDEA.pod +GENERATE[man/man7/EVP_CIPHER-IDEA.7]=man7/EVP_CIPHER-IDEA.pod +DEPEND[html/man7/EVP_CIPHER-NULL.html]=man7/EVP_CIPHER-NULL.pod +GENERATE[html/man7/EVP_CIPHER-NULL.html]=man7/EVP_CIPHER-NULL.pod +DEPEND[man/man7/EVP_CIPHER-NULL.7]=man7/EVP_CIPHER-NULL.pod +GENERATE[man/man7/EVP_CIPHER-NULL.7]=man7/EVP_CIPHER-NULL.pod +DEPEND[html/man7/EVP_CIPHER-RC2.html]=man7/EVP_CIPHER-RC2.pod +GENERATE[html/man7/EVP_CIPHER-RC2.html]=man7/EVP_CIPHER-RC2.pod +DEPEND[man/man7/EVP_CIPHER-RC2.7]=man7/EVP_CIPHER-RC2.pod +GENERATE[man/man7/EVP_CIPHER-RC2.7]=man7/EVP_CIPHER-RC2.pod +DEPEND[html/man7/EVP_CIPHER-RC4.html]=man7/EVP_CIPHER-RC4.pod +GENERATE[html/man7/EVP_CIPHER-RC4.html]=man7/EVP_CIPHER-RC4.pod +DEPEND[man/man7/EVP_CIPHER-RC4.7]=man7/EVP_CIPHER-RC4.pod +GENERATE[man/man7/EVP_CIPHER-RC4.7]=man7/EVP_CIPHER-RC4.pod +DEPEND[html/man7/EVP_CIPHER-RC5.html]=man7/EVP_CIPHER-RC5.pod +GENERATE[html/man7/EVP_CIPHER-RC5.html]=man7/EVP_CIPHER-RC5.pod +DEPEND[man/man7/EVP_CIPHER-RC5.7]=man7/EVP_CIPHER-RC5.pod +GENERATE[man/man7/EVP_CIPHER-RC5.7]=man7/EVP_CIPHER-RC5.pod +DEPEND[html/man7/EVP_CIPHER-SEED.html]=man7/EVP_CIPHER-SEED.pod +GENERATE[html/man7/EVP_CIPHER-SEED.html]=man7/EVP_CIPHER-SEED.pod +DEPEND[man/man7/EVP_CIPHER-SEED.7]=man7/EVP_CIPHER-SEED.pod +GENERATE[man/man7/EVP_CIPHER-SEED.7]=man7/EVP_CIPHER-SEED.pod +DEPEND[html/man7/EVP_CIPHER-SM4.html]=man7/EVP_CIPHER-SM4.pod +GENERATE[html/man7/EVP_CIPHER-SM4.html]=man7/EVP_CIPHER-SM4.pod +DEPEND[man/man7/EVP_CIPHER-SM4.7]=man7/EVP_CIPHER-SM4.pod +GENERATE[man/man7/EVP_CIPHER-SM4.7]=man7/EVP_CIPHER-SM4.pod +DEPEND[html/man7/EVP_KDF-HKDF.html]=man7/EVP_KDF-HKDF.pod +GENERATE[html/man7/EVP_KDF-HKDF.html]=man7/EVP_KDF-HKDF.pod +DEPEND[man/man7/EVP_KDF-HKDF.7]=man7/EVP_KDF-HKDF.pod +GENERATE[man/man7/EVP_KDF-HKDF.7]=man7/EVP_KDF-HKDF.pod +DEPEND[html/man7/EVP_KDF-KB.html]=man7/EVP_KDF-KB.pod +GENERATE[html/man7/EVP_KDF-KB.html]=man7/EVP_KDF-KB.pod +DEPEND[man/man7/EVP_KDF-KB.7]=man7/EVP_KDF-KB.pod +GENERATE[man/man7/EVP_KDF-KB.7]=man7/EVP_KDF-KB.pod +DEPEND[html/man7/EVP_KDF-KRB5KDF.html]=man7/EVP_KDF-KRB5KDF.pod +GENERATE[html/man7/EVP_KDF-KRB5KDF.html]=man7/EVP_KDF-KRB5KDF.pod +DEPEND[man/man7/EVP_KDF-KRB5KDF.7]=man7/EVP_KDF-KRB5KDF.pod +GENERATE[man/man7/EVP_KDF-KRB5KDF.7]=man7/EVP_KDF-KRB5KDF.pod +DEPEND[html/man7/EVP_KDF-PBKDF1.html]=man7/EVP_KDF-PBKDF1.pod +GENERATE[html/man7/EVP_KDF-PBKDF1.html]=man7/EVP_KDF-PBKDF1.pod +DEPEND[man/man7/EVP_KDF-PBKDF1.7]=man7/EVP_KDF-PBKDF1.pod +GENERATE[man/man7/EVP_KDF-PBKDF1.7]=man7/EVP_KDF-PBKDF1.pod +DEPEND[html/man7/EVP_KDF-PBKDF2.html]=man7/EVP_KDF-PBKDF2.pod +GENERATE[html/man7/EVP_KDF-PBKDF2.html]=man7/EVP_KDF-PBKDF2.pod +DEPEND[man/man7/EVP_KDF-PBKDF2.7]=man7/EVP_KDF-PBKDF2.pod +GENERATE[man/man7/EVP_KDF-PBKDF2.7]=man7/EVP_KDF-PBKDF2.pod +DEPEND[html/man7/EVP_KDF-PKCS12KDF.html]=man7/EVP_KDF-PKCS12KDF.pod +GENERATE[html/man7/EVP_KDF-PKCS12KDF.html]=man7/EVP_KDF-PKCS12KDF.pod +DEPEND[man/man7/EVP_KDF-PKCS12KDF.7]=man7/EVP_KDF-PKCS12KDF.pod +GENERATE[man/man7/EVP_KDF-PKCS12KDF.7]=man7/EVP_KDF-PKCS12KDF.pod +DEPEND[html/man7/EVP_KDF-SCRYPT.html]=man7/EVP_KDF-SCRYPT.pod +GENERATE[html/man7/EVP_KDF-SCRYPT.html]=man7/EVP_KDF-SCRYPT.pod +DEPEND[man/man7/EVP_KDF-SCRYPT.7]=man7/EVP_KDF-SCRYPT.pod +GENERATE[man/man7/EVP_KDF-SCRYPT.7]=man7/EVP_KDF-SCRYPT.pod +DEPEND[html/man7/EVP_KDF-SS.html]=man7/EVP_KDF-SS.pod +GENERATE[html/man7/EVP_KDF-SS.html]=man7/EVP_KDF-SS.pod +DEPEND[man/man7/EVP_KDF-SS.7]=man7/EVP_KDF-SS.pod +GENERATE[man/man7/EVP_KDF-SS.7]=man7/EVP_KDF-SS.pod +DEPEND[html/man7/EVP_KDF-SSHKDF.html]=man7/EVP_KDF-SSHKDF.pod +GENERATE[html/man7/EVP_KDF-SSHKDF.html]=man7/EVP_KDF-SSHKDF.pod +DEPEND[man/man7/EVP_KDF-SSHKDF.7]=man7/EVP_KDF-SSHKDF.pod +GENERATE[man/man7/EVP_KDF-SSHKDF.7]=man7/EVP_KDF-SSHKDF.pod +DEPEND[html/man7/EVP_KDF-TLS13_KDF.html]=man7/EVP_KDF-TLS13_KDF.pod +GENERATE[html/man7/EVP_KDF-TLS13_KDF.html]=man7/EVP_KDF-TLS13_KDF.pod +DEPEND[man/man7/EVP_KDF-TLS13_KDF.7]=man7/EVP_KDF-TLS13_KDF.pod +GENERATE[man/man7/EVP_KDF-TLS13_KDF.7]=man7/EVP_KDF-TLS13_KDF.pod +DEPEND[html/man7/EVP_KDF-TLS1_PRF.html]=man7/EVP_KDF-TLS1_PRF.pod +GENERATE[html/man7/EVP_KDF-TLS1_PRF.html]=man7/EVP_KDF-TLS1_PRF.pod +DEPEND[man/man7/EVP_KDF-TLS1_PRF.7]=man7/EVP_KDF-TLS1_PRF.pod +GENERATE[man/man7/EVP_KDF-TLS1_PRF.7]=man7/EVP_KDF-TLS1_PRF.pod +DEPEND[html/man7/EVP_KDF-X942-ASN1.html]=man7/EVP_KDF-X942-ASN1.pod +GENERATE[html/man7/EVP_KDF-X942-ASN1.html]=man7/EVP_KDF-X942-ASN1.pod +DEPEND[man/man7/EVP_KDF-X942-ASN1.7]=man7/EVP_KDF-X942-ASN1.pod +GENERATE[man/man7/EVP_KDF-X942-ASN1.7]=man7/EVP_KDF-X942-ASN1.pod +DEPEND[html/man7/EVP_KDF-X942-CONCAT.html]=man7/EVP_KDF-X942-CONCAT.pod +GENERATE[html/man7/EVP_KDF-X942-CONCAT.html]=man7/EVP_KDF-X942-CONCAT.pod +DEPEND[man/man7/EVP_KDF-X942-CONCAT.7]=man7/EVP_KDF-X942-CONCAT.pod +GENERATE[man/man7/EVP_KDF-X942-CONCAT.7]=man7/EVP_KDF-X942-CONCAT.pod +DEPEND[html/man7/EVP_KDF-X963.html]=man7/EVP_KDF-X963.pod +GENERATE[html/man7/EVP_KDF-X963.html]=man7/EVP_KDF-X963.pod +DEPEND[man/man7/EVP_KDF-X963.7]=man7/EVP_KDF-X963.pod +GENERATE[man/man7/EVP_KDF-X963.7]=man7/EVP_KDF-X963.pod +DEPEND[html/man7/EVP_KEM-RSA.html]=man7/EVP_KEM-RSA.pod +GENERATE[html/man7/EVP_KEM-RSA.html]=man7/EVP_KEM-RSA.pod +DEPEND[man/man7/EVP_KEM-RSA.7]=man7/EVP_KEM-RSA.pod +GENERATE[man/man7/EVP_KEM-RSA.7]=man7/EVP_KEM-RSA.pod +DEPEND[html/man7/EVP_KEYEXCH-DH.html]=man7/EVP_KEYEXCH-DH.pod +GENERATE[html/man7/EVP_KEYEXCH-DH.html]=man7/EVP_KEYEXCH-DH.pod +DEPEND[man/man7/EVP_KEYEXCH-DH.7]=man7/EVP_KEYEXCH-DH.pod +GENERATE[man/man7/EVP_KEYEXCH-DH.7]=man7/EVP_KEYEXCH-DH.pod +DEPEND[html/man7/EVP_KEYEXCH-ECDH.html]=man7/EVP_KEYEXCH-ECDH.pod +GENERATE[html/man7/EVP_KEYEXCH-ECDH.html]=man7/EVP_KEYEXCH-ECDH.pod +DEPEND[man/man7/EVP_KEYEXCH-ECDH.7]=man7/EVP_KEYEXCH-ECDH.pod +GENERATE[man/man7/EVP_KEYEXCH-ECDH.7]=man7/EVP_KEYEXCH-ECDH.pod +DEPEND[html/man7/EVP_KEYEXCH-X25519.html]=man7/EVP_KEYEXCH-X25519.pod +GENERATE[html/man7/EVP_KEYEXCH-X25519.html]=man7/EVP_KEYEXCH-X25519.pod +DEPEND[man/man7/EVP_KEYEXCH-X25519.7]=man7/EVP_KEYEXCH-X25519.pod +GENERATE[man/man7/EVP_KEYEXCH-X25519.7]=man7/EVP_KEYEXCH-X25519.pod +DEPEND[html/man7/EVP_MAC-BLAKE2.html]=man7/EVP_MAC-BLAKE2.pod +GENERATE[html/man7/EVP_MAC-BLAKE2.html]=man7/EVP_MAC-BLAKE2.pod +DEPEND[man/man7/EVP_MAC-BLAKE2.7]=man7/EVP_MAC-BLAKE2.pod +GENERATE[man/man7/EVP_MAC-BLAKE2.7]=man7/EVP_MAC-BLAKE2.pod +DEPEND[html/man7/EVP_MAC-CMAC.html]=man7/EVP_MAC-CMAC.pod +GENERATE[html/man7/EVP_MAC-CMAC.html]=man7/EVP_MAC-CMAC.pod +DEPEND[man/man7/EVP_MAC-CMAC.7]=man7/EVP_MAC-CMAC.pod +GENERATE[man/man7/EVP_MAC-CMAC.7]=man7/EVP_MAC-CMAC.pod +DEPEND[html/man7/EVP_MAC-GMAC.html]=man7/EVP_MAC-GMAC.pod +GENERATE[html/man7/EVP_MAC-GMAC.html]=man7/EVP_MAC-GMAC.pod +DEPEND[man/man7/EVP_MAC-GMAC.7]=man7/EVP_MAC-GMAC.pod +GENERATE[man/man7/EVP_MAC-GMAC.7]=man7/EVP_MAC-GMAC.pod +DEPEND[html/man7/EVP_MAC-HMAC.html]=man7/EVP_MAC-HMAC.pod +GENERATE[html/man7/EVP_MAC-HMAC.html]=man7/EVP_MAC-HMAC.pod +DEPEND[man/man7/EVP_MAC-HMAC.7]=man7/EVP_MAC-HMAC.pod +GENERATE[man/man7/EVP_MAC-HMAC.7]=man7/EVP_MAC-HMAC.pod +DEPEND[html/man7/EVP_MAC-KMAC.html]=man7/EVP_MAC-KMAC.pod +GENERATE[html/man7/EVP_MAC-KMAC.html]=man7/EVP_MAC-KMAC.pod +DEPEND[man/man7/EVP_MAC-KMAC.7]=man7/EVP_MAC-KMAC.pod +GENERATE[man/man7/EVP_MAC-KMAC.7]=man7/EVP_MAC-KMAC.pod +DEPEND[html/man7/EVP_MAC-Poly1305.html]=man7/EVP_MAC-Poly1305.pod +GENERATE[html/man7/EVP_MAC-Poly1305.html]=man7/EVP_MAC-Poly1305.pod +DEPEND[man/man7/EVP_MAC-Poly1305.7]=man7/EVP_MAC-Poly1305.pod +GENERATE[man/man7/EVP_MAC-Poly1305.7]=man7/EVP_MAC-Poly1305.pod +DEPEND[html/man7/EVP_MAC-Siphash.html]=man7/EVP_MAC-Siphash.pod +GENERATE[html/man7/EVP_MAC-Siphash.html]=man7/EVP_MAC-Siphash.pod +DEPEND[man/man7/EVP_MAC-Siphash.7]=man7/EVP_MAC-Siphash.pod +GENERATE[man/man7/EVP_MAC-Siphash.7]=man7/EVP_MAC-Siphash.pod +DEPEND[html/man7/EVP_MD-BLAKE2.html]=man7/EVP_MD-BLAKE2.pod +GENERATE[html/man7/EVP_MD-BLAKE2.html]=man7/EVP_MD-BLAKE2.pod +DEPEND[man/man7/EVP_MD-BLAKE2.7]=man7/EVP_MD-BLAKE2.pod +GENERATE[man/man7/EVP_MD-BLAKE2.7]=man7/EVP_MD-BLAKE2.pod +DEPEND[html/man7/EVP_MD-MD2.html]=man7/EVP_MD-MD2.pod +GENERATE[html/man7/EVP_MD-MD2.html]=man7/EVP_MD-MD2.pod +DEPEND[man/man7/EVP_MD-MD2.7]=man7/EVP_MD-MD2.pod +GENERATE[man/man7/EVP_MD-MD2.7]=man7/EVP_MD-MD2.pod +DEPEND[html/man7/EVP_MD-MD4.html]=man7/EVP_MD-MD4.pod +GENERATE[html/man7/EVP_MD-MD4.html]=man7/EVP_MD-MD4.pod +DEPEND[man/man7/EVP_MD-MD4.7]=man7/EVP_MD-MD4.pod +GENERATE[man/man7/EVP_MD-MD4.7]=man7/EVP_MD-MD4.pod +DEPEND[html/man7/EVP_MD-MD5-SHA1.html]=man7/EVP_MD-MD5-SHA1.pod +GENERATE[html/man7/EVP_MD-MD5-SHA1.html]=man7/EVP_MD-MD5-SHA1.pod +DEPEND[man/man7/EVP_MD-MD5-SHA1.7]=man7/EVP_MD-MD5-SHA1.pod +GENERATE[man/man7/EVP_MD-MD5-SHA1.7]=man7/EVP_MD-MD5-SHA1.pod +DEPEND[html/man7/EVP_MD-MD5.html]=man7/EVP_MD-MD5.pod +GENERATE[html/man7/EVP_MD-MD5.html]=man7/EVP_MD-MD5.pod +DEPEND[man/man7/EVP_MD-MD5.7]=man7/EVP_MD-MD5.pod +GENERATE[man/man7/EVP_MD-MD5.7]=man7/EVP_MD-MD5.pod +DEPEND[html/man7/EVP_MD-MDC2.html]=man7/EVP_MD-MDC2.pod +GENERATE[html/man7/EVP_MD-MDC2.html]=man7/EVP_MD-MDC2.pod +DEPEND[man/man7/EVP_MD-MDC2.7]=man7/EVP_MD-MDC2.pod +GENERATE[man/man7/EVP_MD-MDC2.7]=man7/EVP_MD-MDC2.pod +DEPEND[html/man7/EVP_MD-NULL.html]=man7/EVP_MD-NULL.pod +GENERATE[html/man7/EVP_MD-NULL.html]=man7/EVP_MD-NULL.pod +DEPEND[man/man7/EVP_MD-NULL.7]=man7/EVP_MD-NULL.pod +GENERATE[man/man7/EVP_MD-NULL.7]=man7/EVP_MD-NULL.pod +DEPEND[html/man7/EVP_MD-RIPEMD160.html]=man7/EVP_MD-RIPEMD160.pod +GENERATE[html/man7/EVP_MD-RIPEMD160.html]=man7/EVP_MD-RIPEMD160.pod +DEPEND[man/man7/EVP_MD-RIPEMD160.7]=man7/EVP_MD-RIPEMD160.pod +GENERATE[man/man7/EVP_MD-RIPEMD160.7]=man7/EVP_MD-RIPEMD160.pod +DEPEND[html/man7/EVP_MD-SHA1.html]=man7/EVP_MD-SHA1.pod +GENERATE[html/man7/EVP_MD-SHA1.html]=man7/EVP_MD-SHA1.pod +DEPEND[man/man7/EVP_MD-SHA1.7]=man7/EVP_MD-SHA1.pod +GENERATE[man/man7/EVP_MD-SHA1.7]=man7/EVP_MD-SHA1.pod +DEPEND[html/man7/EVP_MD-SHA2.html]=man7/EVP_MD-SHA2.pod +GENERATE[html/man7/EVP_MD-SHA2.html]=man7/EVP_MD-SHA2.pod +DEPEND[man/man7/EVP_MD-SHA2.7]=man7/EVP_MD-SHA2.pod +GENERATE[man/man7/EVP_MD-SHA2.7]=man7/EVP_MD-SHA2.pod +DEPEND[html/man7/EVP_MD-SHA3.html]=man7/EVP_MD-SHA3.pod +GENERATE[html/man7/EVP_MD-SHA3.html]=man7/EVP_MD-SHA3.pod +DEPEND[man/man7/EVP_MD-SHA3.7]=man7/EVP_MD-SHA3.pod +GENERATE[man/man7/EVP_MD-SHA3.7]=man7/EVP_MD-SHA3.pod +DEPEND[html/man7/EVP_MD-SHAKE.html]=man7/EVP_MD-SHAKE.pod +GENERATE[html/man7/EVP_MD-SHAKE.html]=man7/EVP_MD-SHAKE.pod +DEPEND[man/man7/EVP_MD-SHAKE.7]=man7/EVP_MD-SHAKE.pod +GENERATE[man/man7/EVP_MD-SHAKE.7]=man7/EVP_MD-SHAKE.pod +DEPEND[html/man7/EVP_MD-SM3.html]=man7/EVP_MD-SM3.pod +GENERATE[html/man7/EVP_MD-SM3.html]=man7/EVP_MD-SM3.pod +DEPEND[man/man7/EVP_MD-SM3.7]=man7/EVP_MD-SM3.pod +GENERATE[man/man7/EVP_MD-SM3.7]=man7/EVP_MD-SM3.pod +DEPEND[html/man7/EVP_MD-WHIRLPOOL.html]=man7/EVP_MD-WHIRLPOOL.pod +GENERATE[html/man7/EVP_MD-WHIRLPOOL.html]=man7/EVP_MD-WHIRLPOOL.pod +DEPEND[man/man7/EVP_MD-WHIRLPOOL.7]=man7/EVP_MD-WHIRLPOOL.pod +GENERATE[man/man7/EVP_MD-WHIRLPOOL.7]=man7/EVP_MD-WHIRLPOOL.pod +DEPEND[html/man7/EVP_MD-common.html]=man7/EVP_MD-common.pod +GENERATE[html/man7/EVP_MD-common.html]=man7/EVP_MD-common.pod +DEPEND[man/man7/EVP_MD-common.7]=man7/EVP_MD-common.pod +GENERATE[man/man7/EVP_MD-common.7]=man7/EVP_MD-common.pod +DEPEND[html/man7/EVP_PKEY-DH.html]=man7/EVP_PKEY-DH.pod +GENERATE[html/man7/EVP_PKEY-DH.html]=man7/EVP_PKEY-DH.pod +DEPEND[man/man7/EVP_PKEY-DH.7]=man7/EVP_PKEY-DH.pod +GENERATE[man/man7/EVP_PKEY-DH.7]=man7/EVP_PKEY-DH.pod +DEPEND[html/man7/EVP_PKEY-DSA.html]=man7/EVP_PKEY-DSA.pod +GENERATE[html/man7/EVP_PKEY-DSA.html]=man7/EVP_PKEY-DSA.pod +DEPEND[man/man7/EVP_PKEY-DSA.7]=man7/EVP_PKEY-DSA.pod +GENERATE[man/man7/EVP_PKEY-DSA.7]=man7/EVP_PKEY-DSA.pod +DEPEND[html/man7/EVP_PKEY-EC.html]=man7/EVP_PKEY-EC.pod +GENERATE[html/man7/EVP_PKEY-EC.html]=man7/EVP_PKEY-EC.pod +DEPEND[man/man7/EVP_PKEY-EC.7]=man7/EVP_PKEY-EC.pod +GENERATE[man/man7/EVP_PKEY-EC.7]=man7/EVP_PKEY-EC.pod +DEPEND[html/man7/EVP_PKEY-FFC.html]=man7/EVP_PKEY-FFC.pod +GENERATE[html/man7/EVP_PKEY-FFC.html]=man7/EVP_PKEY-FFC.pod +DEPEND[man/man7/EVP_PKEY-FFC.7]=man7/EVP_PKEY-FFC.pod +GENERATE[man/man7/EVP_PKEY-FFC.7]=man7/EVP_PKEY-FFC.pod +DEPEND[html/man7/EVP_PKEY-HMAC.html]=man7/EVP_PKEY-HMAC.pod +GENERATE[html/man7/EVP_PKEY-HMAC.html]=man7/EVP_PKEY-HMAC.pod +DEPEND[man/man7/EVP_PKEY-HMAC.7]=man7/EVP_PKEY-HMAC.pod +GENERATE[man/man7/EVP_PKEY-HMAC.7]=man7/EVP_PKEY-HMAC.pod +DEPEND[html/man7/EVP_PKEY-RSA.html]=man7/EVP_PKEY-RSA.pod +GENERATE[html/man7/EVP_PKEY-RSA.html]=man7/EVP_PKEY-RSA.pod +DEPEND[man/man7/EVP_PKEY-RSA.7]=man7/EVP_PKEY-RSA.pod +GENERATE[man/man7/EVP_PKEY-RSA.7]=man7/EVP_PKEY-RSA.pod +DEPEND[html/man7/EVP_PKEY-SM2.html]=man7/EVP_PKEY-SM2.pod +GENERATE[html/man7/EVP_PKEY-SM2.html]=man7/EVP_PKEY-SM2.pod +DEPEND[man/man7/EVP_PKEY-SM2.7]=man7/EVP_PKEY-SM2.pod +GENERATE[man/man7/EVP_PKEY-SM2.7]=man7/EVP_PKEY-SM2.pod +DEPEND[html/man7/EVP_PKEY-X25519.html]=man7/EVP_PKEY-X25519.pod +GENERATE[html/man7/EVP_PKEY-X25519.html]=man7/EVP_PKEY-X25519.pod +DEPEND[man/man7/EVP_PKEY-X25519.7]=man7/EVP_PKEY-X25519.pod +GENERATE[man/man7/EVP_PKEY-X25519.7]=man7/EVP_PKEY-X25519.pod +DEPEND[html/man7/EVP_RAND-CTR-DRBG.html]=man7/EVP_RAND-CTR-DRBG.pod +GENERATE[html/man7/EVP_RAND-CTR-DRBG.html]=man7/EVP_RAND-CTR-DRBG.pod +DEPEND[man/man7/EVP_RAND-CTR-DRBG.7]=man7/EVP_RAND-CTR-DRBG.pod +GENERATE[man/man7/EVP_RAND-CTR-DRBG.7]=man7/EVP_RAND-CTR-DRBG.pod +DEPEND[html/man7/EVP_RAND-HASH-DRBG.html]=man7/EVP_RAND-HASH-DRBG.pod +GENERATE[html/man7/EVP_RAND-HASH-DRBG.html]=man7/EVP_RAND-HASH-DRBG.pod +DEPEND[man/man7/EVP_RAND-HASH-DRBG.7]=man7/EVP_RAND-HASH-DRBG.pod +GENERATE[man/man7/EVP_RAND-HASH-DRBG.7]=man7/EVP_RAND-HASH-DRBG.pod +DEPEND[html/man7/EVP_RAND-HMAC-DRBG.html]=man7/EVP_RAND-HMAC-DRBG.pod +GENERATE[html/man7/EVP_RAND-HMAC-DRBG.html]=man7/EVP_RAND-HMAC-DRBG.pod +DEPEND[man/man7/EVP_RAND-HMAC-DRBG.7]=man7/EVP_RAND-HMAC-DRBG.pod +GENERATE[man/man7/EVP_RAND-HMAC-DRBG.7]=man7/EVP_RAND-HMAC-DRBG.pod +DEPEND[html/man7/EVP_RAND-SEED-SRC.html]=man7/EVP_RAND-SEED-SRC.pod +GENERATE[html/man7/EVP_RAND-SEED-SRC.html]=man7/EVP_RAND-SEED-SRC.pod +DEPEND[man/man7/EVP_RAND-SEED-SRC.7]=man7/EVP_RAND-SEED-SRC.pod +GENERATE[man/man7/EVP_RAND-SEED-SRC.7]=man7/EVP_RAND-SEED-SRC.pod +DEPEND[html/man7/EVP_RAND-TEST-RAND.html]=man7/EVP_RAND-TEST-RAND.pod +GENERATE[html/man7/EVP_RAND-TEST-RAND.html]=man7/EVP_RAND-TEST-RAND.pod +DEPEND[man/man7/EVP_RAND-TEST-RAND.7]=man7/EVP_RAND-TEST-RAND.pod +GENERATE[man/man7/EVP_RAND-TEST-RAND.7]=man7/EVP_RAND-TEST-RAND.pod +DEPEND[html/man7/EVP_RAND.html]=man7/EVP_RAND.pod +GENERATE[html/man7/EVP_RAND.html]=man7/EVP_RAND.pod +DEPEND[man/man7/EVP_RAND.7]=man7/EVP_RAND.pod +GENERATE[man/man7/EVP_RAND.7]=man7/EVP_RAND.pod +DEPEND[html/man7/EVP_SIGNATURE-DSA.html]=man7/EVP_SIGNATURE-DSA.pod +GENERATE[html/man7/EVP_SIGNATURE-DSA.html]=man7/EVP_SIGNATURE-DSA.pod +DEPEND[man/man7/EVP_SIGNATURE-DSA.7]=man7/EVP_SIGNATURE-DSA.pod +GENERATE[man/man7/EVP_SIGNATURE-DSA.7]=man7/EVP_SIGNATURE-DSA.pod +DEPEND[html/man7/EVP_SIGNATURE-ECDSA.html]=man7/EVP_SIGNATURE-ECDSA.pod +GENERATE[html/man7/EVP_SIGNATURE-ECDSA.html]=man7/EVP_SIGNATURE-ECDSA.pod +DEPEND[man/man7/EVP_SIGNATURE-ECDSA.7]=man7/EVP_SIGNATURE-ECDSA.pod +GENERATE[man/man7/EVP_SIGNATURE-ECDSA.7]=man7/EVP_SIGNATURE-ECDSA.pod +DEPEND[html/man7/EVP_SIGNATURE-ED25519.html]=man7/EVP_SIGNATURE-ED25519.pod +GENERATE[html/man7/EVP_SIGNATURE-ED25519.html]=man7/EVP_SIGNATURE-ED25519.pod +DEPEND[man/man7/EVP_SIGNATURE-ED25519.7]=man7/EVP_SIGNATURE-ED25519.pod +GENERATE[man/man7/EVP_SIGNATURE-ED25519.7]=man7/EVP_SIGNATURE-ED25519.pod +DEPEND[html/man7/EVP_SIGNATURE-HMAC.html]=man7/EVP_SIGNATURE-HMAC.pod +GENERATE[html/man7/EVP_SIGNATURE-HMAC.html]=man7/EVP_SIGNATURE-HMAC.pod +DEPEND[man/man7/EVP_SIGNATURE-HMAC.7]=man7/EVP_SIGNATURE-HMAC.pod +GENERATE[man/man7/EVP_SIGNATURE-HMAC.7]=man7/EVP_SIGNATURE-HMAC.pod +DEPEND[html/man7/EVP_SIGNATURE-RSA.html]=man7/EVP_SIGNATURE-RSA.pod +GENERATE[html/man7/EVP_SIGNATURE-RSA.html]=man7/EVP_SIGNATURE-RSA.pod +DEPEND[man/man7/EVP_SIGNATURE-RSA.7]=man7/EVP_SIGNATURE-RSA.pod +GENERATE[man/man7/EVP_SIGNATURE-RSA.7]=man7/EVP_SIGNATURE-RSA.pod +DEPEND[html/man7/OSSL_PROVIDER-FIPS.html]=man7/OSSL_PROVIDER-FIPS.pod +GENERATE[html/man7/OSSL_PROVIDER-FIPS.html]=man7/OSSL_PROVIDER-FIPS.pod +DEPEND[man/man7/OSSL_PROVIDER-FIPS.7]=man7/OSSL_PROVIDER-FIPS.pod +GENERATE[man/man7/OSSL_PROVIDER-FIPS.7]=man7/OSSL_PROVIDER-FIPS.pod +DEPEND[html/man7/OSSL_PROVIDER-base.html]=man7/OSSL_PROVIDER-base.pod +GENERATE[html/man7/OSSL_PROVIDER-base.html]=man7/OSSL_PROVIDER-base.pod +DEPEND[man/man7/OSSL_PROVIDER-base.7]=man7/OSSL_PROVIDER-base.pod +GENERATE[man/man7/OSSL_PROVIDER-base.7]=man7/OSSL_PROVIDER-base.pod +DEPEND[html/man7/OSSL_PROVIDER-default.html]=man7/OSSL_PROVIDER-default.pod +GENERATE[html/man7/OSSL_PROVIDER-default.html]=man7/OSSL_PROVIDER-default.pod +DEPEND[man/man7/OSSL_PROVIDER-default.7]=man7/OSSL_PROVIDER-default.pod +GENERATE[man/man7/OSSL_PROVIDER-default.7]=man7/OSSL_PROVIDER-default.pod +DEPEND[html/man7/OSSL_PROVIDER-legacy.html]=man7/OSSL_PROVIDER-legacy.pod +GENERATE[html/man7/OSSL_PROVIDER-legacy.html]=man7/OSSL_PROVIDER-legacy.pod +DEPEND[man/man7/OSSL_PROVIDER-legacy.7]=man7/OSSL_PROVIDER-legacy.pod +GENERATE[man/man7/OSSL_PROVIDER-legacy.7]=man7/OSSL_PROVIDER-legacy.pod +DEPEND[html/man7/OSSL_PROVIDER-null.html]=man7/OSSL_PROVIDER-null.pod +GENERATE[html/man7/OSSL_PROVIDER-null.html]=man7/OSSL_PROVIDER-null.pod +DEPEND[man/man7/OSSL_PROVIDER-null.7]=man7/OSSL_PROVIDER-null.pod +GENERATE[man/man7/OSSL_PROVIDER-null.7]=man7/OSSL_PROVIDER-null.pod +DEPEND[html/man7/RAND.html]=man7/RAND.pod +GENERATE[html/man7/RAND.html]=man7/RAND.pod +DEPEND[man/man7/RAND.7]=man7/RAND.pod +GENERATE[man/man7/RAND.7]=man7/RAND.pod +DEPEND[html/man7/RSA-PSS.html]=man7/RSA-PSS.pod +GENERATE[html/man7/RSA-PSS.html]=man7/RSA-PSS.pod +DEPEND[man/man7/RSA-PSS.7]=man7/RSA-PSS.pod +GENERATE[man/man7/RSA-PSS.7]=man7/RSA-PSS.pod +DEPEND[html/man7/X25519.html]=man7/X25519.pod +GENERATE[html/man7/X25519.html]=man7/X25519.pod +DEPEND[man/man7/X25519.7]=man7/X25519.pod +GENERATE[man/man7/X25519.7]=man7/X25519.pod +DEPEND[html/man7/bio.html]=man7/bio.pod +GENERATE[html/man7/bio.html]=man7/bio.pod +DEPEND[man/man7/bio.7]=man7/bio.pod +GENERATE[man/man7/bio.7]=man7/bio.pod +DEPEND[html/man7/crypto.html]=man7/crypto.pod +GENERATE[html/man7/crypto.html]=man7/crypto.pod +DEPEND[man/man7/crypto.7]=man7/crypto.pod +GENERATE[man/man7/crypto.7]=man7/crypto.pod +DEPEND[html/man7/ct.html]=man7/ct.pod +GENERATE[html/man7/ct.html]=man7/ct.pod +DEPEND[man/man7/ct.7]=man7/ct.pod +GENERATE[man/man7/ct.7]=man7/ct.pod +DEPEND[html/man7/des_modes.html]=man7/des_modes.pod +GENERATE[html/man7/des_modes.html]=man7/des_modes.pod +DEPEND[man/man7/des_modes.7]=man7/des_modes.pod +GENERATE[man/man7/des_modes.7]=man7/des_modes.pod +DEPEND[html/man7/evp.html]=man7/evp.pod +GENERATE[html/man7/evp.html]=man7/evp.pod +DEPEND[man/man7/evp.7]=man7/evp.pod +GENERATE[man/man7/evp.7]=man7/evp.pod +DEPEND[html/man7/fips_module.html]=man7/fips_module.pod +GENERATE[html/man7/fips_module.html]=man7/fips_module.pod +DEPEND[man/man7/fips_module.7]=man7/fips_module.pod +GENERATE[man/man7/fips_module.7]=man7/fips_module.pod +DEPEND[html/man7/life_cycle-cipher.html]=man7/life_cycle-cipher.pod +GENERATE[html/man7/life_cycle-cipher.html]=man7/life_cycle-cipher.pod +DEPEND[man/man7/life_cycle-cipher.7]=man7/life_cycle-cipher.pod +GENERATE[man/man7/life_cycle-cipher.7]=man7/life_cycle-cipher.pod +DEPEND[html/man7/life_cycle-digest.html]=man7/life_cycle-digest.pod +GENERATE[html/man7/life_cycle-digest.html]=man7/life_cycle-digest.pod +DEPEND[man/man7/life_cycle-digest.7]=man7/life_cycle-digest.pod +GENERATE[man/man7/life_cycle-digest.7]=man7/life_cycle-digest.pod +DEPEND[html/man7/life_cycle-kdf.html]=man7/life_cycle-kdf.pod +GENERATE[html/man7/life_cycle-kdf.html]=man7/life_cycle-kdf.pod +DEPEND[man/man7/life_cycle-kdf.7]=man7/life_cycle-kdf.pod +GENERATE[man/man7/life_cycle-kdf.7]=man7/life_cycle-kdf.pod +DEPEND[html/man7/life_cycle-mac.html]=man7/life_cycle-mac.pod +GENERATE[html/man7/life_cycle-mac.html]=man7/life_cycle-mac.pod +DEPEND[man/man7/life_cycle-mac.7]=man7/life_cycle-mac.pod +GENERATE[man/man7/life_cycle-mac.7]=man7/life_cycle-mac.pod +DEPEND[html/man7/life_cycle-pkey.html]=man7/life_cycle-pkey.pod +GENERATE[html/man7/life_cycle-pkey.html]=man7/life_cycle-pkey.pod +DEPEND[man/man7/life_cycle-pkey.7]=man7/life_cycle-pkey.pod +GENERATE[man/man7/life_cycle-pkey.7]=man7/life_cycle-pkey.pod +DEPEND[html/man7/life_cycle-rand.html]=man7/life_cycle-rand.pod +GENERATE[html/man7/life_cycle-rand.html]=man7/life_cycle-rand.pod +DEPEND[man/man7/life_cycle-rand.7]=man7/life_cycle-rand.pod +GENERATE[man/man7/life_cycle-rand.7]=man7/life_cycle-rand.pod +DEPEND[html/man7/migration_guide.html]=man7/migration_guide.pod +GENERATE[html/man7/migration_guide.html]=man7/migration_guide.pod +DEPEND[man/man7/migration_guide.7]=man7/migration_guide.pod +GENERATE[man/man7/migration_guide.7]=man7/migration_guide.pod +DEPEND[html/man7/openssl-core.h.html]=man7/openssl-core.h.pod +GENERATE[html/man7/openssl-core.h.html]=man7/openssl-core.h.pod +DEPEND[man/man7/openssl-core.h.7]=man7/openssl-core.h.pod +GENERATE[man/man7/openssl-core.h.7]=man7/openssl-core.h.pod +DEPEND[html/man7/openssl-core_dispatch.h.html]=man7/openssl-core_dispatch.h.pod +GENERATE[html/man7/openssl-core_dispatch.h.html]=man7/openssl-core_dispatch.h.pod +DEPEND[man/man7/openssl-core_dispatch.h.7]=man7/openssl-core_dispatch.h.pod +GENERATE[man/man7/openssl-core_dispatch.h.7]=man7/openssl-core_dispatch.h.pod +DEPEND[html/man7/openssl-core_names.h.html]=man7/openssl-core_names.h.pod +GENERATE[html/man7/openssl-core_names.h.html]=man7/openssl-core_names.h.pod +DEPEND[man/man7/openssl-core_names.h.7]=man7/openssl-core_names.h.pod +GENERATE[man/man7/openssl-core_names.h.7]=man7/openssl-core_names.h.pod +DEPEND[html/man7/openssl-env.html]=man7/openssl-env.pod +GENERATE[html/man7/openssl-env.html]=man7/openssl-env.pod +DEPEND[man/man7/openssl-env.7]=man7/openssl-env.pod +GENERATE[man/man7/openssl-env.7]=man7/openssl-env.pod +DEPEND[html/man7/openssl-glossary.html]=man7/openssl-glossary.pod +GENERATE[html/man7/openssl-glossary.html]=man7/openssl-glossary.pod +DEPEND[man/man7/openssl-glossary.7]=man7/openssl-glossary.pod +GENERATE[man/man7/openssl-glossary.7]=man7/openssl-glossary.pod +DEPEND[html/man7/openssl-threads.html]=man7/openssl-threads.pod +GENERATE[html/man7/openssl-threads.html]=man7/openssl-threads.pod +DEPEND[man/man7/openssl-threads.7]=man7/openssl-threads.pod +GENERATE[man/man7/openssl-threads.7]=man7/openssl-threads.pod +DEPEND[html/man7/openssl_user_macros.html]=man7/openssl_user_macros.pod +GENERATE[html/man7/openssl_user_macros.html]=man7/openssl_user_macros.pod +DEPEND[man/man7/openssl_user_macros.7]=man7/openssl_user_macros.pod +GENERATE[man/man7/openssl_user_macros.7]=man7/openssl_user_macros.pod +DEPEND[man7/openssl_user_macros.pod]{pod}=man7/openssl_user_macros.pod.in +GENERATE[man7/openssl_user_macros.pod]=man7/openssl_user_macros.pod.in +DEPEND[html/man7/ossl_store-file.html]=man7/ossl_store-file.pod +GENERATE[html/man7/ossl_store-file.html]=man7/ossl_store-file.pod +DEPEND[man/man7/ossl_store-file.7]=man7/ossl_store-file.pod +GENERATE[man/man7/ossl_store-file.7]=man7/ossl_store-file.pod +DEPEND[html/man7/ossl_store.html]=man7/ossl_store.pod +GENERATE[html/man7/ossl_store.html]=man7/ossl_store.pod +DEPEND[man/man7/ossl_store.7]=man7/ossl_store.pod +GENERATE[man/man7/ossl_store.7]=man7/ossl_store.pod +DEPEND[html/man7/passphrase-encoding.html]=man7/passphrase-encoding.pod +GENERATE[html/man7/passphrase-encoding.html]=man7/passphrase-encoding.pod +DEPEND[man/man7/passphrase-encoding.7]=man7/passphrase-encoding.pod +GENERATE[man/man7/passphrase-encoding.7]=man7/passphrase-encoding.pod +DEPEND[html/man7/property.html]=man7/property.pod +GENERATE[html/man7/property.html]=man7/property.pod +DEPEND[man/man7/property.7]=man7/property.pod +GENERATE[man/man7/property.7]=man7/property.pod +DEPEND[html/man7/provider-asym_cipher.html]=man7/provider-asym_cipher.pod +GENERATE[html/man7/provider-asym_cipher.html]=man7/provider-asym_cipher.pod +DEPEND[man/man7/provider-asym_cipher.7]=man7/provider-asym_cipher.pod +GENERATE[man/man7/provider-asym_cipher.7]=man7/provider-asym_cipher.pod +DEPEND[html/man7/provider-base.html]=man7/provider-base.pod +GENERATE[html/man7/provider-base.html]=man7/provider-base.pod +DEPEND[man/man7/provider-base.7]=man7/provider-base.pod +GENERATE[man/man7/provider-base.7]=man7/provider-base.pod +DEPEND[html/man7/provider-cipher.html]=man7/provider-cipher.pod +GENERATE[html/man7/provider-cipher.html]=man7/provider-cipher.pod +DEPEND[man/man7/provider-cipher.7]=man7/provider-cipher.pod +GENERATE[man/man7/provider-cipher.7]=man7/provider-cipher.pod +DEPEND[html/man7/provider-decoder.html]=man7/provider-decoder.pod +GENERATE[html/man7/provider-decoder.html]=man7/provider-decoder.pod +DEPEND[man/man7/provider-decoder.7]=man7/provider-decoder.pod +GENERATE[man/man7/provider-decoder.7]=man7/provider-decoder.pod +DEPEND[html/man7/provider-digest.html]=man7/provider-digest.pod +GENERATE[html/man7/provider-digest.html]=man7/provider-digest.pod +DEPEND[man/man7/provider-digest.7]=man7/provider-digest.pod +GENERATE[man/man7/provider-digest.7]=man7/provider-digest.pod +DEPEND[html/man7/provider-encoder.html]=man7/provider-encoder.pod +GENERATE[html/man7/provider-encoder.html]=man7/provider-encoder.pod +DEPEND[man/man7/provider-encoder.7]=man7/provider-encoder.pod +GENERATE[man/man7/provider-encoder.7]=man7/provider-encoder.pod +DEPEND[html/man7/provider-kdf.html]=man7/provider-kdf.pod +GENERATE[html/man7/provider-kdf.html]=man7/provider-kdf.pod +DEPEND[man/man7/provider-kdf.7]=man7/provider-kdf.pod +GENERATE[man/man7/provider-kdf.7]=man7/provider-kdf.pod +DEPEND[html/man7/provider-kem.html]=man7/provider-kem.pod +GENERATE[html/man7/provider-kem.html]=man7/provider-kem.pod +DEPEND[man/man7/provider-kem.7]=man7/provider-kem.pod +GENERATE[man/man7/provider-kem.7]=man7/provider-kem.pod +DEPEND[html/man7/provider-keyexch.html]=man7/provider-keyexch.pod +GENERATE[html/man7/provider-keyexch.html]=man7/provider-keyexch.pod +DEPEND[man/man7/provider-keyexch.7]=man7/provider-keyexch.pod +GENERATE[man/man7/provider-keyexch.7]=man7/provider-keyexch.pod +DEPEND[html/man7/provider-keymgmt.html]=man7/provider-keymgmt.pod +GENERATE[html/man7/provider-keymgmt.html]=man7/provider-keymgmt.pod +DEPEND[man/man7/provider-keymgmt.7]=man7/provider-keymgmt.pod +GENERATE[man/man7/provider-keymgmt.7]=man7/provider-keymgmt.pod +DEPEND[html/man7/provider-mac.html]=man7/provider-mac.pod +GENERATE[html/man7/provider-mac.html]=man7/provider-mac.pod +DEPEND[man/man7/provider-mac.7]=man7/provider-mac.pod +GENERATE[man/man7/provider-mac.7]=man7/provider-mac.pod +DEPEND[html/man7/provider-object.html]=man7/provider-object.pod +GENERATE[html/man7/provider-object.html]=man7/provider-object.pod +DEPEND[man/man7/provider-object.7]=man7/provider-object.pod +GENERATE[man/man7/provider-object.7]=man7/provider-object.pod +DEPEND[html/man7/provider-rand.html]=man7/provider-rand.pod +GENERATE[html/man7/provider-rand.html]=man7/provider-rand.pod +DEPEND[man/man7/provider-rand.7]=man7/provider-rand.pod +GENERATE[man/man7/provider-rand.7]=man7/provider-rand.pod +DEPEND[html/man7/provider-signature.html]=man7/provider-signature.pod +GENERATE[html/man7/provider-signature.html]=man7/provider-signature.pod +DEPEND[man/man7/provider-signature.7]=man7/provider-signature.pod +GENERATE[man/man7/provider-signature.7]=man7/provider-signature.pod +DEPEND[html/man7/provider-storemgmt.html]=man7/provider-storemgmt.pod +GENERATE[html/man7/provider-storemgmt.html]=man7/provider-storemgmt.pod +DEPEND[man/man7/provider-storemgmt.7]=man7/provider-storemgmt.pod +GENERATE[man/man7/provider-storemgmt.7]=man7/provider-storemgmt.pod +DEPEND[html/man7/provider.html]=man7/provider.pod +GENERATE[html/man7/provider.html]=man7/provider.pod +DEPEND[man/man7/provider.7]=man7/provider.pod +GENERATE[man/man7/provider.7]=man7/provider.pod +DEPEND[html/man7/proxy-certificates.html]=man7/proxy-certificates.pod +GENERATE[html/man7/proxy-certificates.html]=man7/proxy-certificates.pod +DEPEND[man/man7/proxy-certificates.7]=man7/proxy-certificates.pod +GENERATE[man/man7/proxy-certificates.7]=man7/proxy-certificates.pod +DEPEND[html/man7/ssl.html]=man7/ssl.pod +GENERATE[html/man7/ssl.html]=man7/ssl.pod +DEPEND[man/man7/ssl.7]=man7/ssl.pod +GENERATE[man/man7/ssl.7]=man7/ssl.pod +DEPEND[html/man7/x509.html]=man7/x509.pod +GENERATE[html/man7/x509.html]=man7/x509.pod +DEPEND[man/man7/x509.7]=man7/x509.pod +GENERATE[man/man7/x509.7]=man7/x509.pod +IMAGEDOCS[man7]=man7/img/cipher.png \ +man7/img/digest.png \ +man7/img/kdf.png \ +man7/img/mac.png \ +man7/img/pkey.png \ +man7/img/rand.png +HTMLDOCS[man7]=html/man7/EVP_ASYM_CIPHER-RSA.html \ +html/man7/EVP_ASYM_CIPHER-SM2.html \ +html/man7/EVP_CIPHER-AES.html \ +html/man7/EVP_CIPHER-ARIA.html \ +html/man7/EVP_CIPHER-BLOWFISH.html \ +html/man7/EVP_CIPHER-CAMELLIA.html \ +html/man7/EVP_CIPHER-CAST.html \ +html/man7/EVP_CIPHER-CHACHA.html \ +html/man7/EVP_CIPHER-DES.html \ +html/man7/EVP_CIPHER-IDEA.html \ +html/man7/EVP_CIPHER-NULL.html \ +html/man7/EVP_CIPHER-RC2.html \ +html/man7/EVP_CIPHER-RC4.html \ +html/man7/EVP_CIPHER-RC5.html \ +html/man7/EVP_CIPHER-SEED.html \ +html/man7/EVP_CIPHER-SM4.html \ +html/man7/EVP_KDF-HKDF.html \ +html/man7/EVP_KDF-KB.html \ +html/man7/EVP_KDF-KRB5KDF.html \ +html/man7/EVP_KDF-PBKDF1.html \ +html/man7/EVP_KDF-PBKDF2.html \ +html/man7/EVP_KDF-PKCS12KDF.html \ +html/man7/EVP_KDF-SCRYPT.html \ +html/man7/EVP_KDF-SS.html \ +html/man7/EVP_KDF-SSHKDF.html \ +html/man7/EVP_KDF-TLS13_KDF.html \ +html/man7/EVP_KDF-TLS1_PRF.html \ +html/man7/EVP_KDF-X942-ASN1.html \ +html/man7/EVP_KDF-X942-CONCAT.html \ +html/man7/EVP_KDF-X963.html \ +html/man7/EVP_KEM-RSA.html \ +html/man7/EVP_KEYEXCH-DH.html \ +html/man7/EVP_KEYEXCH-ECDH.html \ +html/man7/EVP_KEYEXCH-X25519.html \ +html/man7/EVP_MAC-BLAKE2.html \ +html/man7/EVP_MAC-CMAC.html \ +html/man7/EVP_MAC-GMAC.html \ +html/man7/EVP_MAC-HMAC.html \ +html/man7/EVP_MAC-KMAC.html \ +html/man7/EVP_MAC-Poly1305.html \ +html/man7/EVP_MAC-Siphash.html \ +html/man7/EVP_MD-BLAKE2.html \ +html/man7/EVP_MD-MD2.html \ +html/man7/EVP_MD-MD4.html \ +html/man7/EVP_MD-MD5-SHA1.html \ +html/man7/EVP_MD-MD5.html \ +html/man7/EVP_MD-MDC2.html \ +html/man7/EVP_MD-NULL.html \ +html/man7/EVP_MD-RIPEMD160.html \ +html/man7/EVP_MD-SHA1.html \ +html/man7/EVP_MD-SHA2.html \ +html/man7/EVP_MD-SHA3.html \ +html/man7/EVP_MD-SHAKE.html \ +html/man7/EVP_MD-SM3.html \ +html/man7/EVP_MD-WHIRLPOOL.html \ +html/man7/EVP_MD-common.html \ +html/man7/EVP_PKEY-DH.html \ +html/man7/EVP_PKEY-DSA.html \ +html/man7/EVP_PKEY-EC.html \ +html/man7/EVP_PKEY-FFC.html \ +html/man7/EVP_PKEY-HMAC.html \ +html/man7/EVP_PKEY-RSA.html \ +html/man7/EVP_PKEY-SM2.html \ +html/man7/EVP_PKEY-X25519.html \ +html/man7/EVP_RAND-CTR-DRBG.html \ +html/man7/EVP_RAND-HASH-DRBG.html \ +html/man7/EVP_RAND-HMAC-DRBG.html \ +html/man7/EVP_RAND-SEED-SRC.html \ +html/man7/EVP_RAND-TEST-RAND.html \ +html/man7/EVP_RAND.html \ +html/man7/EVP_SIGNATURE-DSA.html \ +html/man7/EVP_SIGNATURE-ECDSA.html \ +html/man7/EVP_SIGNATURE-ED25519.html \ +html/man7/EVP_SIGNATURE-HMAC.html \ +html/man7/EVP_SIGNATURE-RSA.html \ +html/man7/OSSL_PROVIDER-FIPS.html \ +html/man7/OSSL_PROVIDER-base.html \ +html/man7/OSSL_PROVIDER-default.html \ +html/man7/OSSL_PROVIDER-legacy.html \ +html/man7/OSSL_PROVIDER-null.html \ +html/man7/RAND.html \ +html/man7/RSA-PSS.html \ +html/man7/X25519.html \ +html/man7/bio.html \ +html/man7/crypto.html \ +html/man7/ct.html \ +html/man7/des_modes.html \ +html/man7/evp.html \ +html/man7/fips_module.html \ +html/man7/life_cycle-cipher.html \ +html/man7/life_cycle-digest.html \ +html/man7/life_cycle-kdf.html \ +html/man7/life_cycle-mac.html \ +html/man7/life_cycle-pkey.html \ +html/man7/life_cycle-rand.html \ +html/man7/migration_guide.html \ +html/man7/openssl-core.h.html \ +html/man7/openssl-core_dispatch.h.html \ +html/man7/openssl-core_names.h.html \ +html/man7/openssl-env.html \ +html/man7/openssl-glossary.html \ +html/man7/openssl-threads.html \ +html/man7/openssl_user_macros.html \ +html/man7/ossl_store-file.html \ +html/man7/ossl_store.html \ +html/man7/passphrase-encoding.html \ +html/man7/property.html \ +html/man7/provider-asym_cipher.html \ +html/man7/provider-base.html \ +html/man7/provider-cipher.html \ +html/man7/provider-decoder.html \ +html/man7/provider-digest.html \ +html/man7/provider-encoder.html \ +html/man7/provider-kdf.html \ +html/man7/provider-kem.html \ +html/man7/provider-keyexch.html \ +html/man7/provider-keymgmt.html \ +html/man7/provider-mac.html \ +html/man7/provider-object.html \ +html/man7/provider-rand.html \ +html/man7/provider-signature.html \ +html/man7/provider-storemgmt.html \ +html/man7/provider.html \ +html/man7/proxy-certificates.html \ +html/man7/ssl.html \ +html/man7/x509.html +MANDOCS[man7]=man/man7/EVP_ASYM_CIPHER-RSA.7 \ +man/man7/EVP_ASYM_CIPHER-SM2.7 \ +man/man7/EVP_CIPHER-AES.7 \ +man/man7/EVP_CIPHER-ARIA.7 \ +man/man7/EVP_CIPHER-BLOWFISH.7 \ +man/man7/EVP_CIPHER-CAMELLIA.7 \ +man/man7/EVP_CIPHER-CAST.7 \ +man/man7/EVP_CIPHER-CHACHA.7 \ +man/man7/EVP_CIPHER-DES.7 \ +man/man7/EVP_CIPHER-IDEA.7 \ +man/man7/EVP_CIPHER-NULL.7 \ +man/man7/EVP_CIPHER-RC2.7 \ +man/man7/EVP_CIPHER-RC4.7 \ +man/man7/EVP_CIPHER-RC5.7 \ +man/man7/EVP_CIPHER-SEED.7 \ +man/man7/EVP_CIPHER-SM4.7 \ +man/man7/EVP_KDF-HKDF.7 \ +man/man7/EVP_KDF-KB.7 \ +man/man7/EVP_KDF-KRB5KDF.7 \ +man/man7/EVP_KDF-PBKDF1.7 \ +man/man7/EVP_KDF-PBKDF2.7 \ +man/man7/EVP_KDF-PKCS12KDF.7 \ +man/man7/EVP_KDF-SCRYPT.7 \ +man/man7/EVP_KDF-SS.7 \ +man/man7/EVP_KDF-SSHKDF.7 \ +man/man7/EVP_KDF-TLS13_KDF.7 \ +man/man7/EVP_KDF-TLS1_PRF.7 \ +man/man7/EVP_KDF-X942-ASN1.7 \ +man/man7/EVP_KDF-X942-CONCAT.7 \ +man/man7/EVP_KDF-X963.7 \ +man/man7/EVP_KEM-RSA.7 \ +man/man7/EVP_KEYEXCH-DH.7 \ +man/man7/EVP_KEYEXCH-ECDH.7 \ +man/man7/EVP_KEYEXCH-X25519.7 \ +man/man7/EVP_MAC-BLAKE2.7 \ +man/man7/EVP_MAC-CMAC.7 \ +man/man7/EVP_MAC-GMAC.7 \ +man/man7/EVP_MAC-HMAC.7 \ +man/man7/EVP_MAC-KMAC.7 \ +man/man7/EVP_MAC-Poly1305.7 \ +man/man7/EVP_MAC-Siphash.7 \ +man/man7/EVP_MD-BLAKE2.7 \ +man/man7/EVP_MD-MD2.7 \ +man/man7/EVP_MD-MD4.7 \ +man/man7/EVP_MD-MD5-SHA1.7 \ +man/man7/EVP_MD-MD5.7 \ +man/man7/EVP_MD-MDC2.7 \ +man/man7/EVP_MD-NULL.7 \ +man/man7/EVP_MD-RIPEMD160.7 \ +man/man7/EVP_MD-SHA1.7 \ +man/man7/EVP_MD-SHA2.7 \ +man/man7/EVP_MD-SHA3.7 \ +man/man7/EVP_MD-SHAKE.7 \ +man/man7/EVP_MD-SM3.7 \ +man/man7/EVP_MD-WHIRLPOOL.7 \ +man/man7/EVP_MD-common.7 \ +man/man7/EVP_PKEY-DH.7 \ +man/man7/EVP_PKEY-DSA.7 \ +man/man7/EVP_PKEY-EC.7 \ +man/man7/EVP_PKEY-FFC.7 \ +man/man7/EVP_PKEY-HMAC.7 \ +man/man7/EVP_PKEY-RSA.7 \ +man/man7/EVP_PKEY-SM2.7 \ +man/man7/EVP_PKEY-X25519.7 \ +man/man7/EVP_RAND-CTR-DRBG.7 \ +man/man7/EVP_RAND-HASH-DRBG.7 \ +man/man7/EVP_RAND-HMAC-DRBG.7 \ +man/man7/EVP_RAND-SEED-SRC.7 \ +man/man7/EVP_RAND-TEST-RAND.7 \ +man/man7/EVP_RAND.7 \ +man/man7/EVP_SIGNATURE-DSA.7 \ +man/man7/EVP_SIGNATURE-ECDSA.7 \ +man/man7/EVP_SIGNATURE-ED25519.7 \ +man/man7/EVP_SIGNATURE-HMAC.7 \ +man/man7/EVP_SIGNATURE-RSA.7 \ +man/man7/OSSL_PROVIDER-FIPS.7 \ +man/man7/OSSL_PROVIDER-base.7 \ +man/man7/OSSL_PROVIDER-default.7 \ +man/man7/OSSL_PROVIDER-legacy.7 \ +man/man7/OSSL_PROVIDER-null.7 \ +man/man7/RAND.7 \ +man/man7/RSA-PSS.7 \ +man/man7/X25519.7 \ +man/man7/bio.7 \ +man/man7/crypto.7 \ +man/man7/ct.7 \ +man/man7/des_modes.7 \ +man/man7/evp.7 \ +man/man7/fips_module.7 \ +man/man7/life_cycle-cipher.7 \ +man/man7/life_cycle-digest.7 \ +man/man7/life_cycle-kdf.7 \ +man/man7/life_cycle-mac.7 \ +man/man7/life_cycle-pkey.7 \ +man/man7/life_cycle-rand.7 \ +man/man7/migration_guide.7 \ +man/man7/openssl-core.h.7 \ +man/man7/openssl-core_dispatch.h.7 \ +man/man7/openssl-core_names.h.7 \ +man/man7/openssl-env.7 \ +man/man7/openssl-glossary.7 \ +man/man7/openssl-threads.7 \ +man/man7/openssl_user_macros.7 \ +man/man7/ossl_store-file.7 \ +man/man7/ossl_store.7 \ +man/man7/passphrase-encoding.7 \ +man/man7/property.7 \ +man/man7/provider-asym_cipher.7 \ +man/man7/provider-base.7 \ +man/man7/provider-cipher.7 \ +man/man7/provider-decoder.7 \ +man/man7/provider-digest.7 \ +man/man7/provider-encoder.7 \ +man/man7/provider-kdf.7 \ +man/man7/provider-kem.7 \ +man/man7/provider-keyexch.7 \ +man/man7/provider-keymgmt.7 \ +man/man7/provider-mac.7 \ +man/man7/provider-object.7 \ +man/man7/provider-rand.7 \ +man/man7/provider-signature.7 \ +man/man7/provider-storemgmt.7 \ +man/man7/provider.7 \ +man/man7/proxy-certificates.7 \ +man/man7/ssl.7 \ +man/man7/x509.7 + diff --git a/deps/openssl/openssl/doc/man1/build.info b/deps/openssl/openssl/doc/man1/build.info new file mode 100644 index 00000000000000..b796fce42fdd90 --- /dev/null +++ b/deps/openssl/openssl/doc/man1/build.info @@ -0,0 +1,57 @@ +# All .pod.in files are detected by build.info in the parent directory, and +# turned into appropriate DEPEND and GENERATE lines. All we need here are +# the additional dependencies on ../perlvars.pm. + +DEPEND[openssl-asn1parse.pod]=../perlvars.pm +DEPEND[openssl-ca.pod]=../perlvars.pm +DEPEND[openssl-ciphers.pod]=../perlvars.pm +DEPEND[openssl-cmds.pod]=../perlvars.pm +DEPEND[openssl-cmp.pod]=../perlvars.pm +DEPEND[openssl-cms.pod]=../perlvars.pm +DEPEND[openssl-crl2pkcs7.pod]=../perlvars.pm +DEPEND[openssl-crl.pod]=../perlvars.pm +DEPEND[openssl-dgst.pod]=../perlvars.pm +DEPEND[openssl-dhparam.pod]=../perlvars.pm +DEPEND[openssl-dsaparam.pod]=../perlvars.pm +DEPEND[openssl-dsa.pod]=../perlvars.pm +DEPEND[openssl-ecparam.pod]=../perlvars.pm +DEPEND[openssl-ec.pod]=../perlvars.pm +DEPEND[openssl-enc.pod]=../perlvars.pm +DEPEND[openssl-engine.pod]=../perlvars.pm +DEPEND[openssl-errstr.pod]=../perlvars.pm +DEPEND[openssl-fipsinstall.pod]=../perlvars.pm +DEPEND[openssl-gendsa.pod]=../perlvars.pm +DEPEND[openssl-genpkey.pod]=../perlvars.pm +DEPEND[openssl-genrsa.pod]=../perlvars.pm +DEPEND[openssl-info.pod]=../perlvars.pm +DEPEND[openssl-kdf.pod]=../perlvars.pm +DEPEND[openssl-list.pod]=../perlvars.pm +DEPEND[openssl-mac.pod]=../perlvars.pm +DEPEND[openssl-nseq.pod]=../perlvars.pm +DEPEND[openssl-ocsp.pod]=../perlvars.pm +DEPEND[openssl-passwd.pod]=../perlvars.pm +DEPEND[openssl-pkcs12.pod]=../perlvars.pm +DEPEND[openssl-pkcs7.pod]=../perlvars.pm +DEPEND[openssl-pkcs8.pod]=../perlvars.pm +DEPEND[openssl-pkeyparam.pod]=../perlvars.pm +DEPEND[openssl-pkey.pod]=../perlvars.pm +DEPEND[openssl-pkeyutl.pod]=../perlvars.pm +DEPEND[openssl-prime.pod]=../perlvars.pm +DEPEND[openssl-rand.pod]=../perlvars.pm +DEPEND[openssl-rehash.pod]=../perlvars.pm +DEPEND[openssl-req.pod]=../perlvars.pm +DEPEND[openssl-rsa.pod]=../perlvars.pm +DEPEND[openssl-rsautl.pod]=../perlvars.pm +DEPEND[openssl-s_client.pod]=../perlvars.pm +DEPEND[openssl-sess_id.pod]=../perlvars.pm +DEPEND[openssl-smime.pod]=../perlvars.pm +DEPEND[openssl-speed.pod]=../perlvars.pm +DEPEND[openssl-spkac.pod]=../perlvars.pm +DEPEND[openssl-srp.pod]=../perlvars.pm +DEPEND[openssl-s_server.pod]=../perlvars.pm +DEPEND[openssl-s_time.pod]=../perlvars.pm +DEPEND[openssl-storeutl.pod]=../perlvars.pm +DEPEND[openssl-ts.pod]=../perlvars.pm +DEPEND[openssl-verify.pod]=../perlvars.pm +DEPEND[openssl-version.pod]=../perlvars.pm +DEPEND[openssl-x509.pod]=../perlvars.pm diff --git a/deps/openssl/openssl_asm.gypi b/deps/openssl/openssl_asm.gypi index dd7e636eb08893..51631c536bbbef 100644 --- a/deps/openssl/openssl_asm.gypi +++ b/deps/openssl/openssl_asm.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/asm/openssl.gypi'], }, 'target_arch=="arm" and OS=="linux"', { 'includes': ['config/archs/linux-armv4/asm/openssl.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in "linux openharmony"', { 'includes': ['config/archs/linux-aarch64/asm/openssl.gypi'], }, 'target_arch=="arm64" and OS=="mac"', { 'includes': ['config/archs/darwin64-arm64-cc/asm/openssl.gypi'], diff --git a/deps/openssl/openssl_asm_avx2.gypi b/deps/openssl/openssl_asm_avx2.gypi index 6a9c56d76a211a..a6e69b71524366 100644 --- a/deps/openssl/openssl_asm_avx2.gypi +++ b/deps/openssl/openssl_asm_avx2.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/asm_avx2/openssl.gypi'], }, 'target_arch=="arm" and OS=="linux"', { 'includes': ['config/archs/linux-armv4/asm_avx2/openssl.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in ("linux", "openharmony")', { 'includes': ['config/archs/linux-aarch64/asm_avx2/openssl.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/asm_avx2/openssl.gypi'], diff --git a/deps/openssl/openssl_no_asm.gypi b/deps/openssl/openssl_no_asm.gypi index 20663decabba23..8169f605d7d7f1 100644 --- a/deps/openssl/openssl_no_asm.gypi +++ b/deps/openssl/openssl_no_asm.gypi @@ -9,7 +9,7 @@ 'includes': ['config/archs/linux64-s390x/no-asm/openssl.gypi'], }, 'target_arch=="arm" and OS in ("linux", "android")', { 'includes': ['config/archs/linux-armv4/no-asm/openssl.gypi'], - }, 'target_arch=="arm64" and OS in ("linux", "android")', { + }, 'target_arch=="arm64" and OS in ("linux", "android", "openharmony")', { 'includes': ['config/archs/linux-aarch64/no-asm/openssl.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/no-asm/openssl.gypi'], diff --git a/deps/simdjson/simdjson.cpp b/deps/simdjson/simdjson.cpp index aaeca3fadde29b..d0f441b5a5401d 100644 --- a/deps/simdjson/simdjson.cpp +++ b/deps/simdjson/simdjson.cpp @@ -1,4 +1,4 @@ -/* auto-generated on 2025-02-14 16:11:36 -0500. Do not edit! */ +/* auto-generated on 2025-03-27 15:01:10 -0400. Do not edit! */ /* including simdjson.cpp: */ /* begin file simdjson.cpp */ #define SIMDJSON_SRC_SIMDJSON_CPP @@ -776,22 +776,22 @@ inline namespace literals { inline namespace string_view_literals { -constexpr std::string_view operator "" _sv( const char* str, size_t len ) noexcept // (1) +constexpr std::string_view operator ""_sv( const char* str, size_t len ) noexcept // (1) { return std::string_view{ str, len }; } -constexpr std::u16string_view operator "" _sv( const char16_t* str, size_t len ) noexcept // (2) +constexpr std::u16string_view operator ""_sv( const char16_t* str, size_t len ) noexcept // (2) { return std::u16string_view{ str, len }; } -constexpr std::u32string_view operator "" _sv( const char32_t* str, size_t len ) noexcept // (3) +constexpr std::u32string_view operator ""_sv( const char32_t* str, size_t len ) noexcept // (3) { return std::u32string_view{ str, len }; } -constexpr std::wstring_view operator "" _sv( const wchar_t* str, size_t len ) noexcept // (4) +constexpr std::wstring_view operator ""_sv( const wchar_t* str, size_t len ) noexcept // (4) { return std::wstring_view{ str, len }; } @@ -2122,22 +2122,22 @@ nssv_inline_ns namespace string_view_literals { #if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS -nssv_constexpr nonstd::sv_lite::string_view operator "" sv( const char* str, size_t len ) nssv_noexcept // (1) +nssv_constexpr nonstd::sv_lite::string_view operator ""sv( const char* str, size_t len ) nssv_noexcept // (1) { return nonstd::sv_lite::string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u16string_view operator "" sv( const char16_t* str, size_t len ) nssv_noexcept // (2) +nssv_constexpr nonstd::sv_lite::u16string_view operator ""sv( const char16_t* str, size_t len ) nssv_noexcept // (2) { return nonstd::sv_lite::u16string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u32string_view operator "" sv( const char32_t* str, size_t len ) nssv_noexcept // (3) +nssv_constexpr nonstd::sv_lite::u32string_view operator ""sv( const char32_t* str, size_t len ) nssv_noexcept // (3) { return nonstd::sv_lite::u32string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) +nssv_constexpr nonstd::sv_lite::wstring_view operator ""sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) { return nonstd::sv_lite::wstring_view{ str, len }; } @@ -2146,22 +2146,22 @@ nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, #if nssv_CONFIG_USR_SV_OPERATOR -nssv_constexpr nonstd::sv_lite::string_view operator "" _sv( const char* str, size_t len ) nssv_noexcept // (1) +nssv_constexpr nonstd::sv_lite::string_view operator ""_sv( const char* str, size_t len ) nssv_noexcept // (1) { return nonstd::sv_lite::string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u16string_view operator "" _sv( const char16_t* str, size_t len ) nssv_noexcept // (2) +nssv_constexpr nonstd::sv_lite::u16string_view operator ""_sv( const char16_t* str, size_t len ) nssv_noexcept // (2) { return nonstd::sv_lite::u16string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u32string_view operator "" _sv( const char32_t* str, size_t len ) nssv_noexcept // (3) +nssv_constexpr nonstd::sv_lite::u32string_view operator ""_sv( const char32_t* str, size_t len ) nssv_noexcept // (3) { return nonstd::sv_lite::u32string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) +nssv_constexpr nonstd::sv_lite::wstring_view operator ""_sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) { return nonstd::sv_lite::wstring_view{ str, len }; } @@ -2431,7 +2431,7 @@ enum error_code { SUCCESS = 0, ///< No error CAPACITY, ///< This parser can't support a document that big MEMALLOC, ///< Error allocating memory, most likely out of memory - TAPE_ERROR, ///< Something went wrong, this is a generic error + TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error. DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation STRING_ERROR, ///< Problem while parsing a string T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't' @@ -2456,13 +2456,21 @@ enum error_code { PARSER_IN_USE, ///< parser is already in use. OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1) INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it. - INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. + INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error. SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value. OUT_OF_BOUNDS, ///< Attempted to access location outside of document. TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input NUM_ERROR_CODES }; +/** + * Some errors are fatal and invalidate the document. This function returns true if the + * error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT. + * Once a fatal error is encountered, the on-demand document is no longer valid and + * processing should stop. + */ + inline bool is_fatal(error_code error) noexcept; + /** * It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether * we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code @@ -2765,14 +2773,30 @@ SIMDJSON_IMPL_CONCEPT(op_append, operator+=) #undef SIMDJSON_IMPL_CONCEPT } // namespace details + +template +concept string_view_like = std::is_convertible_v && + !std::is_convertible_v; + +template +concept constructible_from_string_view = std::is_constructible_v + && !std::is_same_v + && std::is_default_constructible_v; + +template +concept string_view_keyed_map = string_view_like + && requires(std::remove_cvref_t& m, typename M::key_type sv, typename M::mapped_type v) { + { m.emplace(sv, v) } -> std::same_as>; +}; + /// Check if T is a container that we can append to, including: /// std::vector, std::deque, std::list, std::string, ... template concept appendable_containers = - details::supports_emplace_back || details::supports_emplace || + (details::supports_emplace_back || details::supports_emplace || details::supports_push_back || details::supports_push || details::supports_add || details::supports_append || - details::supports_insert; + details::supports_insert) && !string_view_keyed_map; /// Insert into the container however possible template @@ -2840,6 +2864,8 @@ concept optional_type = requires(std::remove_cvref_t obj) { { static_cast(obj) } -> std::same_as; // convertible to bool }; + + } // namespace concepts } // namespace simdjson #endif // SIMDJSON_SUPPORTS_DESERIALIZATION @@ -4511,6 +4537,11 @@ extern SIMDJSON_DLLIMPORTEXPORT const uint32_t digit_to_val32[886]; #include namespace simdjson { + +inline bool is_fatal(error_code error) noexcept { + return error == TAPE_ERROR || error == INCOMPLETE_ARRAY_OR_OBJECT; +} + namespace internal { // We store the error code so we can validate the error message is associated with the right code struct error_code_info { @@ -4696,7 +4727,7 @@ namespace internal { { SUCCESS, "SUCCESS: No error" }, { CAPACITY, "CAPACITY: This parser can't support a document that big" }, { MEMALLOC, "MEMALLOC: Error allocating memory, we're most likely out of memory" }, - { TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc." }, + { TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc. This is a fatal and unrecoverable error." }, { DEPTH_ERROR, "DEPTH_ERROR: The JSON document was too deep (too many nested objects and arrays)" }, { STRING_ERROR, "STRING_ERROR: Problem while parsing a string" }, { T_ATOM_ERROR, "T_ATOM_ERROR: Problem while parsing an atom starting with the letter 't'" }, @@ -4721,7 +4752,7 @@ namespace internal { { PARSER_IN_USE, "PARSER_IN_USE: Cannot parse a new document while a document is still in use." }, { OUT_OF_ORDER_ITERATION, "OUT_OF_ORDER_ITERATION: Objects and arrays can only be iterated when they are first encountered." }, { INSUFFICIENT_PADDING, "INSUFFICIENT_PADDING: simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." }, - { INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array." }, + { INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array. This is a fatal and unrecoverable error." }, { SCALAR_DOCUMENT_AS_VALUE, "SCALAR_DOCUMENT_AS_VALUE: A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "}, { OUT_OF_BOUNDS, "OUT_OF_BOUNDS: Attempt to access location outside of document."}, { TRAILING_CONTENT, "TRAILING_CONTENT: Unexpected trailing content in the JSON input."} @@ -6787,7 +6818,7 @@ class document { * The memory allocation is strict: you * can you use this function to increase * or lower the amount of allocated memory. - * Passsing zero clears the memory. + * Passing zero clears the memory. */ error_code allocate(size_t len) noexcept; /** @private Capacity in bytes, in terms @@ -9185,7 +9216,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -15545,7 +15576,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -21769,7 +21800,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -28149,7 +28180,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -34891,7 +34922,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -41457,7 +41488,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -47468,7 +47499,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -53078,7 +53109,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // diff --git a/deps/simdjson/simdjson.h b/deps/simdjson/simdjson.h index c1535ee81300b9..a0d449975224a3 100644 --- a/deps/simdjson/simdjson.h +++ b/deps/simdjson/simdjson.h @@ -1,4 +1,4 @@ -/* auto-generated on 2025-02-14 16:11:36 -0500. Do not edit! */ +/* auto-generated on 2025-03-27 15:01:10 -0400. Do not edit! */ /* including simdjson.h: */ /* begin file simdjson.h */ #ifndef SIMDJSON_H @@ -796,22 +796,22 @@ inline namespace literals { inline namespace string_view_literals { -constexpr std::string_view operator "" _sv( const char* str, size_t len ) noexcept // (1) +constexpr std::string_view operator ""_sv( const char* str, size_t len ) noexcept // (1) { return std::string_view{ str, len }; } -constexpr std::u16string_view operator "" _sv( const char16_t* str, size_t len ) noexcept // (2) +constexpr std::u16string_view operator ""_sv( const char16_t* str, size_t len ) noexcept // (2) { return std::u16string_view{ str, len }; } -constexpr std::u32string_view operator "" _sv( const char32_t* str, size_t len ) noexcept // (3) +constexpr std::u32string_view operator ""_sv( const char32_t* str, size_t len ) noexcept // (3) { return std::u32string_view{ str, len }; } -constexpr std::wstring_view operator "" _sv( const wchar_t* str, size_t len ) noexcept // (4) +constexpr std::wstring_view operator ""_sv( const wchar_t* str, size_t len ) noexcept // (4) { return std::wstring_view{ str, len }; } @@ -2142,22 +2142,22 @@ nssv_inline_ns namespace string_view_literals { #if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS -nssv_constexpr nonstd::sv_lite::string_view operator "" sv( const char* str, size_t len ) nssv_noexcept // (1) +nssv_constexpr nonstd::sv_lite::string_view operator ""sv( const char* str, size_t len ) nssv_noexcept // (1) { return nonstd::sv_lite::string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u16string_view operator "" sv( const char16_t* str, size_t len ) nssv_noexcept // (2) +nssv_constexpr nonstd::sv_lite::u16string_view operator ""sv( const char16_t* str, size_t len ) nssv_noexcept // (2) { return nonstd::sv_lite::u16string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u32string_view operator "" sv( const char32_t* str, size_t len ) nssv_noexcept // (3) +nssv_constexpr nonstd::sv_lite::u32string_view operator ""sv( const char32_t* str, size_t len ) nssv_noexcept // (3) { return nonstd::sv_lite::u32string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) +nssv_constexpr nonstd::sv_lite::wstring_view operator ""sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) { return nonstd::sv_lite::wstring_view{ str, len }; } @@ -2166,22 +2166,22 @@ nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, #if nssv_CONFIG_USR_SV_OPERATOR -nssv_constexpr nonstd::sv_lite::string_view operator "" _sv( const char* str, size_t len ) nssv_noexcept // (1) +nssv_constexpr nonstd::sv_lite::string_view operator ""_sv( const char* str, size_t len ) nssv_noexcept // (1) { return nonstd::sv_lite::string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u16string_view operator "" _sv( const char16_t* str, size_t len ) nssv_noexcept // (2) +nssv_constexpr nonstd::sv_lite::u16string_view operator ""_sv( const char16_t* str, size_t len ) nssv_noexcept // (2) { return nonstd::sv_lite::u16string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u32string_view operator "" _sv( const char32_t* str, size_t len ) nssv_noexcept // (3) +nssv_constexpr nonstd::sv_lite::u32string_view operator ""_sv( const char32_t* str, size_t len ) nssv_noexcept // (3) { return nonstd::sv_lite::u32string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) +nssv_constexpr nonstd::sv_lite::wstring_view operator ""_sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) { return nonstd::sv_lite::wstring_view{ str, len }; } @@ -2437,7 +2437,7 @@ namespace std { #define SIMDJSON_SIMDJSON_VERSION_H /** The version of simdjson being used (major.minor.revision) */ -#define SIMDJSON_VERSION "3.12.2" +#define SIMDJSON_VERSION "3.12.3" namespace simdjson { enum { @@ -2452,7 +2452,7 @@ enum { /** * The revision (major.minor.REVISION) of simdjson being used. */ - SIMDJSON_VERSION_REVISION = 2 + SIMDJSON_VERSION_REVISION = 3 }; } // namespace simdjson @@ -2494,7 +2494,7 @@ enum error_code { SUCCESS = 0, ///< No error CAPACITY, ///< This parser can't support a document that big MEMALLOC, ///< Error allocating memory, most likely out of memory - TAPE_ERROR, ///< Something went wrong, this is a generic error + TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error. DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation STRING_ERROR, ///< Problem while parsing a string T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't' @@ -2519,13 +2519,21 @@ enum error_code { PARSER_IN_USE, ///< parser is already in use. OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1) INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it. - INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. + INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error. SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value. OUT_OF_BOUNDS, ///< Attempted to access location outside of document. TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input NUM_ERROR_CODES }; +/** + * Some errors are fatal and invalidate the document. This function returns true if the + * error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT. + * Once a fatal error is encountered, the on-demand document is no longer valid and + * processing should stop. + */ + inline bool is_fatal(error_code error) noexcept; + /** * It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether * we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code @@ -2828,14 +2836,30 @@ SIMDJSON_IMPL_CONCEPT(op_append, operator+=) #undef SIMDJSON_IMPL_CONCEPT } // namespace details + +template +concept string_view_like = std::is_convertible_v && + !std::is_convertible_v; + +template +concept constructible_from_string_view = std::is_constructible_v + && !std::is_same_v + && std::is_default_constructible_v; + +template +concept string_view_keyed_map = string_view_like + && requires(std::remove_cvref_t& m, typename M::key_type sv, typename M::mapped_type v) { + { m.emplace(sv, v) } -> std::same_as>; +}; + /// Check if T is a container that we can append to, including: /// std::vector, std::deque, std::list, std::string, ... template concept appendable_containers = - details::supports_emplace_back || details::supports_emplace || + (details::supports_emplace_back || details::supports_emplace || details::supports_push_back || details::supports_push || details::supports_add || details::supports_append || - details::supports_insert; + details::supports_insert) && !string_view_keyed_map; /// Insert into the container however possible template @@ -2903,6 +2927,8 @@ concept optional_type = requires(std::remove_cvref_t obj) { { static_cast(obj) } -> std::same_as; // convertible to bool }; + + } // namespace concepts } // namespace simdjson #endif // SIMDJSON_SUPPORTS_DESERIALIZATION @@ -2970,6 +2996,11 @@ enum class tape_type; #include namespace simdjson { + +inline bool is_fatal(error_code error) noexcept { + return error == TAPE_ERROR || error == INCOMPLETE_ARRAY_OR_OBJECT; +} + namespace internal { // We store the error code so we can validate the error message is associated with the right code struct error_code_info { @@ -4656,7 +4687,7 @@ class document { * The memory allocation is strict: you * can you use this function to increase * or lower the amount of allocated memory. - * Passsing zero clears the memory. + * Passing zero clears the memory. */ error_code allocate(size_t len) noexcept; /** @private Capacity in bytes, in terms @@ -5013,7 +5044,7 @@ class parser { * arrays or objects) MUST be separated with whitespace. * * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse. - * Setting batch_size to excessively large or excesively small values may impact negatively the + * Setting batch_size to excessively large or excessively small values may impact negatively the * performance. * * ### Error Handling @@ -5107,7 +5138,7 @@ class parser { * arrays or objects) MUST be separated with whitespace. * * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse. - * Setting batch_size to excessively large or excesively small values may impact negatively the + * Setting batch_size to excessively large or excessively small values may impact negatively the * performance. * * ### Error Handling @@ -11599,7 +11630,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -13707,7 +13738,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -16307,7 +16338,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -18904,7 +18935,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -21618,7 +21649,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -24649,7 +24680,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -27157,7 +27188,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -29678,7 +29709,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -32147,7 +32178,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -32157,7 +32189,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -32279,7 +32312,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -32289,7 +32323,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -32587,22 +32622,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -35237,20 +35278,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -35812,20 +35860,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -37000,6 +37055,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -37045,6 +37110,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + arm64::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -42269,19 +42367,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -43123,7 +43225,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -43133,7 +43236,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -43255,7 +43359,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -43265,7 +43370,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -43563,22 +43669,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -46213,20 +46325,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -46788,20 +46907,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -47976,6 +48102,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -48021,6 +48157,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + fallback::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -53245,19 +53414,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -54591,7 +54764,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -54601,7 +54775,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -54723,7 +54898,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -54733,7 +54909,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -55031,22 +55208,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -57681,20 +57864,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -58256,20 +58446,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -59444,6 +59641,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -59489,6 +59696,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + haswell::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -64713,19 +64953,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -66056,7 +66300,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -66066,7 +66311,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -66188,7 +66434,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -66198,7 +66445,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -66496,22 +66744,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -69146,20 +69400,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -69721,20 +69982,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -70909,6 +71177,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -70954,6 +71232,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + icelake::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -76178,19 +76489,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -77638,7 +77953,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -77648,7 +77964,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -77770,7 +78087,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -77780,7 +78098,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -78078,22 +78397,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -80728,20 +81053,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -81303,20 +81635,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -82491,6 +82830,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -82536,6 +82885,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + ppc64::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -87760,19 +88142,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -89537,7 +89923,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -89547,7 +89934,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -89669,7 +90057,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -89679,7 +90068,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -89977,22 +90367,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -92627,20 +93023,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -93202,20 +93605,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -94390,6 +94800,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -94435,6 +94855,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + westmere::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -99659,19 +100112,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -100913,7 +101370,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -100923,7 +101381,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -101045,7 +101504,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -101055,7 +101515,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -101353,22 +101814,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -104003,20 +104470,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -104578,20 +105052,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -105766,6 +106247,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -105811,6 +106302,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + lsx::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -111035,19 +111559,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -112302,7 +112830,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -112312,7 +112841,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -112434,7 +112964,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -112444,7 +112975,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -112742,22 +113274,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -115392,20 +115930,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -115967,20 +116512,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -117155,6 +117707,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -117200,6 +117762,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + lasx::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -122424,19 +123019,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); diff --git a/deps/sqlite/sqlite3.c b/deps/sqlite/sqlite3.c index 37b534afb2787c..58dc0e9208d7bd 100644 --- a/deps/sqlite/sqlite3.c +++ b/deps/sqlite/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.49.1. By combining all the individual C code files into this +** version 3.50.0. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -18,7 +18,7 @@ ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** 873d4e274b4988d260ba8354a9718324a1c2 with changes in files: +** dfc790f998f450d9c35e3ba1c8c89c17466c with changes in files: ** ** */ @@ -452,7 +452,7 @@ extern "C" { ** ** Since [version 3.6.18] ([dateof:3.6.18]), ** SQLite source code has been stored in the -** Fossil configuration management +** Fossil configuration management ** system. ^The SQLITE_SOURCE_ID macro evaluates to ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID @@ -465,9 +465,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.49.1" -#define SQLITE_VERSION_NUMBER 3049001 -#define SQLITE_SOURCE_ID "2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f10e70" +#define SQLITE_VERSION "3.50.0" +#define SQLITE_VERSION_NUMBER 3050000 +#define SQLITE_SOURCE_ID "2025-05-29 14:26:00 dfc790f998f450d9c35e3ba1c8c89c17466cb559f87b0239e4aab9d34e28f742" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -1482,6 +1482,12 @@ struct sqlite3_io_methods { ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** +**
  • [[SQLITE_FCNTL_BLOCK_ON_CONNECT]] +** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the +** VFS to block when taking a SHARED lock to connect to a wal mode database. +** This is used to implement the functionality associated with +** SQLITE_SETLK_BLOCK_ON_CONNECT. +** **
  • [[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. @@ -1578,6 +1584,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 #define SQLITE_FCNTL_NULL_IO 43 +#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -2308,13 +2315,16 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_CONFIG_LOOKASIDE]]
    SQLITE_CONFIG_LOOKASIDE
    **
    ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine -** the default size of lookaside memory on each [database connection]. +** the default size of [lookaside memory] on each [database connection]. ** The first argument is the -** size of each lookaside buffer slot and the second is the number of -** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE -** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] -** option to [sqlite3_db_config()] can be used to change the lookaside -** configuration on individual connections.)^
    +** size of each lookaside buffer slot ("sz") and the second is the number of +** slots allocated to each database connection ("cnt").)^ +** ^(SQLITE_CONFIG_LOOKASIDE sets the default lookaside size. +** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can +** be used to change the lookaside configuration on individual connections.)^ +** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the +** default lookaside configuration at compile-time. +** ** ** [[SQLITE_CONFIG_PCACHE2]]
    SQLITE_CONFIG_PCACHE2
    **
    ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is @@ -2551,31 +2561,50 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    **
    The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the -** configuration of the lookaside memory allocator within a database +** configuration of the [lookaside memory allocator] within a database ** connection. ** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are not ** in the [DBCONFIG arguments|usual format]. ** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two, ** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE ** should have a total of five parameters. -** ^The first argument (the third parameter to [sqlite3_db_config()] is a +**
      +**
    1. The first argument ("buf") is a ** pointer to a memory buffer to use for lookaside memory. -** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb -** may be NULL in which case SQLite will allocate the -** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the -** size of each lookaside buffer slot. ^The third argument is the number of -** slots. The size of the buffer in the first argument must be greater than -** or equal to the product of the second and third arguments. The buffer -** must be aligned to an 8-byte boundary. ^If the second argument to -** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally -** rounded down to the next smaller multiple of 8. ^(The lookaside memory +** The first argument may be NULL in which case SQLite will allocate the +** lookaside buffer itself using [sqlite3_malloc()]. +**

    2. The second argument ("sz") is the +** size of each lookaside buffer slot. Lookaside is disabled if "sz" +** is less than 8. The "sz" argument should be a multiple of 8 less than +** 65536. If "sz" does not meet this constraint, it is reduced in size until +** it does. +**

    3. The third argument ("cnt") is the number of slots. Lookaside is disabled +** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so +** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt" +** parameter is usually chosen so that the product of "sz" and "cnt" is less +** than 1,000,000. +**

    +**

    If the "buf" argument is not NULL, then it must +** point to a memory buffer with a size that is greater than +** or equal to the product of "sz" and "cnt". +** The buffer must be aligned to an 8-byte boundary. +** The lookaside memory ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words -** when the "current value" returned by -** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero. +** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns -** [SQLITE_BUSY].)^

    +** [SQLITE_BUSY]. +** If the "buf" argument is NULL and an attempt +** to allocate memory based on "sz" and "cnt" fails, then +** lookaside is silently disabled. +**

    +** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the +** default lookaside configuration at initialization. The +** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside +** configuration at compile-time. Typical values for lookaside are 1200 for +** "sz" and 40 to 100 for "cnt". +** ** ** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **

    SQLITE_DBCONFIG_ENABLE_FKEY
    @@ -3312,6 +3341,44 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); +/* +** CAPI3REF: Set the Setlk Timeout +** METHOD: sqlite3 +** +** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If +** the VFS supports blocking locks, it sets the timeout in ms used by +** eligible locks taken on wal mode databases by the specified database +** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does +** not support blocking locks, this function is a no-op. +** +** Passing 0 to this function disables blocking locks altogether. Passing +** -1 to this function requests that the VFS blocks for a long time - +** indefinitely if possible. The results of passing any other negative value +** are undefined. +** +** Internally, each SQLite database handle store two timeout values - the +** busy-timeout (used for rollback mode databases, or if the VFS does not +** support blocking locks) and the setlk-timeout (used for blocking locks +** on wal-mode databases). The sqlite3_busy_timeout() method sets both +** values, this function sets only the setlk-timeout value. Therefore, +** to configure separate busy-timeout and setlk-timeout values for a single +** database handle, call sqlite3_busy_timeout() followed by this function. +** +** Whenever the number of connections to a wal mode database falls from +** 1 to 0, the last connection takes an exclusive lock on the database, +** then checkpoints and deletes the wal file. While it is doing this, any +** new connection that tries to read from the database fails with an +** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is +** passed to this API, the new connection blocks until the exclusive lock +** has been released. +*/ +SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags); + +/* +** CAPI3REF: Flags for sqlite3_setlk_timeout() +*/ +#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01 + /* ** CAPI3REF: Convenience Routines For Running Queries ** METHOD: sqlite3 @@ -5427,7 +5494,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from -** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], +** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1]), ** sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility @@ -7323,6 +7390,8 @@ SQLITE_API int sqlite3_autovacuum_pages( ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. +** ^The update hook is disabled by invoking sqlite3_update_hook() +** with a NULL pointer as the second parameter. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], @@ -11805,9 +11874,10 @@ SQLITE_API void sqlite3session_table_filter( ** is inserted while a session object is enabled, then later deleted while ** the same session object is disabled, no INSERT record will appear in the ** changeset, even though the delete took place while the session was disabled. -** Or, if one field of a row is updated while a session is disabled, and -** another field of the same row is updated while the session is enabled, the -** resulting changeset will contain an UPDATE change that updates both fields. +** Or, if one field of a row is updated while a session is enabled, and +** then another field of the same row is updated while the session is disabled, +** the resulting changeset will contain an UPDATE change that updates both +** fields. */ SQLITE_API int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ @@ -11879,8 +11949,9 @@ SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession ** database zFrom the contents of the two compatible tables would be ** identical. ** -** It an error if database zFrom does not exist or does not contain the -** required compatible table. +** Unless the call to this function is a no-op as described above, it is an +** error if database zFrom does not exist or does not contain the required +** compatible table. ** ** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite ** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg @@ -12015,7 +12086,7 @@ SQLITE_API int sqlite3changeset_start_v2( ** The following flags may passed via the 4th parameter to ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: ** -**
    SQLITE_CHANGESETAPPLY_INVERT
    +**
    SQLITE_CHANGESETSTART_INVERT
    ** Invert the changeset while iterating through it. This is equivalent to ** inverting a changeset using sqlite3changeset_invert() before applying it. ** It is an error to specify this flag with a patchset. @@ -12330,19 +12401,6 @@ SQLITE_API int sqlite3changeset_concat( void **ppOut /* OUT: Buffer containing output changeset */ ); - -/* -** CAPI3REF: Upgrade the Schema of a Changeset/Patchset -*/ -SQLITE_API int sqlite3changeset_upgrade( - sqlite3 *db, - const char *zDb, - int nIn, const void *pIn, /* Input changeset */ - int *pnOut, void **ppOut /* OUT: Inverse of input */ -); - - - /* ** CAPI3REF: Changegroup Handle ** @@ -14090,14 +14148,22 @@ struct fts5_api { ** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement. ** * Terms in the VALUES clause of an INSERT statement ** -** The hard upper limit here is 32676. Most database people will +** The hard upper limit here is 32767. Most database people will ** tell you that in a well-normalized database, you usually should ** not have more than a dozen or so columns in any table. And if ** that is the case, there is no point in having more than a few ** dozen values in any of the other situations described above. +** +** An index can only have SQLITE_MAX_COLUMN columns from the user +** point of view, but the underlying b-tree that implements the index +** might have up to twice as many columns in a WITHOUT ROWID table, +** since must also store the primary key at the end. Hence the +** column count for Index is u16 instead of i16. */ -#ifndef SQLITE_MAX_COLUMN +#if !defined(SQLITE_MAX_COLUMN) # define SQLITE_MAX_COLUMN 2000 +#elif SQLITE_MAX_COLUMN>32767 +# error SQLITE_MAX_COLUMN may not exceed 32767 #endif /* @@ -14749,6 +14815,7 @@ struct HashElem { HashElem *next, *prev; /* Next and previous elements in the table */ void *data; /* Data associated with this element */ const char *pKey; /* Key associated with this element */ + unsigned int h; /* hash for pKey */ }; /* @@ -15109,7 +15176,17 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); ** ourselves. */ #ifndef offsetof -#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD)) +#define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD)) +#endif + +/* +** Work around C99 "flex-array" syntax for pre-C99 compilers, so as +** to avoid complaints from -fsanitize=strict-bounds. +*/ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEXARRAY +#else +# define FLEXARRAY 1 #endif /* @@ -15187,6 +15264,11 @@ typedef INT16_TYPE i16; /* 2-byte signed integer */ typedef UINT8_TYPE u8; /* 1-byte unsigned integer */ typedef INT8_TYPE i8; /* 1-byte signed integer */ +/* A bitfield type for use inside of structures. Always follow with :N where +** N is the number of bits. +*/ +typedef unsigned bft; /* Bit Field Type */ + /* ** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value ** that can be stored in a u32 without loss of data. The value @@ -15355,6 +15437,14 @@ typedef INT16_TYPE LogEst; #define LARGEST_UINT64 (0xffffffff|(((u64)0xffffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) +/* +** Macro SMXV(n) return the maximum value that can be held in variable n, +** assuming n is a signed integer type. UMXV(n) is similar for unsigned +** integer types. +*/ +#define SMXV(n) ((((i64)1)<<(sizeof(n)-1))-1) +#define UMXV(n) ((((i64)1)<<(sizeof(n)))-1) + /* ** Round up a number to the next larger multiple of 8. This is used ** to force 8-byte alignment on 64-bit architectures. @@ -17331,8 +17421,8 @@ SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*); SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*); #endif -/* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on -** each VDBE opcode. +/* Use SQLITE_ENABLE_EXPLAIN_COMMENTS to enable generation of extra +** comments on each VDBE opcode. ** ** Use the SQLITE_ENABLE_MODULE_COMMENTS macro to see some extra no-op ** comments in VDBE programs that show key decision points in the code @@ -18055,6 +18145,10 @@ struct sqlite3 { Savepoint *pSavepoint; /* List of active savepoints */ int nAnalysisLimit; /* Number of index rows to ANALYZE */ int busyTimeout; /* Busy handler timeout, in msec */ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + int setlkTimeout; /* Blocking lock timeout, in msec. -1 -> inf. */ + int setlkFlags; /* Flags passed to setlk_timeout() */ +#endif int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ @@ -18733,6 +18827,7 @@ struct Table { } u; Trigger *pTrigger; /* List of triggers on this object */ Schema *pSchema; /* Schema that contains this table */ + u8 aHx[16]; /* Column aHt[K%sizeof(aHt)] might have hash K */ }; /* @@ -18866,9 +18961,13 @@ struct FKey { struct sColMap { /* Mapping of columns in pFrom to columns in zTo */ int iFrom; /* Index of column in pFrom */ char *zCol; /* Name of column in zTo. If NULL use PRIMARY KEY */ - } aCol[1]; /* One entry for each of nCol columns */ + } aCol[FLEXARRAY]; /* One entry for each of nCol columns */ }; +/* The size (in bytes) of an FKey object holding N columns. The answer +** does NOT include space to hold the zTo name. */ +#define SZ_FKEY(N) (offsetof(FKey,aCol)+(N)*sizeof(struct sColMap)) + /* ** SQLite supports many different ways to resolve a constraint ** error. ROLLBACK processing means that a constraint violation @@ -18930,9 +19029,12 @@ struct KeyInfo { u16 nAllField; /* Total columns, including key plus others */ sqlite3 *db; /* The database connection */ u8 *aSortFlags; /* Sort order for each column. */ - CollSeq *aColl[1]; /* Collating sequence for each term of the key */ + CollSeq *aColl[FLEXARRAY]; /* Collating sequence for each term of the key */ }; +/* The size (in bytes) of a KeyInfo object with up to N fields */ +#define SZ_KEYINFO(N) (offsetof(KeyInfo,aColl) + (N)*sizeof(CollSeq*)) + /* ** Allowed bit values for entries in the KeyInfo.aSortFlags[] array. */ @@ -19052,7 +19154,7 @@ struct Index { Pgno tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ - u16 nColumn; /* Number of columns stored in the index */ + u16 nColumn; /* Nr columns in btree. Can be 2*Table.nCol */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ @@ -19061,9 +19163,9 @@ struct Index { unsigned isCovering:1; /* True if this is a covering index */ unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ - unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */ unsigned bNoQuery:1; /* Do not use this index to optimize queries */ unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ + unsigned bIdxRowid:1; /* One or more of the index keys is the ROWID */ unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ unsigned bHasExpr:1; /* Index contains an expression, either a literal ** expression, or a reference to a VIRTUAL column */ @@ -19390,10 +19492,10 @@ struct Expr { /* Macros can be used to test, set, or clear bits in the ** Expr.flags field. */ -#define ExprHasProperty(E,P) (((E)->flags&(P))!=0) -#define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P)) -#define ExprSetProperty(E,P) (E)->flags|=(P) -#define ExprClearProperty(E,P) (E)->flags&=~(P) +#define ExprHasProperty(E,P) (((E)->flags&(u32)(P))!=0) +#define ExprHasAllProperty(E,P) (((E)->flags&(u32)(P))==(u32)(P)) +#define ExprSetProperty(E,P) (E)->flags|=(u32)(P) +#define ExprClearProperty(E,P) (E)->flags&=~(u32)(P) #define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue) #define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse) #define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0) @@ -19505,9 +19607,14 @@ struct ExprList { int iConstExprReg; /* Register in which Expr value is cached. Used only ** by Parse.pConstExpr */ } u; - } a[1]; /* One slot for each expression in the list */ + } a[FLEXARRAY]; /* One slot for each expression in the list */ }; +/* The size (in bytes) of an ExprList object that is big enough to hold +** as many as N expressions. */ +#define SZ_EXPRLIST(N) \ + (offsetof(ExprList,a) + (N)*sizeof(struct ExprList_item)) + /* ** Allowed values for Expr.a.eEName */ @@ -19535,9 +19642,12 @@ struct IdList { int nId; /* Number of identifiers on the list */ struct IdList_item { char *zName; /* Name of the identifier */ - } a[1]; + } a[FLEXARRAY]; }; +/* The size (in bytes) of an IdList object that can hold up to N IDs. */ +#define SZ_IDLIST(N) (offsetof(IdList,a)+(N)*sizeof(struct IdList_item)) + /* ** Allowed values for IdList.eType, which determines which value of the a.u4 ** is valid. @@ -19657,11 +19767,19 @@ struct OnOrUsing { ** */ struct SrcList { - int nSrc; /* Number of tables or subqueries in the FROM clause */ - u32 nAlloc; /* Number of entries allocated in a[] below */ - SrcItem a[1]; /* One entry for each identifier on the list */ + int nSrc; /* Number of tables or subqueries in the FROM clause */ + u32 nAlloc; /* Number of entries allocated in a[] below */ + SrcItem a[FLEXARRAY]; /* One entry for each identifier on the list */ }; +/* Size (in bytes) of a SrcList object that can hold as many as N +** SrcItem objects. */ +#define SZ_SRCLIST(N) (offsetof(SrcList,a)+(N)*sizeof(SrcItem)) + +/* Size (in bytes( of a SrcList object that holds 1 SrcItem. This is a +** special case of SZ_SRCITEM(1) that comes up often. */ +#define SZ_SRCLIST_1 (offsetof(SrcList,a)+sizeof(SrcItem)) + /* ** Permitted values of the SrcList.a.jointype field */ @@ -20130,25 +20248,32 @@ struct Parse { char *zErrMsg; /* An error message */ Vdbe *pVdbe; /* An engine for executing database bytecode */ int rc; /* Return code from execution */ - u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ - u8 checkSchema; /* Causes schema cookie check after an error */ + LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ - u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ - u8 bHasWith; /* True if statement contains WITH */ u8 mSubrtnSig; /* mini Bloom filter on available SubrtnSig.selId */ + u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ + u8 bReturning; /* Coding a RETURNING trigger */ + u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ + u8 disableTriggers; /* True to disable triggers */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ #endif #ifdef SQLITE_DEBUG u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */ + u8 isCreate; /* CREATE TABLE, INDEX, or VIEW (but not TRIGGER) + ** and ALTER TABLE ADD COLUMN. */ #endif + bft colNamesSet :1; /* TRUE after OP_ColumnName has been issued to pVdbe */ + bft bHasWith :1; /* True if statement contains WITH */ + bft okConstFactor :1; /* OK to factor out constants */ + bft checkSchema :1; /* Causes schema cookie check after an error */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ @@ -20163,12 +20288,9 @@ struct Parse { ExprList *pConstExpr;/* Constant expressions */ IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */ IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */ - Token constraintName;/* Name of the constraint currently being parsed */ yDbMask writeMask; /* Start a write transaction on these databases */ yDbMask cookieMask; /* Bitmask of schema verified databases */ - int regRowid; /* Register holding rowid of CREATE TABLE entry */ - int regRoot; /* Register holding root page number for new objects */ - int nMaxArg; /* Max args passed to user function by sub-program */ + int nMaxArg; /* Max args to xUpdate and xFilter vtab methods */ int nSelect; /* Number of SELECT stmts. Counter for Select.selId */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */ @@ -20182,17 +20304,6 @@ struct Parse { Table *pTriggerTab; /* Table triggers are being coded for */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */ - union { - int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */ - Returning *pReturning; /* The RETURNING clause */ - } u1; - u32 oldmask; /* Mask of old.* columns referenced */ - u32 newmask; /* Mask of new.* columns referenced */ - LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ - u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ - u8 bReturning; /* Coding a RETURNING trigger */ - u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ - u8 disableTriggers; /* True to disable triggers */ /************************************************************************** ** Fields above must be initialized to zero. The fields that follow, @@ -20204,6 +20315,19 @@ struct Parse { int aTempReg[8]; /* Holding area for temporary registers */ Parse *pOuterParse; /* Outer Parse object when nested */ Token sNameToken; /* Token with unqualified schema object name */ + u32 oldmask; /* Mask of old.* columns referenced */ + u32 newmask; /* Mask of new.* columns referenced */ + union { + struct { /* These fields available when isCreate is true */ + int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */ + int regRowid; /* Register holding rowid of CREATE TABLE entry */ + int regRoot; /* Register holding root page for new objects */ + Token constraintName; /* Name of the constraint currently being parsed */ + } cr; + struct { /* These fields available to all other statements */ + Returning *pReturning; /* The RETURNING clause */ + } d; + } u1; /************************************************************************ ** Above is constant between recursions. Below is reset before and after @@ -20719,9 +20843,13 @@ struct With { int nCte; /* Number of CTEs in the WITH clause */ int bView; /* Belongs to the outermost Select of a view */ With *pOuter; /* Containing WITH clause, or NULL */ - Cte a[1]; /* For each CTE in the WITH clause.... */ + Cte a[FLEXARRAY]; /* For each CTE in the WITH clause.... */ }; +/* The size (in bytes) of a With object that can hold as many +** as N different CTEs. */ +#define SZ_WITH(N) (offsetof(With,a) + (N)*sizeof(Cte)) + /* ** The Cte object is not guaranteed to persist for the entire duration ** of code generation. (The query flattener or other parser tree @@ -20750,9 +20878,13 @@ struct DbClientData { DbClientData *pNext; /* Next in a linked list */ void *pData; /* The data */ void (*xDestructor)(void*); /* Destructor. Might be NULL */ - char zName[1]; /* Name of this client data. MUST BE LAST */ + char zName[FLEXARRAY]; /* Name of this client data. MUST BE LAST */ }; +/* The size (in bytes) of a DbClientData object that can has a name +** that is N bytes long, including the zero-terminator. */ +#define SZ_DBCLIENTDATA(N) (offsetof(DbClientData,zName)+(N)) + #ifdef SQLITE_DEBUG /* ** An instance of the TreeView object is used for printing the content of @@ -21195,7 +21327,7 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char); SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int); SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*); -SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index*, i16); +SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index*, int); #ifdef SQLITE_OMIT_GENERATED_COLUMNS # define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */ # define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */ @@ -21293,7 +21425,7 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*); SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*); SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*); SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*); -SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); +SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,int,int,char**); SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Expr*, int, int, u8); SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int); @@ -21429,7 +21561,8 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,const Select*,int); SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*); SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int); SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); -SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*); +SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*,int); +SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char*, u32); SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void); @@ -22294,6 +22427,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_BUG_COMPATIBLE_20160819 "BUG_COMPATIBLE_20160819", #endif +#ifdef SQLITE_BUG_COMPATIBLE_20250510 + "BUG_COMPATIBLE_20250510", +#endif #ifdef SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif @@ -22530,6 +22666,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_ENABLE_SESSION "ENABLE_SESSION", #endif +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + "ENABLE_SETLK_TIMEOUT", +#endif #ifdef SQLITE_ENABLE_SNAPSHOT "ENABLE_SNAPSHOT", #endif @@ -22584,6 +22723,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_EXTRA_INIT "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT), #endif +#ifdef SQLITE_EXTRA_INIT_MUTEXED + "EXTRA_INIT_MUTEXED=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT_MUTEXED), +#endif #ifdef SQLITE_EXTRA_SHUTDOWN "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN), #endif @@ -23568,12 +23710,19 @@ struct VdbeCursor { #endif VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */ - /* 2*nField extra array elements allocated for aType[], beyond the one - ** static element declared in the structure. nField total array slots for - ** aType[] and nField+1 array slots for aOffset[] */ - u32 aType[1]; /* Type values record decode. MUST BE LAST */ + /* Space is allocated for aType to hold at least 2*nField+1 entries: + ** nField slots for aType[] and nField+1 array slots for aOffset[] */ + u32 aType[FLEXARRAY]; /* Type values record decode. MUST BE LAST */ }; +/* +** The size (in bytes) of a VdbeCursor object that has an nField value of N +** or less. The value of SZ_VDBECURSOR(n) is guaranteed to be a multiple +** of 8. +*/ +#define SZ_VDBECURSOR(N) \ + (ROUND8(offsetof(VdbeCursor,aType)) + ((N)+1)*sizeof(u64)) + /* Return true if P is a null-only cursor */ #define IsNullCursor(P) \ @@ -23830,13 +23979,16 @@ struct sqlite3_context { u8 enc; /* Encoding to use for results */ u8 skipFlag; /* Skip accumulator loading if true */ u16 argc; /* Number of arguments */ - sqlite3_value *argv[1]; /* Argument set */ + sqlite3_value *argv[FLEXARRAY]; /* Argument set */ }; -/* A bitfield type for use inside of structures. Always follow with :N where -** N is the number of bits. +/* +** The size (in bytes) of an sqlite3_context object that holds N +** argv[] arguments. */ -typedef unsigned bft; /* Bit Field Type */ +#define SZ_CONTEXT(N) \ + (offsetof(sqlite3_context,argv)+(N)*sizeof(sqlite3_value*)) + /* The ScanStatus object holds a single value for the ** sqlite3_stmt_scanstatus() interface. @@ -23897,7 +24049,7 @@ struct Vdbe { i64 nStmtDefCons; /* Number of def. constraints when stmt started */ i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ Mem *aMem; /* The memory locations */ - Mem **apArg; /* Arguments to currently executing user function */ + Mem **apArg; /* Arguments xUpdate and xFilter vtab methods */ VdbeCursor **apCsr; /* One element of this array for each open cursor */ Mem *aVar; /* Values for the OP_Variable opcode. */ @@ -23917,6 +24069,7 @@ struct Vdbe { #ifdef SQLITE_DEBUG int rcApp; /* errcode set by sqlite3_result_error_code() */ u32 nWrite; /* Number of write operations that have occurred */ + int napArg; /* Size of the apArg[] array */ #endif u16 nResColumn; /* Number of columns in one row of the result set */ u16 nResAlloc; /* Column slots allocated to aColName[] */ @@ -23969,7 +24122,7 @@ struct PreUpdate { VdbeCursor *pCsr; /* Cursor to read old values from */ int op; /* One of SQLITE_INSERT, UPDATE, DELETE */ u8 *aRecord; /* old.* database record */ - KeyInfo keyinfo; + KeyInfo *pKeyinfo; /* Key information */ UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */ UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */ int iNewReg; /* Register for new.* values */ @@ -23981,6 +24134,7 @@ struct PreUpdate { Table *pTab; /* Schema object being updated */ Index *pPk; /* PK index if pTab is WITHOUT ROWID */ sqlite3_value **apDflt; /* Array of default values, if required */ + u8 keyinfoSpace[SZ_KEYINFO(0)]; /* Space to hold pKeyinfo[0] content */ }; /* @@ -24347,8 +24501,9 @@ SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){ nInit += countLookasideSlots(db->lookaside.pSmallInit); nFree += countLookasideSlots(db->lookaside.pSmallFree); #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ - if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit; - return db->lookaside.nSlot - (nInit+nFree); + assert( db->lookaside.nSlot >= nInit+nFree ); + if( pHighwater ) *pHighwater = (int)(db->lookaside.nSlot - nInit); + return (int)(db->lookaside.nSlot - (nInit+nFree)); } /* @@ -24401,7 +24556,7 @@ SQLITE_API int sqlite3_db_status( assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 ); assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 ); *pCurrent = 0; - *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT]; + *pHighwater = (int)db->lookaside.anStat[op-SQLITE_DBSTATUS_LOOKASIDE_HIT]; if( resetFlag ){ db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0; } @@ -25913,7 +26068,7 @@ static int daysAfterMonday(DateTime *pDate){ ** In other words, return the day of the week according ** to this code: ** -** 0=Sunday, 1=Monday, 2=Tues, ..., 6=Saturday +** 0=Sunday, 1=Monday, 2=Tuesday, ..., 6=Saturday */ static int daysAfterSunday(DateTime *pDate){ assert( pDate->validJD ); @@ -30122,6 +30277,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ #ifdef __CYGWIN__ # include +# include /* amalgamator: dontcache */ +# include /* amalgamator: dontcache */ # include /* amalgamator: dontcache */ #endif @@ -31516,17 +31673,17 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ #define etPERCENT 7 /* Percent symbol. %% */ #define etCHARX 8 /* Characters. %c */ /* The rest are extensions, not normally found in printf() */ -#define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */ -#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', - NULL pointers replaced by SQL NULL. %Q */ -#define etTOKEN 11 /* a pointer to a Token structure */ -#define etSRCITEM 12 /* a pointer to a SrcItem */ -#define etPOINTER 13 /* The %p conversion */ -#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */ -#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ -#define etDECIMAL 16 /* %d or %u, but not %x, %o */ +#define etESCAPE_q 9 /* Strings with '\'' doubled. %q */ +#define etESCAPE_Q 10 /* Strings with '\'' doubled and enclosed in '', + NULL pointers replaced by SQL NULL. %Q */ +#define etTOKEN 11 /* a pointer to a Token structure */ +#define etSRCITEM 12 /* a pointer to a SrcItem */ +#define etPOINTER 13 /* The %p conversion */ +#define etESCAPE_w 14 /* %w -> Strings with '\"' doubled */ +#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ +#define etDECIMAL 16 /* %d or %u, but not %x, %o */ -#define etINVALID 17 /* Any unrecognized conversion type */ +#define etINVALID 17 /* Any unrecognized conversion type */ /* @@ -31565,9 +31722,9 @@ static const et_info fmtinfo[] = { { 's', 0, 4, etSTRING, 0, 0 }, { 'g', 0, 1, etGENERIC, 30, 0 }, { 'z', 0, 4, etDYNSTRING, 0, 0 }, - { 'q', 0, 4, etSQLESCAPE, 0, 0 }, - { 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, - { 'w', 0, 4, etSQLESCAPE3, 0, 0 }, + { 'q', 0, 4, etESCAPE_q, 0, 0 }, + { 'Q', 0, 4, etESCAPE_Q, 0, 0 }, + { 'w', 0, 4, etESCAPE_w, 0, 0 }, { 'c', 0, 0, etCHARX, 0, 0 }, { 'o', 8, 0, etRADIX, 0, 2 }, { 'u', 10, 0, etDECIMAL, 0, 0 }, @@ -32164,25 +32321,7 @@ SQLITE_API void sqlite3_str_vappendf( } }else{ unsigned int ch = va_arg(ap,unsigned int); - if( ch<0x00080 ){ - buf[0] = ch & 0xff; - length = 1; - }else if( ch<0x00800 ){ - buf[0] = 0xc0 + (u8)((ch>>6)&0x1f); - buf[1] = 0x80 + (u8)(ch & 0x3f); - length = 2; - }else if( ch<0x10000 ){ - buf[0] = 0xe0 + (u8)((ch>>12)&0x0f); - buf[1] = 0x80 + (u8)((ch>>6) & 0x3f); - buf[2] = 0x80 + (u8)(ch & 0x3f); - length = 3; - }else{ - buf[0] = 0xf0 + (u8)((ch>>18) & 0x07); - buf[1] = 0x80 + (u8)((ch>>12) & 0x3f); - buf[2] = 0x80 + (u8)((ch>>6) & 0x3f); - buf[3] = 0x80 + (u8)(ch & 0x3f); - length = 4; - } + length = sqlite3AppendOneUtf8Character(buf, ch); } if( precision>1 ){ i64 nPrior = 1; @@ -32262,22 +32401,31 @@ SQLITE_API void sqlite3_str_vappendf( while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++; } break; - case etSQLESCAPE: /* %q: Escape ' characters */ - case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */ - case etSQLESCAPE3: { /* %w: Escape " characters */ + case etESCAPE_q: /* %q: Escape ' characters */ + case etESCAPE_Q: /* %Q: Escape ' and enclose in '...' */ + case etESCAPE_w: { /* %w: Escape " characters */ i64 i, j, k, n; - int needQuote, isnull; + int needQuote = 0; char ch; - char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */ char *escarg; + char q; if( bArgList ){ escarg = getTextArg(pArgList); }else{ escarg = va_arg(ap,char*); } - isnull = escarg==0; - if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)"); + if( escarg==0 ){ + escarg = (xtype==etESCAPE_Q ? "NULL" : "(NULL)"); + }else if( xtype==etESCAPE_Q ){ + needQuote = 1; + } + if( xtype==etESCAPE_w ){ + q = '"'; + flag_alternateform = 0; + }else{ + q = '\''; + } /* For %q, %Q, and %w, the precision is the number of bytes (or ** characters if the ! flags is present) to use from the input. ** Because of the extra quoting characters inserted, the number @@ -32290,7 +32438,30 @@ SQLITE_API void sqlite3_str_vappendf( while( (escarg[i+1]&0xc0)==0x80 ){ i++; } } } - needQuote = !isnull && xtype==etSQLESCAPE2; + if( flag_alternateform ){ + /* For %#q, do unistr()-style backslash escapes for + ** all control characters, and for backslash itself. + ** For %#Q, do the same but only if there is at least + ** one control character. */ + u32 nBack = 0; + u32 nCtrl = 0; + for(k=0; ketBUFSIZE ){ bufpt = zExtra = printfTempBuf(pAccum, n); @@ -32299,13 +32470,41 @@ SQLITE_API void sqlite3_str_vappendf( bufpt = buf; } j = 0; - if( needQuote ) bufpt[j++] = q; + if( needQuote ){ + if( needQuote==2 ){ + memcpy(&bufpt[j], "unistr('", 8); + j += 8; + }else{ + bufpt[j++] = '\''; + } + } k = i; - for(i=0; i=0x10 ? '1' : '0'; + bufpt[j++] = "0123456789abcdef"[ch&0xf]; + } + } + }else{ + for(i=0; imxAlloc>0 && !isMalloced(p) ); - zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); + zText = sqlite3DbMallocRaw(p->db, 1+(u64)p->nChar ); if( zText ){ memcpy(zText, p->zText, p->nChar+1); p->printfFlags |= SQLITE_PRINTF_MALLOCED; @@ -32793,6 +32992,15 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ return zBuf; } +/* Maximum size of an sqlite3_log() message. */ +#if defined(SQLITE_MAX_LOG_MESSAGE) + /* Leave the definition as supplied */ +#elif SQLITE_PRINT_BUF_SIZE*10>10000 +# define SQLITE_MAX_LOG_MESSAGE 10000 +#else +# define SQLITE_MAX_LOG_MESSAGE (SQLITE_PRINT_BUF_SIZE*10) +#endif + /* ** This is the routine that actually formats the sqlite3_log() message. ** We house it in a separate routine from sqlite3_log() to avoid using @@ -32809,7 +33017,7 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ */ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ StrAccum acc; /* String accumulator */ - char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ + char zMsg[SQLITE_MAX_LOG_MESSAGE]; /* Complete log message */ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); sqlite3_str_vappendf(&acc, zFormat, ap); @@ -34804,6 +35012,35 @@ static const unsigned char sqlite3Utf8Trans1[] = { } \ } +/* +** Write a single UTF8 character whose value is v into the +** buffer starting at zOut. zOut must be sized to hold at +** least four bytes. Return the number of bytes needed +** to encode the new character. +*/ +SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char *zOut, u32 v){ + if( v<0x00080 ){ + zOut[0] = (u8)(v & 0xff); + return 1; + } + if( v<0x00800 ){ + zOut[0] = 0xc0 + (u8)((v>>6) & 0x1f); + zOut[1] = 0x80 + (u8)(v & 0x3f); + return 2; + } + if( v<0x10000 ){ + zOut[0] = 0xe0 + (u8)((v>>12) & 0x0f); + zOut[1] = 0x80 + (u8)((v>>6) & 0x3f); + zOut[2] = 0x80 + (u8)(v & 0x3f); + return 3; + } + zOut[0] = 0xf0 + (u8)((v>>18) & 0x07); + zOut[1] = 0x80 + (u8)((v>>12) & 0x3f); + zOut[2] = 0x80 + (u8)((v>>6) & 0x3f); + zOut[3] = 0x80 + (u8)(v & 0x3f); + return 4; +} + /* ** Translate a single UTF-8 character. Return the unicode value. ** @@ -35225,7 +35462,7 @@ SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nByte, int nChar){ int n = 0; if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++; - while( n=0xd8 && c<0xdc && z<=zEnd && z[0]>=0xdc && z[0]<0xe0 ) z += 2; @@ -36400,7 +36637,11 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou } p->z = &p->zBuf[i+1]; assert( i+p->n < sizeof(p->zBuf) ); - while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; } + assert( p->n>0 ); + while( p->z[p->n-1]=='0' ){ + p->n--; + assert( p->n>0 ); + } } /* @@ -36905,7 +37146,7 @@ SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){ } /* -** Compute the absolute value of a 32-bit signed integer, of possible. Or +** Compute the absolute value of a 32-bit signed integer, if possible. Or ** if the integer has a value of -2147483648, return +2147483647 */ SQLITE_PRIVATE int sqlite3AbsInt32(int x){ @@ -37186,12 +37427,19 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){ */ static unsigned int strHash(const char *z){ unsigned int h = 0; - unsigned char c; - while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/ + while( z[0] ){ /*OPTIMIZATION-IF-TRUE*/ /* Knuth multiplicative hashing. (Sorting & Searching, p. 510). ** 0x9e3779b1 is 2654435761 which is the closest prime number to - ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */ - h += sqlite3UpperToLower[c]; + ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. + ** + ** Only bits 0xdf for ASCII and bits 0xbf for EBCDIC each octet are + ** hashed since the omitted bits determine the upper/lower case difference. + */ +#ifdef SQLITE_EBCDIC + h += 0xbf & (unsigned char)*(z++); +#else + h += 0xdf & (unsigned char)*(z++); +#endif h *= 0x9e3779b1; } return h; @@ -37264,9 +37512,8 @@ static int rehash(Hash *pH, unsigned int new_size){ pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht); memset(new_ht, 0, new_size*sizeof(struct _ht)); for(elem=pH->first, pH->first=0; elem; elem = next_elem){ - unsigned int h = strHash(elem->pKey) % new_size; next_elem = elem->next; - insertElement(pH, &new_ht[h], elem); + insertElement(pH, &new_ht[elem->h % new_size], elem); } return 1; } @@ -37284,23 +37531,22 @@ static HashElem *findElementWithHash( HashElem *elem; /* Used to loop thru the element list */ unsigned int count; /* Number of elements left to test */ unsigned int h; /* The computed hash */ - static HashElem nullElement = { 0, 0, 0, 0 }; + static HashElem nullElement = { 0, 0, 0, 0, 0 }; + h = strHash(pKey); if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/ struct _ht *pEntry; - h = strHash(pKey) % pH->htsize; - pEntry = &pH->ht[h]; + pEntry = &pH->ht[h % pH->htsize]; elem = pEntry->chain; count = pEntry->count; }else{ - h = 0; elem = pH->first; count = pH->count; } if( pHash ) *pHash = h; while( count ){ assert( elem!=0 ); - if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ + if( h==elem->h && sqlite3StrICmp(elem->pKey,pKey)==0 ){ return elem; } elem = elem->next; @@ -37312,10 +37558,9 @@ static HashElem *findElementWithHash( /* Remove a single entry from the hash table given a pointer to that ** element and a hash on the element's key. */ -static void removeElementGivenHash( +static void removeElement( Hash *pH, /* The pH containing "elem" */ - HashElem* elem, /* The element to be removed from the pH */ - unsigned int h /* Hash value for the element */ + HashElem *elem /* The element to be removed from the pH */ ){ struct _ht *pEntry; if( elem->prev ){ @@ -37327,7 +37572,7 @@ static void removeElementGivenHash( elem->next->prev = elem->prev; } if( pH->ht ){ - pEntry = &pH->ht[h]; + pEntry = &pH->ht[elem->h % pH->htsize]; if( pEntry->chain==elem ){ pEntry->chain = elem->next; } @@ -37378,7 +37623,7 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ if( elem->data ){ void *old_data = elem->data; if( data==0 ){ - removeElementGivenHash(pH,elem,h); + removeElement(pH,elem); }else{ elem->data = data; elem->pKey = pKey; @@ -37389,15 +37634,13 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) ); if( new_elem==0 ) return data; new_elem->pKey = pKey; + new_elem->h = h; new_elem->data = data; pH->count++; - if( pH->count>=10 && pH->count > 2*pH->htsize ){ - if( rehash(pH, pH->count*2) ){ - assert( pH->htsize>0 ); - h = strHash(pKey) % pH->htsize; - } + if( pH->count>=5 && pH->count > 2*pH->htsize ){ + rehash(pH, pH->count*3); } - insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem); + insertElement(pH, pH->ht ? &pH->ht[new_elem->h % pH->htsize] : 0, new_elem); return 0; } @@ -38880,6 +39123,7 @@ struct unixFile { #endif #ifdef SQLITE_ENABLE_SETLK_TIMEOUT unsigned iBusyTimeout; /* Wait this many millisec on locks */ + int bBlockOnConnect; /* True to block for SHARED locks */ #endif #if OS_VXWORKS struct vxworksFileId *pId; /* Unique file ID */ @@ -40273,6 +40517,13 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){ rc = 0; } }else{ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( pFile->bBlockOnConnect && pLock->l_type==F_RDLCK + && pLock->l_start==SHARED_FIRST && pLock->l_len==SHARED_SIZE + ){ + rc = osFcntl(pFile->h, F_SETLKW, pLock); + }else +#endif rc = osSetPosixAdvisoryLock(pFile->h, pLock, pFile); } return rc; @@ -42634,8 +42885,9 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT case SQLITE_FCNTL_LOCK_TIMEOUT: { int iOld = pFile->iBusyTimeout; + int iNew = *(int*)pArg; #if SQLITE_ENABLE_SETLK_TIMEOUT==1 - pFile->iBusyTimeout = *(int*)pArg; + pFile->iBusyTimeout = iNew<0 ? 0x7FFFFFFF : (unsigned)iNew; #elif SQLITE_ENABLE_SETLK_TIMEOUT==2 pFile->iBusyTimeout = !!(*(int*)pArg); #else @@ -42644,7 +42896,12 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ *(int*)pArg = iOld; return SQLITE_OK; } -#endif + case SQLITE_FCNTL_BLOCK_ON_CONNECT: { + int iNew = *(int*)pArg; + pFile->bBlockOnConnect = iNew; + return SQLITE_OK; + } +#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */ #if SQLITE_MAX_MMAP_SIZE>0 case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; @@ -43627,7 +43884,7 @@ static int unixShmLock( ** ** It is not permitted to block on the RECOVER lock. */ -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT +#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && defined(SQLITE_DEBUG) { u16 lockMask = (p->exclMask|p->sharedMask); assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( @@ -45436,7 +45693,7 @@ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){ /* Almost all modern unix systems support nanosleep(). But if you are ** compiling for one of the rare exceptions, you can use - ** -DHAVE_NANOSLEEP=0 (perhaps in conjuction with -DHAVE_USLEEP if + ** -DHAVE_NANOSLEEP=0 (perhaps in conjunction with -DHAVE_USLEEP if ** usleep() is available) in order to bypass the use of nanosleep() */ nanosleep(&sp, NULL); @@ -47157,8 +47414,18 @@ struct winFile { sqlite3_int64 mmapSize; /* Size of mapped region */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ #endif +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + DWORD iBusyTimeout; /* Wait this many millisec on locks */ + int bBlockOnConnect; +#endif }; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT +# define winFileBusyTimeout(pDbFd) pDbFd->iBusyTimeout +#else +# define winFileBusyTimeout(pDbFd) 0 +#endif + /* ** The winVfsAppData structure is used for the pAppData member for all of the ** Win32 VFS variants. @@ -47477,7 +47744,7 @@ static struct win_syscall { { "FileTimeToLocalFileTime", (SYSCALL)0, 0 }, #endif -#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \ +#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(const FILETIME*, \ LPFILETIME))aSyscall[11].pCurrent) #if SQLITE_OS_WINCE @@ -47486,7 +47753,7 @@ static struct win_syscall { { "FileTimeToSystemTime", (SYSCALL)0, 0 }, #endif -#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \ +#define osFileTimeToSystemTime ((BOOL(WINAPI*)(const FILETIME*, \ LPSYSTEMTIME))aSyscall[12].pCurrent) { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 }, @@ -47592,6 +47859,12 @@ static struct win_syscall { #define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \ LPWSTR*))aSyscall[25].pCurrent) +/* +** For GetLastError(), MSDN says: +** +** Minimum supported client: Windows XP [desktop apps | UWP apps] +** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] +*/ { "GetLastError", (SYSCALL)GetLastError, 0 }, #define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent) @@ -47760,7 +48033,7 @@ static struct win_syscall { { "LockFile", (SYSCALL)0, 0 }, #endif -#ifndef osLockFile +#if !defined(osLockFile) && defined(SQLITE_WIN32_HAS_ANSI) #define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ DWORD))aSyscall[47].pCurrent) #endif @@ -47824,7 +48097,7 @@ static struct win_syscall { { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 }, -#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \ +#define osSystemTimeToFileTime ((BOOL(WINAPI*)(const SYSTEMTIME*, \ LPFILETIME))aSyscall[56].pCurrent) #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT @@ -47833,7 +48106,7 @@ static struct win_syscall { { "UnlockFile", (SYSCALL)0, 0 }, #endif -#ifndef osUnlockFile +#if !defined(osUnlockFile) && defined(SQLITE_WIN32_HAS_ANSI) #define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ DWORD))aSyscall[57].pCurrent) #endif @@ -47874,11 +48147,13 @@ static struct win_syscall { #define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \ DWORD,DWORD))aSyscall[62].pCurrent) -#if !SQLITE_OS_WINRT +/* +** For WaitForSingleObject(), MSDN says: +** +** Minimum supported client: Windows XP [desktop apps | UWP apps] +** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] +*/ { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 }, -#else - { "WaitForSingleObject", (SYSCALL)0, 0 }, -#endif #define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ DWORD))aSyscall[63].pCurrent) @@ -48025,6 +48300,97 @@ static struct win_syscall { #define osFlushViewOfFile \ ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent) +/* +** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CreateEvent() +** to implement blocking locks with timeouts. MSDN says: +** +** Minimum supported client: Windows XP [desktop apps | UWP apps] +** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] +*/ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + { "CreateEvent", (SYSCALL)CreateEvent, 0 }, +#else + { "CreateEvent", (SYSCALL)0, 0 }, +#endif + +#define osCreateEvent ( \ + (HANDLE(WINAPI*) (LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR)) \ + aSyscall[80].pCurrent \ +) + +/* +** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CancelIo() +** for the case where a timeout expires and a lock request must be +** cancelled. +** +** Minimum supported client: Windows XP [desktop apps | UWP apps] +** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] +*/ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + { "CancelIo", (SYSCALL)CancelIo, 0 }, +#else + { "CancelIo", (SYSCALL)0, 0 }, +#endif + +#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[81].pCurrent) + +#if defined(SQLITE_WIN32_HAS_WIDE) && defined(_WIN32) + { "GetModuleHandleW", (SYSCALL)GetModuleHandleW, 0 }, +#else + { "GetModuleHandleW", (SYSCALL)0, 0 }, +#endif + +#define osGetModuleHandleW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[82].pCurrent) + +#ifndef _WIN32 + { "getenv", (SYSCALL)getenv, 0 }, +#else + { "getenv", (SYSCALL)0, 0 }, +#endif + +#define osGetenv ((const char *(*)(const char *))aSyscall[83].pCurrent) + +#ifndef _WIN32 + { "getcwd", (SYSCALL)getcwd, 0 }, +#else + { "getcwd", (SYSCALL)0, 0 }, +#endif + +#define osGetcwd ((char*(*)(char*,size_t))aSyscall[84].pCurrent) + +#ifndef _WIN32 + { "readlink", (SYSCALL)readlink, 0 }, +#else + { "readlink", (SYSCALL)0, 0 }, +#endif + +#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[85].pCurrent) + +#ifndef _WIN32 + { "lstat", (SYSCALL)lstat, 0 }, +#else + { "lstat", (SYSCALL)0, 0 }, +#endif + +#define osLstat ((int(*)(const char*,struct stat*))aSyscall[86].pCurrent) + +#ifndef _WIN32 + { "__errno", (SYSCALL)__errno, 0 }, +#else + { "__errno", (SYSCALL)0, 0 }, +#endif + +#define osErrno (*((int*(*)(void))aSyscall[87].pCurrent)()) + +#ifndef _WIN32 + { "cygwin_conv_path", (SYSCALL)cygwin_conv_path, 0 }, +#else + { "cygwin_conv_path", (SYSCALL)0, 0 }, +#endif + +#define osCygwin_conv_path ((size_t(*)(unsigned int, \ + const void *, void *, size_t))aSyscall[88].pCurrent) + }; /* End of the overrideable system calls */ /* @@ -48198,6 +48564,7 @@ SQLITE_API int sqlite3_win32_reset_heap(){ } #endif /* SQLITE_WIN32_MALLOC */ +#ifdef _WIN32 /* ** This function outputs the specified (ANSI) string to the Win32 debugger ** (if available). @@ -48240,6 +48607,7 @@ SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){ } #endif } +#endif /* _WIN32 */ /* ** The following routine suspends the current thread for at least ms @@ -48323,7 +48691,9 @@ SQLITE_API int sqlite3_win32_is_nt(void){ } return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; #elif SQLITE_TEST - return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; + return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2 + || osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 + ; #else /* ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are @@ -48538,6 +48908,7 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){ } #endif /* SQLITE_WIN32_MALLOC */ +#ifdef _WIN32 /* ** Convert a UTF-8 string to Microsoft Unicode. ** @@ -48563,6 +48934,7 @@ static LPWSTR winUtf8ToUnicode(const char *zText){ } return zWideText; } +#endif /* _WIN32 */ /* ** Convert a Microsoft Unicode string to UTF-8. @@ -48597,28 +48969,29 @@ static char *winUnicodeToUtf8(LPCWSTR zWideText){ ** Space to hold the returned string is obtained from sqlite3_malloc(). */ static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){ - int nByte; + int nWideChar; LPWSTR zMbcsText; int codepage = useAnsi ? CP_ACP : CP_OEMCP; - nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL, - 0)*sizeof(WCHAR); - if( nByte==0 ){ + nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, NULL, + 0); + if( nWideChar==0 ){ return 0; } - zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) ); + zMbcsText = sqlite3MallocZero( nWideChar*sizeof(WCHAR) ); if( zMbcsText==0 ){ return 0; } - nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText, - nByte); - if( nByte==0 ){ + nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText, + nWideChar); + if( nWideChar==0 ){ sqlite3_free(zMbcsText); zMbcsText = 0; } return zMbcsText; } +#ifdef _WIN32 /* ** Convert a Microsoft Unicode string to a multi-byte character string, ** using the ANSI or OEM code page. @@ -48646,6 +49019,7 @@ static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){ } return zText; } +#endif /* _WIN32 */ /* ** Convert a multi-byte character string to UTF-8. @@ -48665,6 +49039,7 @@ static char *winMbcsToUtf8(const char *zText, int useAnsi){ return zTextUtf8; } +#ifdef _WIN32 /* ** Convert a UTF-8 string to a multi-byte character string. ** @@ -48714,6 +49089,7 @@ SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){ #endif return winUnicodeToUtf8(zWideText); } +#endif /* _WIN32 */ /* ** This is a public wrapper for the winMbcsToUtf8() function. @@ -48731,6 +49107,7 @@ SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){ return winMbcsToUtf8(zText, osAreFileApisANSI()); } +#ifdef _WIN32 /* ** This is a public wrapper for the winMbcsToUtf8() function. */ @@ -48855,6 +49232,7 @@ SQLITE_API int sqlite3_win32_set_directory( ){ return sqlite3_win32_set_directory16(type, zValue); } +#endif /* _WIN32 */ /* ** The return value of winGetLastErrorMsg @@ -49403,13 +49781,94 @@ static BOOL winLockFile( ovlp.Offset = offsetLow; ovlp.OffsetHigh = offsetHigh; return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp); +#ifdef SQLITE_WIN32_HAS_ANSI }else{ return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh); +#endif } #endif } +/* +** Lock a region of nByte bytes starting at offset offset of file hFile. +** Take an EXCLUSIVE lock if parameter bExclusive is true, or a SHARED lock +** otherwise. If nMs is greater than zero and the lock cannot be obtained +** immediately, block for that many ms before giving up. +** +** This function returns SQLITE_OK if the lock is obtained successfully. If +** some other process holds the lock, SQLITE_BUSY is returned if nMs==0, or +** SQLITE_BUSY_TIMEOUT otherwise. Or, if an error occurs, SQLITE_IOERR. +*/ +static int winHandleLockTimeout( + HANDLE hFile, + DWORD offset, + DWORD nByte, + int bExcl, + DWORD nMs +){ + DWORD flags = LOCKFILE_FAIL_IMMEDIATELY | (bExcl?LOCKFILE_EXCLUSIVE_LOCK:0); + int rc = SQLITE_OK; + BOOL ret; + + if( !osIsNT() ){ + ret = winLockFile(&hFile, flags, offset, 0, nByte, 0); + }else{ + OVERLAPPED ovlp; + memset(&ovlp, 0, sizeof(OVERLAPPED)); + ovlp.Offset = offset; + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( nMs!=0 ){ + flags &= ~LOCKFILE_FAIL_IMMEDIATELY; + } + ovlp.hEvent = osCreateEvent(NULL, TRUE, FALSE, NULL); + if( ovlp.hEvent==NULL ){ + return SQLITE_IOERR_LOCK; + } +#endif + + ret = osLockFileEx(hFile, flags, 0, nByte, 0, &ovlp); + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + /* If SQLITE_ENABLE_SETLK_TIMEOUT is defined, then the file-handle was + ** opened with FILE_FLAG_OVERHEAD specified. In this case, the call to + ** LockFileEx() may fail because the request is still pending. This can + ** happen even if LOCKFILE_FAIL_IMMEDIATELY was specified. + ** + ** If nMs is 0, then LOCKFILE_FAIL_IMMEDIATELY was set in the flags + ** passed to LockFileEx(). In this case, if the operation is pending, + ** block indefinitely until it is finished. + ** + ** Otherwise, wait for up to nMs ms for the operation to finish. nMs + ** may be set to INFINITE. + */ + if( !ret && GetLastError()==ERROR_IO_PENDING ){ + DWORD nDelay = (nMs==0 ? INFINITE : nMs); + DWORD res = osWaitForSingleObject(ovlp.hEvent, nDelay); + if( res==WAIT_OBJECT_0 ){ + ret = TRUE; + }else if( res==WAIT_TIMEOUT ){ + rc = SQLITE_BUSY_TIMEOUT; + }else{ + /* Some other error has occurred */ + rc = SQLITE_IOERR_LOCK; + } + + /* If it is still pending, cancel the LockFileEx() call. */ + osCancelIo(hFile); + } + + osCloseHandle(ovlp.hEvent); +#endif + } + + if( rc==SQLITE_OK && !ret ){ + rc = SQLITE_BUSY; + } + return rc; +} + /* ** Unlock a file region. */ @@ -49434,13 +49893,23 @@ static BOOL winUnlockFile( ovlp.Offset = offsetLow; ovlp.OffsetHigh = offsetHigh; return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp); +#ifdef SQLITE_WIN32_HAS_ANSI }else{ return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh); +#endif } #endif } +/* +** Remove an nByte lock starting at offset iOff from HANDLE h. +*/ +static int winHandleUnlock(HANDLE h, int iOff, int nByte){ + BOOL ret = winUnlockFile(&h, iOff, 0, nByte, 0); + return (ret ? SQLITE_OK : SQLITE_IOERR_UNLOCK); +} + /***************************************************************************** ** The next group of routines implement the I/O methods specified ** by the sqlite3_io_methods object. @@ -49454,66 +49923,70 @@ static BOOL winUnlockFile( #endif /* -** Move the current position of the file handle passed as the first -** argument to offset iOffset within the file. If successful, return 0. -** Otherwise, set pFile->lastErrno and return non-zero. +** Seek the file handle h to offset nByte of the file. +** +** If successful, return SQLITE_OK. Or, if an error occurs, return an SQLite +** error code. */ -static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ +static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){ + int rc = SQLITE_OK; /* Return value */ + #if !SQLITE_OS_WINRT LONG upperBits; /* Most sig. 32 bits of new offset */ LONG lowerBits; /* Least sig. 32 bits of new offset */ DWORD dwRet; /* Value returned by SetFilePointer() */ - DWORD lastErrno; /* Value returned by GetLastError() */ - - OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset)); upperBits = (LONG)((iOffset>>32) & 0x7fffffff); lowerBits = (LONG)(iOffset & 0xffffffff); + dwRet = osSetFilePointer(h, lowerBits, &upperBits, FILE_BEGIN); + /* API oddity: If successful, SetFilePointer() returns a dword ** containing the lower 32-bits of the new file-offset. Or, if it fails, ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine ** whether an error has actually occurred, it is also necessary to call - ** GetLastError(). - */ - dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); - - if( (dwRet==INVALID_SET_FILE_POINTER - && ((lastErrno = osGetLastError())!=NO_ERROR)) ){ - pFile->lastErrno = lastErrno; - winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, - "winSeekFile", pFile->zPath); - OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); - return 1; + ** GetLastError(). */ + if( dwRet==INVALID_SET_FILE_POINTER ){ + DWORD lastErrno = osGetLastError(); + if( lastErrno!=NO_ERROR ){ + rc = SQLITE_IOERR_SEEK; + } } - - OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); - return 0; #else - /* - ** Same as above, except that this implementation works for WinRT. - */ - + /* This implementation works for WinRT. */ LARGE_INTEGER x; /* The new offset */ BOOL bRet; /* Value returned by SetFilePointerEx() */ x.QuadPart = iOffset; - bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN); + bRet = osSetFilePointerEx(h, x, 0, FILE_BEGIN); if(!bRet){ - pFile->lastErrno = osGetLastError(); - winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, - "winSeekFile", pFile->zPath); - OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); - return 1; + rc = SQLITE_IOERR_SEEK; } - - OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); - return 0; #endif + + OSTRACE(("SEEK file=%p, offset=%lld rc=%s\n", h, iOffset, sqlite3ErrName(rc))); + return rc; +} + +/* +** Move the current position of the file handle passed as the first +** argument to offset iOffset within the file. If successful, return 0. +** Otherwise, set pFile->lastErrno and return non-zero. +*/ +static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ + int rc; + + rc = winHandleSeek(pFile->h, iOffset); + if( rc!=SQLITE_OK ){ + pFile->lastErrno = osGetLastError(); + winLogError(rc, pFile->lastErrno, "winSeekFile", pFile->zPath); + } + return rc; } + #if SQLITE_MAX_MMAP_SIZE>0 /* Forward references to VFS helper methods used for memory mapped files */ static int winMapfile(winFile*, sqlite3_int64); @@ -49773,6 +50246,60 @@ static int winWrite( return SQLITE_OK; } +/* +** Truncate the file opened by handle h to nByte bytes in size. +*/ +static int winHandleTruncate(HANDLE h, sqlite3_int64 nByte){ + int rc = SQLITE_OK; /* Return code */ + rc = winHandleSeek(h, nByte); + if( rc==SQLITE_OK ){ + if( 0==osSetEndOfFile(h) ){ + rc = SQLITE_IOERR_TRUNCATE; + } + } + return rc; +} + +/* +** Determine the size in bytes of the file opened by the handle passed as +** the first argument. +*/ +static int winHandleSize(HANDLE h, sqlite3_int64 *pnByte){ + int rc = SQLITE_OK; + +#if SQLITE_OS_WINRT + FILE_STANDARD_INFO info; + BOOL b; + b = osGetFileInformationByHandleEx(h, FileStandardInfo, &info, sizeof(info)); + if( b ){ + *pnByte = info.EndOfFile.QuadPart; + }else{ + rc = SQLITE_IOERR_FSTAT; + } +#else + DWORD upperBits = 0; + DWORD lowerBits = 0; + + assert( pnByte ); + lowerBits = osGetFileSize(h, &upperBits); + *pnByte = (((sqlite3_int64)upperBits)<<32) + lowerBits; + if( lowerBits==INVALID_FILE_SIZE && osGetLastError()!=NO_ERROR ){ + rc = SQLITE_IOERR_FSTAT; + } +#endif + + return rc; +} + +/* +** Close the handle passed as the only argument. +*/ +static void winHandleClose(HANDLE h){ + if( h!=INVALID_HANDLE_VALUE ){ + osCloseHandle(h); + } +} + /* ** Truncate an open file to a specified size */ @@ -50028,8 +50555,9 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ ** Different API routines are called depending on whether or not this ** is Win9x or WinNT. */ -static int winGetReadLock(winFile *pFile){ +static int winGetReadLock(winFile *pFile, int bBlock){ int res; + DWORD mask = ~(bBlock ? LOCKFILE_FAIL_IMMEDIATELY : 0); OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); if( osIsNT() ){ #if SQLITE_OS_WINCE @@ -50039,7 +50567,7 @@ static int winGetReadLock(winFile *pFile){ */ res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0); #else - res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0, + res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS&mask, SHARED_FIRST, 0, SHARED_SIZE, 0); #endif } @@ -50048,7 +50576,7 @@ static int winGetReadLock(winFile *pFile){ int lk; sqlite3_randomness(sizeof(lk), &lk); pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1)); - res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, + res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS&mask, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); } #endif @@ -50143,46 +50671,62 @@ static int winLock(sqlite3_file *id, int locktype){ assert( locktype!=PENDING_LOCK ); assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); - /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or + /* Lock the PENDING_LOCK byte if we need to acquire an EXCLUSIVE lock or ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of ** the PENDING_LOCK byte is temporary. */ newLocktype = pFile->locktype; - if( pFile->locktype==NO_LOCK - || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK) + if( locktype==SHARED_LOCK + || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) ){ int cnt = 3; - while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, - PENDING_BYTE, 0, 1, 0))==0 ){ + + /* Flags for the LockFileEx() call. This should be an exclusive lock if + ** this call is to obtain EXCLUSIVE, or a shared lock if this call is to + ** obtain SHARED. */ + int flags = LOCKFILE_FAIL_IMMEDIATELY; + if( locktype==EXCLUSIVE_LOCK ){ + flags |= LOCKFILE_EXCLUSIVE_LOCK; + } + while( cnt>0 ){ /* Try 3 times to get the pending lock. This is needed to work ** around problems caused by indexing and/or anti-virus software on ** Windows systems. + ** ** If you are using this code as a model for alternative VFSes, do not - ** copy this retry logic. It is a hack intended for Windows only. - */ + ** copy this retry logic. It is a hack intended for Windows only. */ + res = winLockFile(&pFile->h, flags, PENDING_BYTE, 0, 1, 0); + if( res ) break; + lastErrno = osGetLastError(); OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n", - pFile->h, cnt, res)); + pFile->h, cnt, res + )); + if( lastErrno==ERROR_INVALID_HANDLE ){ pFile->lastErrno = lastErrno; rc = SQLITE_IOERR_LOCK; OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n", - pFile->h, cnt, sqlite3ErrName(rc))); + pFile->h, cnt, sqlite3ErrName(rc) + )); return rc; } - if( cnt ) sqlite3_win32_sleep(1); + + cnt--; + if( cnt>0 ) sqlite3_win32_sleep(1); } gotPendingLock = res; - if( !res ){ - lastErrno = osGetLastError(); - } } /* Acquire a shared lock */ if( locktype==SHARED_LOCK && res ){ assert( pFile->locktype==NO_LOCK ); - res = winGetReadLock(pFile); +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + res = winGetReadLock(pFile, pFile->bBlockOnConnect); +#else + res = winGetReadLock(pFile, 0); +#endif if( res ){ newLocktype = SHARED_LOCK; }else{ @@ -50220,7 +50764,7 @@ static int winLock(sqlite3_file *id, int locktype){ newLocktype = EXCLUSIVE_LOCK; }else{ lastErrno = osGetLastError(); - winGetReadLock(pFile); + winGetReadLock(pFile, 0); } } @@ -50300,7 +50844,7 @@ static int winUnlock(sqlite3_file *id, int locktype){ type = pFile->locktype; if( type>=EXCLUSIVE_LOCK ){ winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - if( locktype==SHARED_LOCK && !winGetReadLock(pFile) ){ + if( locktype==SHARED_LOCK && !winGetReadLock(pFile, 0) ){ /* This should never happen. We should always be able to ** reacquire the read lock */ rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(), @@ -50510,6 +51054,28 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ return rc; } #endif + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + case SQLITE_FCNTL_LOCK_TIMEOUT: { + int iOld = pFile->iBusyTimeout; + int iNew = *(int*)pArg; +#if SQLITE_ENABLE_SETLK_TIMEOUT==1 + pFile->iBusyTimeout = (iNew < 0) ? INFINITE : (DWORD)iNew; +#elif SQLITE_ENABLE_SETLK_TIMEOUT==2 + pFile->iBusyTimeout = (DWORD)(!!iNew); +#else +# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2" +#endif + *(int*)pArg = iOld; + return SQLITE_OK; + } + case SQLITE_FCNTL_BLOCK_ON_CONNECT: { + int iNew = *(int*)pArg; + pFile->bBlockOnConnect = iNew; + return SQLITE_OK; + } +#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */ + } OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h)); return SQLITE_NOTFOUND; @@ -50590,23 +51156,27 @@ static int winShmMutexHeld(void) { ** ** The following fields are read-only after the object is created: ** -** fid ** zFilename ** ** Either winShmNode.mutex must be held or winShmNode.nRef==0 and ** winShmMutexHeld() is true when reading or writing any other field ** in this structure. ** +** File-handle hSharedShm is used to (a) take the DMS lock, (b) truncate +** the *-shm file if the DMS-locking protocol demands it, and (c) map +** regions of the *-shm file into memory using MapViewOfFile() or +** similar. Other locks are taken by individual clients using the +** winShm.hShm handles. */ struct winShmNode { sqlite3_mutex *mutex; /* Mutex to access this object */ char *zFilename; /* Name of the file */ - winFile hFile; /* File handle from winOpen */ + HANDLE hSharedShm; /* File handle open on zFilename */ + int isUnlocked; /* DMS lock has not yet been obtained */ + int isReadonly; /* True if read-only */ int szRegion; /* Size of shared-memory regions */ int nRegion; /* Size of array apRegion */ - u8 isReadonly; /* True if read-only */ - u8 isUnlocked; /* True if no DMS lock held */ struct ShmRegion { HANDLE hMap; /* File handle from CreateFileMapping */ @@ -50615,7 +51185,6 @@ struct winShmNode { DWORD lastErrno; /* The Windows errno from the last I/O error */ int nRef; /* Number of winShm objects pointing to this */ - winShm *pFirst; /* All winShm objects pointing to this */ winShmNode *pNext; /* Next in list of all winShmNode objects */ #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) u8 nextShmId; /* Next available winShm.id value */ @@ -50631,23 +51200,15 @@ static winShmNode *winShmNodeList = 0; /* ** Structure used internally by this VFS to record the state of an -** open shared memory connection. -** -** The following fields are initialized when this object is created and -** are read-only thereafter: -** -** winShm.pShmNode -** winShm.id -** -** All other fields are read/write. The winShm.pShmNode->mutex must be held -** while accessing any read/write fields. +** open shared memory connection. There is one such structure for each +** winFile open on a wal mode database. */ struct winShm { winShmNode *pShmNode; /* The underlying winShmNode object */ - winShm *pNext; /* Next winShm with the same winShmNode */ - u8 hasMutex; /* True if holding the winShmNode mutex */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ + HANDLE hShm; /* File-handle on *-shm file. For locking. */ + int bReadonly; /* True if hShm is opened read-only */ #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) u8 id; /* Id of this connection with its winShmNode */ #endif @@ -50659,50 +51220,6 @@ struct winShm { #define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ -/* -** Apply advisory locks for all n bytes beginning at ofst. -*/ -#define WINSHM_UNLCK 1 -#define WINSHM_RDLCK 2 -#define WINSHM_WRLCK 3 -static int winShmSystemLock( - winShmNode *pFile, /* Apply locks to this open shared-memory segment */ - int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */ - int ofst, /* Offset to first byte to be locked/unlocked */ - int nByte /* Number of bytes to lock or unlock */ -){ - int rc = 0; /* Result code form Lock/UnlockFileEx() */ - - /* Access to the winShmNode object is serialized by the caller */ - assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) ); - - OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n", - pFile->hFile.h, lockType, ofst, nByte)); - - /* Release/Acquire the system-level lock */ - if( lockType==WINSHM_UNLCK ){ - rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0); - }else{ - /* Initialize the locking parameters */ - DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; - if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; - rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); - } - - if( rc!= 0 ){ - rc = SQLITE_OK; - }else{ - pFile->lastErrno = osGetLastError(); - rc = SQLITE_BUSY; - } - - OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n", - pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" : - "winLockFile", pFile->lastErrno, sqlite3ErrName(rc))); - - return rc; -} - /* Forward references to VFS methods */ static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*); static int winDelete(sqlite3_vfs *,const char*,int); @@ -50734,11 +51251,7 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); UNUSED_VARIABLE_VALUE(bRc); } - if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){ - SimulateIOErrorBenign(1); - winClose((sqlite3_file *)&p->hFile); - SimulateIOErrorBenign(0); - } + winHandleClose(p->hSharedShm); if( deleteFlag ){ SimulateIOErrorBenign(1); sqlite3BeginBenignMalloc(); @@ -50756,42 +51269,239 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ } /* -** The DMS lock has not yet been taken on shm file pShmNode. Attempt to -** take it now. Return SQLITE_OK if successful, or an SQLite error -** code otherwise. -** -** If the DMS cannot be locked because this is a readonly_shm=1 -** connection and no other process already holds a lock, return -** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1. +** The DMS lock has not yet been taken on the shm file associated with +** pShmNode. Take the lock. Truncate the *-shm file if required. +** Return SQLITE_OK if successful, or an SQLite error code otherwise. */ -static int winLockSharedMemory(winShmNode *pShmNode){ - int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1); +static int winLockSharedMemory(winShmNode *pShmNode, DWORD nMs){ + HANDLE h = pShmNode->hSharedShm; + int rc = SQLITE_OK; + assert( sqlite3_mutex_held(pShmNode->mutex) ); + rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 1, 0); if( rc==SQLITE_OK ){ + /* We have an EXCLUSIVE lock on the DMS byte. This means that this + ** is the first process to open the file. Truncate it to zero bytes + ** in this case. */ if( pShmNode->isReadonly ){ - pShmNode->isUnlocked = 1; - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); - return SQLITE_READONLY_CANTINIT; - }else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){ - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); - return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(), - "winLockSharedMemory", pShmNode->zFilename); + rc = SQLITE_READONLY_CANTINIT; + }else{ + rc = winHandleTruncate(h, 0); } + + /* Release the EXCLUSIVE lock acquired above. */ + winUnlockFile(&h, WIN_SHM_DMS, 0, 1, 0); + }else if( (rc & 0xFF)==SQLITE_BUSY ){ + rc = SQLITE_OK; } if( rc==SQLITE_OK ){ - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); + /* Take a SHARED lock on the DMS byte. */ + rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 0, nMs); + if( rc==SQLITE_OK ){ + pShmNode->isUnlocked = 0; + } } - return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1); + return rc; } + /* -** Open the shared-memory area associated with database file pDbFd. +** Convert a UTF-8 filename into whatever form the underlying +** operating system wants filenames in. Space to hold the result +** is obtained from malloc and must be freed by the calling +** function +** +** On Cygwin, 3 possible input forms are accepted: +** - If the filename starts with ":/" or ":\", +** it is converted to UTF-16 as-is. +** - If the filename contains '/', it is assumed to be a +** Cygwin absolute path, it is converted to a win32 +** absolute path in UTF-16. +** - Otherwise it must be a filename only, the win32 filename +** is returned in UTF-16. +** Note: If the function cygwin_conv_path() fails, only +** UTF-8 -> UTF-16 conversion will be done. This can only +** happen when the file path >32k, in which case winUtf8ToUnicode() +** will fail too. +*/ +static void *winConvertFromUtf8Filename(const char *zFilename){ + void *zConverted = 0; + if( osIsNT() ){ +#ifdef __CYGWIN__ + int nChar; + LPWSTR zWideFilename; + + if( osCygwin_conv_path && !(winIsDriveLetterAndColon(zFilename) + && winIsDirSep(zFilename[2])) ){ + i64 nByte; + int convertflag = CCP_POSIX_TO_WIN_W; + if( !strchr(zFilename, '/') ) convertflag |= CCP_RELATIVE; + nByte = (i64)osCygwin_conv_path(convertflag, + zFilename, 0, 0); + if( nByte>0 ){ + zConverted = sqlite3MallocZero(12+(u64)nByte); + if ( zConverted==0 ){ + return zConverted; + } + zWideFilename = zConverted; + /* Filenames should be prefixed, except when converted + * full path already starts with "\\?\". */ + if( osCygwin_conv_path(convertflag, zFilename, + zWideFilename+4, nByte)==0 ){ + if( (convertflag&CCP_RELATIVE) ){ + memmove(zWideFilename, zWideFilename+4, nByte); + }else if( memcmp(zWideFilename+4, L"\\\\", 4) ){ + memcpy(zWideFilename, L"\\\\?\\", 8); + }else if( zWideFilename[6]!='?' ){ + memmove(zWideFilename+6, zWideFilename+4, nByte); + memcpy(zWideFilename, L"\\\\?\\UNC", 14); + }else{ + memmove(zWideFilename, zWideFilename+4, nByte); + } + return zConverted; + } + sqlite3_free(zConverted); + } + } + nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); + if( nChar==0 ){ + return 0; + } + zWideFilename = sqlite3MallocZero( nChar*sizeof(WCHAR)+12 ); + if( zWideFilename==0 ){ + return 0; + } + nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, + zWideFilename, nChar); + if( nChar==0 ){ + sqlite3_free(zWideFilename); + zWideFilename = 0; + }else if( nChar>MAX_PATH + && winIsDriveLetterAndColon(zFilename) + && winIsDirSep(zFilename[2]) ){ + memmove(zWideFilename+4, zWideFilename, nChar*sizeof(WCHAR)); + zWideFilename[2] = '\\'; + memcpy(zWideFilename, L"\\\\?\\", 8); + }else if( nChar>MAX_PATH + && winIsDirSep(zFilename[0]) && winIsDirSep(zFilename[1]) + && zFilename[2] != '?' ){ + memmove(zWideFilename+6, zWideFilename, nChar*sizeof(WCHAR)); + memcpy(zWideFilename, L"\\\\?\\UNC", 14); + } + zConverted = zWideFilename; +#else + zConverted = winUtf8ToUnicode(zFilename); +#endif /* __CYGWIN__ */ + } +#if defined(SQLITE_WIN32_HAS_ANSI) && defined(_WIN32) + else{ + zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI()); + } +#endif + /* caller will handle out of memory */ + return zConverted; +} + +/* +** This function is used to open a handle on a *-shm file. ** -** When opening a new shared-memory file, if no other instances of that -** file are currently open, in this process or in other processes, then -** the file must be truncated to zero length or have its header cleared. +** If SQLITE_ENABLE_SETLK_TIMEOUT is defined at build time, then the file +** is opened with FILE_FLAG_OVERLAPPED specified. If not, it is not. +*/ +static int winHandleOpen( + const char *zUtf8, /* File to open */ + int *pbReadonly, /* IN/OUT: True for readonly handle */ + HANDLE *ph /* OUT: New HANDLE for file */ +){ + int rc = SQLITE_OK; + void *zConverted = 0; + int bReadonly = *pbReadonly; + HANDLE h = INVALID_HANDLE_VALUE; + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + const DWORD flag_overlapped = FILE_FLAG_OVERLAPPED; +#else + const DWORD flag_overlapped = 0; +#endif + + /* Convert the filename to the system encoding. */ + zConverted = winConvertFromUtf8Filename(zUtf8); + if( zConverted==0 ){ + OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8)); + rc = SQLITE_IOERR_NOMEM_BKPT; + goto winopenfile_out; + } + + /* Ensure the file we are trying to open is not actually a directory. */ + if( winIsDir(zConverted) ){ + OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8)); + rc = SQLITE_CANTOPEN_ISDIR; + goto winopenfile_out; + } + + /* TODO: platforms. + ** TODO: retry-on-ioerr. + */ + if( osIsNT() ){ +#if SQLITE_OS_WINRT + CREATEFILE2_EXTENDED_PARAMETERS extendedParameters; + memset(&extendedParameters, 0, sizeof(extendedParameters)); + extendedParameters.dwSize = sizeof(extendedParameters); + extendedParameters.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; + extendedParameters.dwFileFlags = flag_overlapped; + extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; + h = osCreateFile2((LPCWSTR)zConverted, + (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)),/* dwDesiredAccess */ + FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ + OPEN_ALWAYS, /* dwCreationDisposition */ + &extendedParameters + ); +#else + h = osCreateFileW((LPCWSTR)zConverted, /* lpFileName */ + (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */ + FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ + NULL, /* lpSecurityAttributes */ + OPEN_ALWAYS, /* dwCreationDisposition */ + FILE_ATTRIBUTE_NORMAL|flag_overlapped, + NULL + ); +#endif + }else{ + /* Due to pre-processor directives earlier in this file, + ** SQLITE_WIN32_HAS_ANSI is always defined if osIsNT() is false. */ +#ifdef SQLITE_WIN32_HAS_ANSI + h = osCreateFileA((LPCSTR)zConverted, + (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */ + FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ + NULL, /* lpSecurityAttributes */ + OPEN_ALWAYS, /* dwCreationDisposition */ + FILE_ATTRIBUTE_NORMAL|flag_overlapped, + NULL + ); +#endif + } + + if( h==INVALID_HANDLE_VALUE ){ + if( bReadonly==0 ){ + bReadonly = 1; + rc = winHandleOpen(zUtf8, &bReadonly, &h); + }else{ + rc = SQLITE_CANTOPEN_BKPT; + } + } + + winopenfile_out: + sqlite3_free(zConverted); + *pbReadonly = bReadonly; + *ph = h; + return rc; +} + + +/* +** Open the shared-memory area associated with database file pDbFd. */ static int winOpenSharedMemory(winFile *pDbFd){ struct winShm *p; /* The connection to be opened */ @@ -50803,98 +51513,83 @@ static int winOpenSharedMemory(winFile *pDbFd){ assert( pDbFd->pShm==0 ); /* Not previously opened */ /* Allocate space for the new sqlite3_shm object. Also speculatively - ** allocate space for a new winShmNode and filename. - */ + ** allocate space for a new winShmNode and filename. */ p = sqlite3MallocZero( sizeof(*p) ); if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT; nName = sqlite3Strlen30(pDbFd->zPath); - pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 ); + pNew = sqlite3MallocZero( sizeof(*pShmNode) + (i64)nName + 17 ); if( pNew==0 ){ sqlite3_free(p); return SQLITE_IOERR_NOMEM_BKPT; } pNew->zFilename = (char*)&pNew[1]; + pNew->hSharedShm = INVALID_HANDLE_VALUE; + pNew->isUnlocked = 1; sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); + /* Open a file-handle on the *-shm file for this connection. This file-handle + ** is only used for locking. The mapping of the *-shm file is created using + ** the shared file handle in winShmNode.hSharedShm. */ + p->bReadonly = sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0); + rc = winHandleOpen(pNew->zFilename, &p->bReadonly, &p->hShm); + /* Look to see if there is an existing winShmNode that can be used. - ** If no matching winShmNode currently exists, create a new one. - */ + ** If no matching winShmNode currently exists, then create a new one. */ winShmEnterMutex(); for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){ /* TBD need to come up with better match here. Perhaps - ** use FILE_ID_BOTH_DIR_INFO Structure. - */ + ** use FILE_ID_BOTH_DIR_INFO Structure. */ if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break; } - if( pShmNode ){ - sqlite3_free(pNew); - }else{ - int inFlags = SQLITE_OPEN_WAL; - int outFlags = 0; - + if( pShmNode==0 ){ pShmNode = pNew; - pNew = 0; - ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE; - pShmNode->pNext = winShmNodeList; - winShmNodeList = pShmNode; + /* Allocate a mutex for this winShmNode object, if one is required. */ if( sqlite3GlobalConfig.bCoreMutex ){ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - if( pShmNode->mutex==0 ){ - rc = SQLITE_IOERR_NOMEM_BKPT; - goto shm_open_err; - } + if( pShmNode->mutex==0 ) rc = SQLITE_IOERR_NOMEM_BKPT; } - if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ - inFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; - }else{ - inFlags |= SQLITE_OPEN_READONLY; - } - rc = winOpen(pDbFd->pVfs, pShmNode->zFilename, - (sqlite3_file*)&pShmNode->hFile, - inFlags, &outFlags); - if( rc!=SQLITE_OK ){ - rc = winLogError(rc, osGetLastError(), "winOpenShm", - pShmNode->zFilename); - goto shm_open_err; + /* Open a file-handle to use for mappings, and for the DMS lock. */ + if( rc==SQLITE_OK ){ + HANDLE h = INVALID_HANDLE_VALUE; + pShmNode->isReadonly = p->bReadonly; + rc = winHandleOpen(pNew->zFilename, &pShmNode->isReadonly, &h); + pShmNode->hSharedShm = h; } - if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1; - rc = winLockSharedMemory(pShmNode); - if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err; + /* If successful, link the new winShmNode into the global list. If an + ** error occurred, free the object. */ + if( rc==SQLITE_OK ){ + pShmNode->pNext = winShmNodeList; + winShmNodeList = pShmNode; + pNew = 0; + }else{ + sqlite3_mutex_free(pShmNode->mutex); + if( pShmNode->hSharedShm!=INVALID_HANDLE_VALUE ){ + osCloseHandle(pShmNode->hSharedShm); + } + } } - /* Make the new connection a child of the winShmNode */ - p->pShmNode = pShmNode; + /* If no error has occurred, link the winShm object to the winShmNode and + ** the winShm to pDbFd. */ + if( rc==SQLITE_OK ){ + p->pShmNode = pShmNode; + pShmNode->nRef++; #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) - p->id = pShmNode->nextShmId++; + p->id = pShmNode->nextShmId++; #endif - pShmNode->nRef++; - pDbFd->pShm = p; - winShmLeaveMutex(); - - /* The reference count on pShmNode has already been incremented under - ** the cover of the winShmEnterMutex() mutex and the pointer from the - ** new (struct winShm) object to the pShmNode has been set. All that is - ** left to do is to link the new object into the linked list starting - ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex - ** mutex. - */ - sqlite3_mutex_enter(pShmNode->mutex); - p->pNext = pShmNode->pFirst; - pShmNode->pFirst = p; - sqlite3_mutex_leave(pShmNode->mutex); - return rc; + pDbFd->pShm = p; + }else if( p ){ + winHandleClose(p->hShm); + sqlite3_free(p); + } - /* Jump here on any error */ -shm_open_err: - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); - winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */ - sqlite3_free(p); - sqlite3_free(pNew); + assert( rc!=SQLITE_OK || pShmNode->isUnlocked==0 || pShmNode->nRegion==0 ); winShmLeaveMutex(); + sqlite3_free(pNew); return rc; } @@ -50909,27 +51604,19 @@ static int winShmUnmap( winFile *pDbFd; /* Database holding shared-memory */ winShm *p; /* The connection to be closed */ winShmNode *pShmNode; /* The underlying shared-memory file */ - winShm **pp; /* For looping over sibling connections */ pDbFd = (winFile*)fd; p = pDbFd->pShm; if( p==0 ) return SQLITE_OK; - pShmNode = p->pShmNode; - - /* Remove connection p from the set of connections associated - ** with pShmNode */ - sqlite3_mutex_enter(pShmNode->mutex); - for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} - *pp = p->pNext; + if( p->hShm!=INVALID_HANDLE_VALUE ){ + osCloseHandle(p->hShm); + } - /* Free the connection p */ - sqlite3_free(p); - pDbFd->pShm = 0; - sqlite3_mutex_leave(pShmNode->mutex); + pShmNode = p->pShmNode; + winShmEnterMutex(); /* If pShmNode->nRef has reached 0, then close the underlying - ** shared-memory file, too */ - winShmEnterMutex(); + ** shared-memory file, too. */ assert( pShmNode->nRef>0 ); pShmNode->nRef--; if( pShmNode->nRef==0 ){ @@ -50937,6 +51624,9 @@ static int winShmUnmap( } winShmLeaveMutex(); + /* Free the connection p */ + sqlite3_free(p); + pDbFd->pShm = 0; return SQLITE_OK; } @@ -50951,10 +51641,9 @@ static int winShmLock( ){ winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */ winShm *p = pDbFd->pShm; /* The shared memory being locked */ - winShm *pX; /* For looping over all siblings */ winShmNode *pShmNode; int rc = SQLITE_OK; /* Result code */ - u16 mask; /* Mask of locks to take or release */ + u16 mask = (u16)((1U<<(ofst+n)) - (1U<pShmNode; @@ -50968,85 +51657,82 @@ static int winShmLock( || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); - mask = (u16)((1U<<(ofst+n)) - (1U<1 || mask==(1<mutex); - if( flags & SQLITE_SHM_UNLOCK ){ - u16 allMask = 0; /* Mask of locks held by siblings */ - - /* See if any siblings hold this same lock */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( pX==p ) continue; - assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); - allMask |= pX->sharedMask; - } + /* Check that, if this to be a blocking lock, no locks that occur later + ** in the following list than the lock being obtained are already held: + ** + ** 1. Checkpointer lock (ofst==1). + ** 2. Write lock (ofst==0). + ** 3. Read locks (ofst>=3 && ofstexclMask|p->sharedMask); + assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( + (ofst!=2) /* not RECOVER */ + && (ofst!=1 || lockMask==0 || lockMask==2) + && (ofst!=0 || lockMask<3) + && (ofst<3 || lockMask<(1<exclMask & mask) + ); + if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask)) + || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask)) + || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)) + ){ - /* Undo the local locks */ - if( rc==SQLITE_OK ){ - p->exclMask &= ~mask; - p->sharedMask &= ~mask; - } - }else if( flags & SQLITE_SHM_SHARED ){ - u16 allShared = 0; /* Union of locks held by connections other than "p" */ + if( flags & SQLITE_SHM_UNLOCK ){ + /* Case (a) - unlock. */ - /* Find out which shared locks are already held by sibling connections. - ** If any sibling already holds an exclusive lock, go ahead and return - ** SQLITE_BUSY. - */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( (pX->exclMask & mask)!=0 ){ - rc = SQLITE_BUSY; - break; - } - allShared |= pX->sharedMask; - } + assert( (p->exclMask & p->sharedMask)==0 ); + assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask ); + assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask ); - /* Get shared locks at the system level, if necessary */ - if( rc==SQLITE_OK ){ - if( (allShared & mask)==0 ){ - rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n); - }else{ - rc = SQLITE_OK; - } - } + rc = winHandleUnlock(p->hShm, ofst+WIN_SHM_BASE, n); - /* Get the local shared locks */ - if( rc==SQLITE_OK ){ - p->sharedMask |= mask; - } - }else{ - /* Make sure no sibling connections hold locks that will block this - ** lock. If any do, return SQLITE_BUSY right away. - */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ - rc = SQLITE_BUSY; - break; + /* If successful, also clear the bits in sharedMask/exclMask */ + if( rc==SQLITE_OK ){ + p->exclMask = (p->exclMask & ~mask); + p->sharedMask = (p->sharedMask & ~mask); } - } - - /* Get the exclusive locks at the system level. Then if successful - ** also mark the local connection as being locked. - */ - if( rc==SQLITE_OK ){ - rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n); + }else{ + int bExcl = ((flags & SQLITE_SHM_EXCLUSIVE) ? 1 : 0); + DWORD nMs = winFileBusyTimeout(pDbFd); + rc = winHandleLockTimeout(p->hShm, ofst+WIN_SHM_BASE, n, bExcl, nMs); if( rc==SQLITE_OK ){ - assert( (p->sharedMask & mask)==0 ); - p->exclMask |= mask; + if( bExcl ){ + p->exclMask = (p->exclMask | mask); + }else{ + p->sharedMask = (p->sharedMask | mask); + } } } } - sqlite3_mutex_leave(pShmNode->mutex); - OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n", - osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask, - sqlite3ErrName(rc))); + + OSTRACE(( + "SHM-LOCK(%d,%d,%d) pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x," + " rc=%s\n", + ofst, n, flags, + osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask, + sqlite3ErrName(rc)) + ); return rc; } @@ -51108,13 +51794,15 @@ static int winShmMap( sqlite3_mutex_enter(pShmNode->mutex); if( pShmNode->isUnlocked ){ - rc = winLockSharedMemory(pShmNode); + /* Take the DMS lock. */ + assert( pShmNode->nRegion==0 ); + rc = winLockSharedMemory(pShmNode, winFileBusyTimeout(pDbFd)); if( rc!=SQLITE_OK ) goto shmpage_out; - pShmNode->isUnlocked = 0; } - assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); + assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); if( pShmNode->nRegion<=iRegion ){ + HANDLE hShared = pShmNode->hSharedShm; struct ShmRegion *apNew; /* New aRegion[] array */ int nByte = (iRegion+1)*szRegion; /* Minimum required file size */ sqlite3_int64 sz; /* Current size of wal-index file */ @@ -51125,10 +51813,9 @@ static int winShmMap( ** Check to see if it has been allocated (i.e. if the wal-index file is ** large enough to contain the requested region). */ - rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz); + rc = winHandleSize(hShared, &sz); if( rc!=SQLITE_OK ){ - rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(), - "winShmMap1", pDbFd->zPath); + rc = winLogError(rc, osGetLastError(), "winShmMap1", pDbFd->zPath); goto shmpage_out; } @@ -51137,19 +51824,17 @@ static int winShmMap( ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned. ** ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate - ** the requested memory region. - */ + ** the requested memory region. */ if( !isWrite ) goto shmpage_out; - rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte); + rc = winHandleTruncate(hShared, nByte); if( rc!=SQLITE_OK ){ - rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(), - "winShmMap2", pDbFd->zPath); + rc = winLogError(rc, osGetLastError(), "winShmMap2", pDbFd->zPath); goto shmpage_out; } } /* Map the requested memory region into this processes address space. */ - apNew = (struct ShmRegion *)sqlite3_realloc64( + apNew = (struct ShmRegion*)sqlite3_realloc64( pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0]) ); if( !apNew ){ @@ -51168,18 +51853,13 @@ static int winShmMap( void *pMap = 0; /* Mapped memory region */ #if SQLITE_OS_WINRT - hMap = osCreateFileMappingFromApp(pShmNode->hFile.h, - NULL, protect, nByte, NULL - ); + hMap = osCreateFileMappingFromApp(hShared, NULL, protect, nByte, NULL); #elif defined(SQLITE_WIN32_HAS_WIDE) - hMap = osCreateFileMappingW(pShmNode->hFile.h, - NULL, protect, 0, nByte, NULL - ); + hMap = osCreateFileMappingW(hShared, NULL, protect, 0, nByte, NULL); #elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA - hMap = osCreateFileMappingA(pShmNode->hFile.h, - NULL, protect, 0, nByte, NULL - ); + hMap = osCreateFileMappingA(hShared, NULL, protect, 0, nByte, NULL); #endif + OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n", osGetCurrentProcessId(), pShmNode->nRegion, nByte, hMap ? "ok" : "failed")); @@ -51222,7 +51902,9 @@ static int winShmMap( }else{ *pp = 0; } - if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; + if( pShmNode->isReadonly && rc==SQLITE_OK ){ + rc = SQLITE_READONLY; + } sqlite3_mutex_leave(pShmNode->mutex); return rc; } @@ -51542,47 +52224,6 @@ static winVfsAppData winNolockAppData = { ** sqlite3_vfs object. */ -#if defined(__CYGWIN__) -/* -** Convert a filename from whatever the underlying operating system -** supports for filenames into UTF-8. Space to hold the result is -** obtained from malloc and must be freed by the calling function. -*/ -static char *winConvertToUtf8Filename(const void *zFilename){ - char *zConverted = 0; - if( osIsNT() ){ - zConverted = winUnicodeToUtf8(zFilename); - } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI()); - } -#endif - /* caller will handle out of memory */ - return zConverted; -} -#endif - -/* -** Convert a UTF-8 filename into whatever form the underlying -** operating system wants filenames in. Space to hold the result -** is obtained from malloc and must be freed by the calling -** function. -*/ -static void *winConvertFromUtf8Filename(const char *zFilename){ - void *zConverted = 0; - if( osIsNT() ){ - zConverted = winUtf8ToUnicode(zFilename); - } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI()); - } -#endif - /* caller will handle out of memory */ - return zConverted; -} - /* ** This function returns non-zero if the specified UTF-8 string buffer ** ends with a directory separator character or one was successfully @@ -51595,7 +52236,14 @@ static int winMakeEndInDirSep(int nBuf, char *zBuf){ if( winIsDirSep(zBuf[nLen-1]) ){ return 1; }else if( nLen+1mxPathname; nBuf = nMax + 2; + nMax = pVfs->mxPathname; + nBuf = 2 + (i64)nMax; zBuf = sqlite3MallocZero( nBuf ); if( !zBuf ){ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); @@ -51672,7 +52321,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ } #if defined(__CYGWIN__) - else{ + else if( osGetenv!=NULL ){ static const char *azDirs[] = { 0, /* getenv("SQLITE_TMPDIR") */ 0, /* getenv("TMPDIR") */ @@ -51688,11 +52337,11 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ unsigned int i; const char *zDir = 0; - if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); - if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); - if( !azDirs[2] ) azDirs[2] = getenv("TMP"); - if( !azDirs[3] ) azDirs[3] = getenv("TEMP"); - if( !azDirs[4] ) azDirs[4] = getenv("USERPROFILE"); + if( !azDirs[0] ) azDirs[0] = osGetenv("SQLITE_TMPDIR"); + if( !azDirs[1] ) azDirs[1] = osGetenv("TMPDIR"); + if( !azDirs[2] ) azDirs[2] = osGetenv("TMP"); + if( !azDirs[3] ) azDirs[3] = osGetenv("TEMP"); + if( !azDirs[4] ) azDirs[4] = osGetenv("USERPROFILE"); for(i=0; inOut ){ + /* SQLite assumes that xFullPathname() nul-terminates the output buffer + ** even if it returns an error. */ + zOut[iOff] = '\0'; + return SQLITE_CANTOPEN_BKPT; + } + sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); + return SQLITE_OK; +} +#endif /* __CYGWIN__ */ /* ** Turn a relative pathname into a full pathname. Write the full @@ -52475,8 +53173,8 @@ static int winFullPathnameNoMutex( int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) - DWORD nByte; +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT + int nByte; void *zConverted; char *zOut; #endif @@ -52489,64 +53187,82 @@ static int winFullPathnameNoMutex( zRelative++; } -#if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); - UNUSED_PARAMETER(nFull); - assert( nFull>=pVfs->mxPathname ); - if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ - /* - ** NOTE: We are dealing with a relative path name and the data - ** directory has been set. Therefore, use it as the basis - ** for converting the relative path name to an absolute - ** one by prepending the data directory and a slash. - */ - char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); - if( !zOut ){ - return SQLITE_IOERR_NOMEM_BKPT; - } - if( cygwin_conv_path( - (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) | - CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){ - sqlite3_free(zOut); - return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno, - "winFullPathname1", zRelative); - }else{ - char *zUtf8 = winConvertToUtf8Filename(zOut); - if( !zUtf8 ){ - sqlite3_free(zOut); - return SQLITE_IOERR_NOMEM_BKPT; - } - sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", - sqlite3_data_directory, winGetDirSep(), zUtf8); - sqlite3_free(zUtf8); - sqlite3_free(zOut); - } - }else{ - char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); - if( !zOut ){ - return SQLITE_IOERR_NOMEM_BKPT; - } - if( cygwin_conv_path( - (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A), - zRelative, zOut, pVfs->mxPathname+1)<0 ){ - sqlite3_free(zOut); - return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno, - "winFullPathname2", zRelative); - }else{ - char *zUtf8 = winConvertToUtf8Filename(zOut); - if( !zUtf8 ){ - sqlite3_free(zOut); - return SQLITE_IOERR_NOMEM_BKPT; - } - sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8); - sqlite3_free(zUtf8); - sqlite3_free(zOut); + +#ifdef __CYGWIN__ + if( osGetcwd ){ + zFull[nFull-1] = '\0'; + if( !winIsDriveLetterAndColon(zRelative) || !winIsDirSep(zRelative[2]) ){ + int rc = SQLITE_OK; + int nLink = 1; /* Number of symbolic links followed so far */ + const char *zIn = zRelative; /* Input path for each iteration of loop */ + char *zDel = 0; + struct stat buf; + + UNUSED_PARAMETER(pVfs); + + do { + /* Call lstat() on path zIn. Set bLink to true if the path is a symbolic + ** link, or false otherwise. */ + int bLink = 0; + if( osLstat && osReadlink ) { + if( osLstat(zIn, &buf)!=0 ){ + int myErrno = osErrno; + if( myErrno!=ENOENT ){ + rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)myErrno, "lstat", zIn); + } + }else{ + bLink = ((buf.st_mode & 0170000) == 0120000); + } + + if( bLink ){ + if( zDel==0 ){ + zDel = sqlite3MallocZero(nFull); + if( zDel==0 ) rc = SQLITE_NOMEM; + }else if( ++nLink>SQLITE_MAX_SYMLINKS ){ + rc = SQLITE_CANTOPEN_BKPT; + } + + if( rc==SQLITE_OK ){ + nByte = osReadlink(zIn, zDel, nFull-1); + if( nByte ==(DWORD)-1 ){ + rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "readlink", zIn); + }else{ + if( zDel[0]!='/' ){ + int n; + for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); + if( nByte+n+1>nFull ){ + rc = SQLITE_CANTOPEN_BKPT; + }else{ + memmove(&zDel[n], zDel, nByte+1); + memcpy(zDel, zIn, n); + nByte += n; + } + } + zDel[nByte] = '\0'; + } + } + + zIn = zDel; + } + } + + assert( rc!=SQLITE_OK || zIn!=zFull || zIn[0]=='/' ); + if( rc==SQLITE_OK && zIn!=zFull ){ + rc = mkFullPathname(zIn, zFull, nFull); + } + if( bLink==0 ) break; + zIn = zFull; + }while( rc==SQLITE_OK ); + + sqlite3_free(zDel); + winSimplifyName(zFull); + return rc; } } - return SQLITE_OK; -#endif +#endif /* __CYGWIN__ */ -#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__) +#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && defined(_WIN32) SimulateIOError( return SQLITE_ERROR ); /* WinCE has no concept of a relative pathname, or so I am told. */ /* WinRT has no way to convert a relative path to an absolute one. */ @@ -52565,7 +53281,8 @@ static int winFullPathnameNoMutex( return SQLITE_OK; #endif -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if defined(_WIN32) /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. This function could fail if, for example, the @@ -52583,6 +53300,7 @@ static int winFullPathnameNoMutex( sqlite3_data_directory, winGetDirSep(), zRelative); return SQLITE_OK; } +#endif zConverted = winConvertFromUtf8Filename(zRelative); if( zConverted==0 ){ return SQLITE_IOERR_NOMEM_BKPT; @@ -52621,13 +53339,12 @@ static int winFullPathnameNoMutex( return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), "winFullPathname3", zRelative); } - nByte += 3; - zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) ); + zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) + 3*sizeof(zTemp[0]) ); if( zTemp==0 ){ sqlite3_free(zConverted); return SQLITE_IOERR_NOMEM_BKPT; } - nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0); + nByte = osGetFullPathNameA((char*)zConverted, nByte+3, zTemp, 0); if( nByte==0 ){ sqlite3_free(zConverted); sqlite3_free(zTemp); @@ -52640,7 +53357,26 @@ static int winFullPathnameNoMutex( } #endif if( zOut ){ +#ifdef __CYGWIN__ + if( memcmp(zOut, "\\\\?\\", 4) ){ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut); + }else if( memcmp(zOut+4, "UNC\\", 4) ){ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+4); + }else{ + char *p = zOut+6; + *p = '\\'; + if( osGetcwd ){ + /* On Cygwin, UNC paths use forward slashes */ + while( *p ){ + if( *p=='\\' ) *p = '/'; + ++p; + } + } + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+6); + } +#else sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut); +#endif /* __CYGWIN__ */ sqlite3_free(zOut); return SQLITE_OK; }else{ @@ -52670,25 +53406,8 @@ static int winFullPathname( */ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ HANDLE h; -#if defined(__CYGWIN__) - int nFull = pVfs->mxPathname+1; - char *zFull = sqlite3MallocZero( nFull ); - void *zConverted = 0; - if( zFull==0 ){ - OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); - return 0; - } - if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){ - sqlite3_free(zFull); - OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); - return 0; - } - zConverted = winConvertFromUtf8Filename(zFull); - sqlite3_free(zFull); -#else void *zConverted = winConvertFromUtf8Filename(zFilename); UNUSED_PARAMETER(pVfs); -#endif if( zConverted==0 ){ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); return 0; @@ -53037,7 +53756,7 @@ SQLITE_API int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==80 ); + assert( ArraySize(aSyscall)==89 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); @@ -53656,13 +54375,13 @@ static int memdbOpen( } if( p==0 ){ MemStore **apNew; - p = sqlite3Malloc( sizeof(*p) + szName + 3 ); + p = sqlite3Malloc( sizeof(*p) + (i64)szName + 3 ); if( p==0 ){ sqlite3_mutex_leave(pVfsMutex); return SQLITE_NOMEM; } apNew = sqlite3Realloc(memdb_g.apMemStore, - sizeof(apNew[0])*(memdb_g.nMemStore+1) ); + sizeof(apNew[0])*(1+(i64)memdb_g.nMemStore) ); if( apNew==0 ){ sqlite3_free(p); sqlite3_mutex_leave(pVfsMutex); @@ -54095,7 +54814,7 @@ SQLITE_PRIVATE int sqlite3MemdbInit(void){ ** no fewer collisions than the no-op *1. */ #define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT) -#define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *)) +#define BITVEC_NPTR ((u32)(BITVEC_USIZE/sizeof(Bitvec *))) /* @@ -54278,7 +54997,7 @@ SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){ } } if( p->iSize<=BITVEC_NBIT ){ - p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1))); + p->u.aBitmap[i/BITVEC_SZELEM] &= ~(BITVEC_TELEM)(1<<(i&(BITVEC_SZELEM-1))); }else{ unsigned int j; u32 *aiValues = pBuf; @@ -54329,7 +55048,7 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){ ** individual bits within V. */ #define SETBIT(V,I) V[I>>3] |= (1<<(I&7)) -#define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7)) +#define CLEARBIT(V,I) V[I>>3] &= ~(BITVEC_TELEM)(1<<(I&7)) #define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0 /* @@ -54372,7 +55091,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){ /* Allocate the Bitvec to be tested and a linear array of ** bits to act as the reference */ pBitvec = sqlite3BitvecCreate( sz ); - pV = sqlite3MallocZero( (sz+7)/8 + 1 ); + pV = sqlite3MallocZero( (7+(i64)sz)/8 + 1 ); pTmpSpace = sqlite3_malloc64(BITVEC_SZ); if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; @@ -55613,10 +56332,6 @@ static SQLITE_WSD struct PCacheGlobal { sqlite3_mutex *mutex; /* Mutex for accessing the following: */ PgFreeslot *pFree; /* Free page blocks */ int nFreeSlot; /* Number of unused pcache slots */ - /* The following value requires a mutex to change. We skip the mutex on - ** reading because (1) most platforms read a 32-bit integer atomically and - ** (2) even if an incorrect value is read, no great harm is done since this - ** is really just an optimization. */ int bUnderPressure; /* True if low on PAGECACHE memory */ } pcache1_g; @@ -55664,7 +56379,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){ pcache1.nReserve = n>90 ? 10 : (n/10 + 1); pcache1.pStart = pBuf; pcache1.pFree = 0; - pcache1.bUnderPressure = 0; + AtomicStore(&pcache1.bUnderPressure,0); while( n-- ){ p = (PgFreeslot*)pBuf; p->pNext = pcache1.pFree; @@ -55732,7 +56447,7 @@ static void *pcache1Alloc(int nByte){ if( p ){ pcache1.pFree = pcache1.pFree->pNext; pcache1.nFreeSlot--; - pcache1.bUnderPressure = pcache1.nFreeSlot=0 ); sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte); sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1); @@ -55771,7 +56486,7 @@ static void pcache1Free(void *p){ pSlot->pNext = pcache1.pFree; pcache1.pFree = pSlot; pcache1.nFreeSlot++; - pcache1.bUnderPressure = pcache1.nFreeSlotszPage+pCache->szExtra)<=pcache1.szSlot ){ - return pcache1.bUnderPressure; + return AtomicLoad(&pcache1.bUnderPressure); }else{ return sqlite3HeapNearlyFull(); } @@ -55919,12 +56634,12 @@ static int pcache1UnderMemoryPressure(PCache1 *pCache){ */ static void pcache1ResizeHash(PCache1 *p){ PgHdr1 **apNew; - unsigned int nNew; - unsigned int i; + u64 nNew; + u32 i; assert( sqlite3_mutex_held(p->pGroup->mutex) ); - nNew = p->nHash*2; + nNew = 2*(u64)p->nHash; if( nNew<256 ){ nNew = 256; } @@ -56147,7 +56862,7 @@ static void pcache1Destroy(sqlite3_pcache *p); static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ PCache1 *pCache; /* The newly created page cache */ PGroup *pGroup; /* The group the new page cache will belong to */ - int sz; /* Bytes of memory required to allocate the new cache */ + i64 sz; /* Bytes of memory required to allocate the new cache */ assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 ); assert( szExtra < 300 ); @@ -58626,7 +59341,7 @@ static void checkPage(PgHdr *pPg){ ** If an error occurs while reading from the journal file, an SQLite ** error code is returned. */ -static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){ +static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u64 nSuper){ int rc; /* Return code */ u32 len; /* Length in bytes of super-journal name */ i64 szJ; /* Total size in bytes of journal file pJrnl */ @@ -59181,6 +59896,15 @@ static void pager_unlock(Pager *pPager){ if( pagerUseWal(pPager) ){ assert( !isOpen(pPager->jfd) ); + if( pPager->eState==PAGER_ERROR ){ + /* If an IO error occurs in wal.c while attempting to wrap the wal file, + ** then the Wal object may be holding a write-lock but no read-lock. + ** This call ensures that the write-lock is dropped as well. We cannot + ** have sqlite3WalEndReadTransaction() drop the write-lock, as it once + ** did, because this would break "BEGIN EXCLUSIVE" handling for + ** SQLITE_ENABLE_SETLK_TIMEOUT builds. */ + sqlite3WalEndWriteTransaction(pPager->pWal); + } sqlite3WalEndReadTransaction(pPager->pWal); pPager->eState = PAGER_OPEN; }else if( !pPager->exclusiveMode ){ @@ -59862,12 +60586,12 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){ char *zJournal; /* Pointer to one journal within MJ file */ char *zSuperPtr; /* Space to hold super-journal filename */ char *zFree = 0; /* Free this buffer */ - int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */ + i64 nSuperPtr; /* Amount of space allocated to zSuperPtr[] */ /* Allocate space for both the pJournal and pSuper file descriptors. ** If successful, open the super-journal file for reading. */ - pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2); + pSuper = (sqlite3_file *)sqlite3MallocZero(2 * (i64)pVfs->szOsFile); if( !pSuper ){ rc = SQLITE_NOMEM_BKPT; pJournal = 0; @@ -59885,11 +60609,14 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){ */ rc = sqlite3OsFileSize(pSuper, &nSuperJournal); if( rc!=SQLITE_OK ) goto delsuper_out; - nSuperPtr = pVfs->mxPathname+1; + nSuperPtr = 1 + (i64)pVfs->mxPathname; + assert( nSuperJournal>=0 && nSuperPtr>0 ); zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2); if( !zFree ){ rc = SQLITE_NOMEM_BKPT; goto delsuper_out; + }else{ + assert( nSuperJournal<=0x7fffffff ); } zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0; zSuperJournal = &zFree[4]; @@ -60150,7 +60877,7 @@ static int pager_playback(Pager *pPager, int isHot){ ** for pageSize. */ zSuper = pPager->pTmpSpace; - rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); + rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname); if( rc==SQLITE_OK && zSuper[0] ){ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res); } @@ -60289,7 +61016,7 @@ static int pager_playback(Pager *pPager, int isHot){ ** which case it requires 4 0x00 bytes in memory immediately before ** the filename. */ zSuper = &pPager->pTmpSpace[4]; - rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); + rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname); testcase( rc!=SQLITE_OK ); } if( rc==SQLITE_OK @@ -62060,6 +62787,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( const char *zUri = 0; /* URI args to copy */ int nUriByte = 1; /* Number of bytes of URI args at *zUri */ + /* Figure out how much space is required for each journal file-handle ** (there are two of them, the main journal and the sub-journal). */ journalFileSize = ROUND8(sqlite3JournalSize(pVfs)); @@ -62085,8 +62813,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen( */ if( zFilename && zFilename[0] ){ const char *z; - nPathname = pVfs->mxPathname+1; - zPathname = sqlite3DbMallocRaw(0, nPathname*2); + nPathname = pVfs->mxPathname + 1; + zPathname = sqlite3DbMallocRaw(0, 2*(i64)nPathname); if( zPathname==0 ){ return SQLITE_NOMEM_BKPT; } @@ -62173,14 +62901,14 @@ SQLITE_PRIVATE int sqlite3PagerOpen( ROUND8(sizeof(*pPager)) + /* Pager structure */ ROUND8(pcacheSize) + /* PCache object */ ROUND8(pVfs->szOsFile) + /* The main db file */ - journalFileSize * 2 + /* The two journal files */ + (u64)journalFileSize * 2 + /* The two journal files */ SQLITE_PTRSIZE + /* Space to hold a pointer */ 4 + /* Database prefix */ - nPathname + 1 + /* database filename */ - nUriByte + /* query parameters */ - nPathname + 8 + 1 + /* Journal filename */ + (u64)nPathname + 1 + /* database filename */ + (u64)nUriByte + /* query parameters */ + (u64)nPathname + 8 + 1 + /* Journal filename */ #ifndef SQLITE_OMIT_WAL - nPathname + 4 + 1 + /* WAL filename */ + (u64)nPathname + 4 + 1 + /* WAL filename */ #endif 3 /* Terminator */ ); @@ -65635,6 +66363,11 @@ struct WalCkptInfo { /* ** An open write-ahead log file is represented by an instance of the ** following object. +** +** writeLock: +** This is usually set to 1 whenever the WRITER lock is held. However, +** if it is set to 2, then the WRITER lock is held but must be released +** by walHandleException() if a SEH exception is thrown. */ struct Wal { sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */ @@ -65725,9 +66458,13 @@ struct WalIterator { u32 *aPgno; /* Array of page numbers. */ int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */ int iZero; /* Frame number associated with aPgno[0] */ - } aSegment[1]; /* One for every 32KB page in the wal-index */ + } aSegment[FLEXARRAY]; /* One for every 32KB page in the wal-index */ }; +/* Size (in bytes) of a WalIterator object suitable for N or fewer segments */ +#define SZ_WALITERATOR(N) \ + (offsetof(WalIterator,aSegment)*(N)*sizeof(struct WalSegment)) + /* ** Define the parameters of the hash tables in the wal-index file. There ** is a hash-table following every HASHTABLE_NPAGE page numbers in the @@ -65886,7 +66623,7 @@ static SQLITE_NOINLINE int walIndexPageRealloc( /* Enlarge the pWal->apWiData[] array if required */ if( pWal->nWiData<=iPage ){ - sqlite3_int64 nByte = sizeof(u32*)*(iPage+1); + sqlite3_int64 nByte = sizeof(u32*)*(1+(i64)iPage); volatile u32 **apNew; apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte); if( !apNew ){ @@ -65995,10 +66732,8 @@ static void walChecksumBytes( s1 = s2 = 0; } - assert( nByte>=8 ); - assert( (nByte&0x00000007)==0 ); - assert( nByte<=65536 ); - assert( nByte%4==0 ); + /* nByte is a multiple of 8 between 8 and 65536 */ + assert( nByte>=8 && (nByte&7)==0 && nByte<=65536 ); if( !nativeCksum ){ do { @@ -67088,8 +67823,7 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){ /* Allocate space for the WalIterator object. */ nSegment = walFramePage(iLast) + 1; - nByte = sizeof(WalIterator) - + (nSegment-1)*sizeof(struct WalSegment) + nByte = SZ_WALITERATOR(nSegment) + iLast*sizeof(ht_slot); p = (WalIterator *)sqlite3_malloc64(nByte + sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) @@ -67160,7 +67894,7 @@ static int walEnableBlockingMs(Wal *pWal, int nMs){ static int walEnableBlocking(Wal *pWal){ int res = 0; if( pWal->db ){ - int tmout = pWal->db->busyTimeout; + int tmout = pWal->db->setlkTimeout; if( tmout ){ res = walEnableBlockingMs(pWal, tmout); } @@ -67546,7 +68280,9 @@ static int walHandleException(Wal *pWal){ static const int S = 1; static const int E = (1<lockMask & ~( + u32 mUnlock; + if( pWal->writeLock==2 ) pWal->writeLock = 0; + mUnlock = pWal->lockMask & ~( (pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock))) | (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0) | (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0) @@ -67818,7 +68554,12 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ if( bWriteLock || SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){ - pWal->writeLock = 1; + /* If the write-lock was just obtained, set writeLock to 2 instead of + ** the usual 1. This causes walIndexPage() to behave as if the + ** write-lock were held (so that it allocates new pages as required), + ** and walHandleException() to unlock the write-lock if a SEH exception + ** is thrown. */ + if( !bWriteLock ) pWal->writeLock = 2; if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ badHdr = walIndexTryHdr(pWal, pChanged); if( badHdr ){ @@ -68603,8 +69344,11 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ ** read-lock. */ SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){ - sqlite3WalEndWriteTransaction(pWal); +#ifndef SQLITE_ENABLE_SETLK_TIMEOUT + assert( pWal->writeLock==0 || pWal->readLock<0 ); +#endif if( pWal->readLock>=0 ){ + sqlite3WalEndWriteTransaction(pWal); walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock)); pWal->readLock = -1; } @@ -68797,7 +69541,7 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){ ** read-transaction was even opened, making this call a no-op. ** Return early. */ if( pWal->writeLock ){ - assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) ); + assert( !memcmp(&pWal->hdr,(void*)pWal->apWiData[0],sizeof(WalIndexHdr)) ); return SQLITE_OK; } #endif @@ -70246,6 +70990,12 @@ struct CellInfo { */ #define BTCURSOR_MAX_DEPTH 20 +/* +** Maximum amount of storage local to a database page, regardless of +** page size. +*/ +#define BT_MAX_LOCAL 65501 /* 65536 - 35 */ + /* ** A cursor is a pointer to a particular entry within a particular ** b-tree within a database file. @@ -70654,7 +71404,7 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){ */ static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){ int i; - int skipOk = 1; + u8 skipOk = 1; Btree *p; assert( sqlite3_mutex_held(db->mutex) ); for(i=0; inDb; i++){ @@ -71510,7 +72260,7 @@ static int saveCursorKey(BtCursor *pCur){ ** below. */ void *pKey; pCur->nKey = sqlite3BtreePayloadSize(pCur); - pKey = sqlite3Malloc( pCur->nKey + 9 + 8 ); + pKey = sqlite3Malloc( ((i64)pCur->nKey) + 9 + 8 ); if( pKey ){ rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ @@ -71800,7 +72550,7 @@ SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){ */ SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){ assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 ); - pCur->hints = x; + pCur->hints = (u8)x; } @@ -71994,14 +72744,15 @@ static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow( static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){ int maxLocal; /* Maximum amount of payload held locally */ maxLocal = pPage->maxLocal; + assert( nPayload>=0 ); if( nPayload<=maxLocal ){ - return nPayload; + return (int)nPayload; }else{ int minLocal; /* Minimum amount of payload held locally */ int surplus; /* Overflow payload available for local storage */ minLocal = pPage->minLocal; - surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize-4); - return ( surplus <= maxLocal ) ? surplus : minLocal; + surplus = (int)(minLocal +(nPayload - minLocal)%(pPage->pBt->usableSize-4)); + return (surplus <= maxLocal) ? surplus : minLocal; } } @@ -72111,11 +72862,13 @@ static void btreeParseCellPtr( pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==(u32)pPage->maxLocal+1 ); + assert( nPayload>=0 ); + assert( pPage->maxLocal <= BT_MAX_LOCAL ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ - pInfo->nSize = nPayload + (u16)(pIter - pCell); + pInfo->nSize = (u16)nPayload + (u16)(pIter - pCell); if( pInfo->nSize<4 ) pInfo->nSize = 4; pInfo->nLocal = (u16)nPayload; }else{ @@ -72148,11 +72901,13 @@ static void btreeParseCellPtrIndex( pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==(u32)pPage->maxLocal+1 ); + assert( nPayload>=0 ); + assert( pPage->maxLocal <= BT_MAX_LOCAL ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ - pInfo->nSize = nPayload + (u16)(pIter - pCell); + pInfo->nSize = (u16)nPayload + (u16)(pIter - pCell); if( pInfo->nSize<4 ) pInfo->nSize = 4; pInfo->nLocal = (u16)nPayload; }else{ @@ -72691,14 +73446,14 @@ static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ ** at the end of the page. So do additional corruption checks inside this ** routine and return SQLITE_CORRUPT if any problems are found. */ -static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ - u16 iPtr; /* Address of ptr to next freeblock */ - u16 iFreeBlk; /* Address of the next freeblock */ +static int freeSpace(MemPage *pPage, int iStart, int iSize){ + int iPtr; /* Address of ptr to next freeblock */ + int iFreeBlk; /* Address of the next freeblock */ u8 hdr; /* Page header size. 0 or 100 */ - u8 nFrag = 0; /* Reduction in fragmentation */ - u16 iOrigSize = iSize; /* Original value of iSize */ - u16 x; /* Offset to cell content area */ - u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ + int nFrag = 0; /* Reduction in fragmentation */ + int iOrigSize = iSize; /* Original value of iSize */ + int x; /* Offset to cell content area */ + int iEnd = iStart + iSize; /* First byte past the iStart buffer */ unsigned char *data = pPage->aData; /* Page content */ u8 *pTmp; /* Temporary ptr into data[] */ @@ -72725,7 +73480,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ } iPtr = iFreeBlk; } - if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ + if( iFreeBlk>(int)pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ return SQLITE_CORRUPT_PAGE(pPage); } assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB ); @@ -72740,7 +73495,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ nFrag = iFreeBlk - iEnd; if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage); iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); - if( iEnd > pPage->pBt->usableSize ){ + if( iEnd > (int)pPage->pBt->usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } iSize = iEnd - iStart; @@ -72761,7 +73516,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ } } if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); - data[hdr+7] -= nFrag; + data[hdr+7] -= (u8)nFrag; } pTmp = &data[hdr+5]; x = get2byte(pTmp); @@ -72782,7 +73537,8 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ /* Insert the new freeblock into the freelist */ put2byte(&data[iPtr], iStart); put2byte(&data[iStart], iFreeBlk); - put2byte(&data[iStart+2], iSize); + assert( iSize>=0 && iSize<=0xffff ); + put2byte(&data[iStart+2], (u16)iSize); } pPage->nFree += iOrigSize; return SQLITE_OK; @@ -73008,7 +73764,7 @@ static int btreeInitPage(MemPage *pPage){ assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); pPage->nOverflow = 0; - pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize; + pPage->cellOffset = (u16)(pPage->hdrOffset + 8 + pPage->childPtrSize); pPage->aCellIdx = data + pPage->childPtrSize + 8; pPage->aDataEnd = pPage->aData + pBt->pageSize; pPage->aDataOfst = pPage->aData + pPage->childPtrSize; @@ -73042,8 +73798,8 @@ static int btreeInitPage(MemPage *pPage){ static void zeroPage(MemPage *pPage, int flags){ unsigned char *data = pPage->aData; BtShared *pBt = pPage->pBt; - u8 hdr = pPage->hdrOffset; - u16 first; + int hdr = pPage->hdrOffset; + int first; assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno || CORRUPT_DB ); assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); @@ -73060,7 +73816,7 @@ static void zeroPage(MemPage *pPage, int flags){ put2byte(&data[hdr+5], pBt->usableSize); pPage->nFree = (u16)(pBt->usableSize - first); decodeFlags(pPage, flags); - pPage->cellOffset = first; + pPage->cellOffset = (u16)first; pPage->aDataEnd = &data[pBt->pageSize]; pPage->aCellIdx = &data[first]; pPage->aDataOfst = &data[pPage->childPtrSize]; @@ -73846,7 +74602,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, BtShared *pBt = p->pBt; assert( nReserve>=0 && nReserve<=255 ); sqlite3BtreeEnter(p); - pBt->nReserveWanted = nReserve; + pBt->nReserveWanted = (u8)nReserve; x = pBt->pageSize - pBt->usableSize; if( nReservebtsFlags & BTS_PAGESIZE_FIXED ){ @@ -73952,7 +74708,7 @@ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) ); if( newFlag>=0 ){ p->pBt->btsFlags &= ~BTS_FAST_SECURE; - p->pBt->btsFlags |= BTS_SECURE_DELETE*newFlag; + p->pBt->btsFlags |= (u16)(BTS_SECURE_DELETE*newFlag); } b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE; sqlite3BtreeLeave(p); @@ -76881,7 +77637,7 @@ SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( rc = SQLITE_CORRUPT_PAGE(pPage); goto moveto_index_finish; } - pCellKey = sqlite3Malloc( nCell+nOverrun ); + pCellKey = sqlite3Malloc( (u64)nCell+(u64)nOverrun ); if( pCellKey==0 ){ rc = SQLITE_NOMEM_BKPT; goto moveto_index_finish; @@ -78400,7 +79156,8 @@ static int rebuildPage( } /* The pPg->nFree field is now set incorrectly. The caller will fix it. */ - pPg->nCell = nCell; + assert( nCell < 10922 ); + pPg->nCell = (u16)nCell; pPg->nOverflow = 0; put2byte(&aData[hdr+1], 0); @@ -78647,9 +79404,13 @@ static int editPage( if( pageInsertArray( pPg, pBegin, &pData, pCellptr, iNew+nCell, nNew-nCell, pCArray - ) ) goto editpage_fail; + ) + ){ + goto editpage_fail; + } - pPg->nCell = nNew; + assert( nNew < 10922 ); + pPg->nCell = (u16)nNew; pPg->nOverflow = 0; put2byte(&aData[hdr+3], pPg->nCell); @@ -78958,7 +79719,7 @@ static int balance_nonroot( int pageFlags; /* Value of pPage->aData[0] */ int iSpace1 = 0; /* First unused byte of aSpace1[] */ int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */ - int szScratch; /* Size of scratch memory requested */ + u64 szScratch; /* Size of scratch memory requested */ MemPage *apOld[NB]; /* pPage and up to two siblings */ MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */ u8 *pRight; /* Location in parent of right-sibling pointer */ @@ -80243,7 +81004,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( if( pCur->info.nKey==pX->nKey ){ BtreePayload x2; x2.pData = pX->pKey; - x2.nData = pX->nKey; + x2.nData = (int)pX->nKey; assert( pX->nKey<=0x7fffffff ); x2.nZero = 0; return btreeOverwriteCell(pCur, &x2); } @@ -80424,7 +81185,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 getCellInfo(pSrc); if( pSrc->info.nPayload<0x80 ){ - *(aOut++) = pSrc->info.nPayload; + *(aOut++) = (u8)pSrc->info.nPayload; }else{ aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload); } @@ -80437,7 +81198,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 nRem = pSrc->info.nPayload; if( nIn==nRem && nInpPage->maxLocal ){ memcpy(aOut, aIn, nIn); - pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace); + pBt->nPreformatSize = nIn + (int)(aOut - pBt->pTmpSpace); return SQLITE_OK; }else{ int rc = SQLITE_OK; @@ -80449,7 +81210,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 u32 nOut; /* Size of output buffer aOut[] */ nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload); - pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace); + pBt->nPreformatSize = (int)nOut + (int)(aOut - pBt->pTmpSpace); if( nOutinfo.nPayload ){ pPgnoOut = &aOut[nOut]; pBt->nPreformatSize += 4; @@ -82070,6 +82831,7 @@ SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){ */ SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ BtShared *pBt = p->pBt; + assert( nBytes==0 || nBytes==sizeof(Schema) ); sqlite3BtreeEnter(p); if( !pBt->pSchema && nBytes ){ pBt->pSchema = sqlite3DbMallocZero(0, nBytes); @@ -83186,7 +83948,7 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ ** corresponding string value, then it is important that the string be ** derived from the numeric value, not the other way around, to ensure ** that the index and table are consistent. See ticket -** https://www.sqlite.org/src/info/343634942dd54ab (2018-01-31) for +** https://sqlite.org/src/info/343634942dd54ab (2018-01-31) for ** an example. ** ** This routine looks at pMem to verify that if it has both a numeric @@ -83372,7 +84134,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ return; } if( pMem->enc!=SQLITE_UTF8 ) return; - if( NEVER(pMem->z==0) ) return; + assert( pMem->z!=0 ); if( pMem->flags & MEM_Dyn ){ if( pMem->xDel==sqlite3_free && sqlite3_msize(pMem->z) >= (u64)(pMem->n+1) @@ -84485,7 +85247,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ if( pRec==0 ){ Index *pIdx = p->pIdx; /* Index being probed */ - int nByte; /* Bytes of space to allocate */ + i64 nByte; /* Bytes of space to allocate */ int i; /* Counter variable */ int nCol = pIdx->nColumn; /* Number of index columns including rowid */ @@ -84551,7 +85313,7 @@ static int valueFromFunction( ){ sqlite3_context ctx; /* Context object for function invocation */ sqlite3_value **apVal = 0; /* Function arguments */ - int nVal = 0; /* Size of apVal[] array */ + int nVal = 0; /* Number of function arguments */ FuncDef *pFunc = 0; /* Function definition */ sqlite3_value *pVal = 0; /* New value */ int rc = SQLITE_OK; /* Return code */ @@ -85549,12 +86311,10 @@ SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall( int eCallCtx /* Calling context */ ){ Vdbe *v = pParse->pVdbe; - int nByte; int addr; sqlite3_context *pCtx; assert( v ); - nByte = sizeof(*pCtx) + (nArg-1)*sizeof(sqlite3_value*); - pCtx = sqlite3DbMallocRawNN(pParse->db, nByte); + pCtx = sqlite3DbMallocRawNN(pParse->db, SZ_CONTEXT(nArg)); if( pCtx==0 ){ assert( pParse->db->mallocFailed ); freeEphemeralFunction(pParse->db, (FuncDef*)pFunc); @@ -85830,7 +86590,7 @@ static Op *opIterNext(VdbeOpIter *p){ } if( pRet->p4type==P4_SUBPROGRAM ){ - int nByte = (p->nSub+1)*sizeof(SubProgram*); + i64 nByte = (1+(u64)p->nSub)*sizeof(SubProgram*); int j; for(j=0; jnSub; j++){ if( p->apSub[j]==pRet->p4.pProgram ) break; @@ -85960,8 +86720,8 @@ SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){ ** (1) For each jump instruction with a negative P2 value (a label) ** resolve the P2 value to an actual address. ** -** (2) Compute the maximum number of arguments used by any SQL function -** and store that value in *pMaxFuncArgs. +** (2) Compute the maximum number of arguments used by the xUpdate/xFilter +** methods of any virtual table and store that value in *pMaxVtabArgs. ** ** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately ** indicate what the prepared statement actually does. @@ -85974,8 +86734,8 @@ SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){ ** script numbers the opcodes correctly. Changes to this routine must be ** coordinated with changes to mkopcodeh.tcl. */ -static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ - int nMaxArgs = *pMaxFuncArgs; +static void resolveP2Values(Vdbe *p, int *pMaxVtabArgs){ + int nMaxVtabArgs = *pMaxVtabArgs; Op *pOp; Parse *pParse = p->pParse; int *aLabel = pParse->aLabel; @@ -86020,15 +86780,19 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ } #ifndef SQLITE_OMIT_VIRTUALTABLE case OP_VUpdate: { - if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; + if( pOp->p2>nMaxVtabArgs ) nMaxVtabArgs = pOp->p2; break; } case OP_VFilter: { int n; + /* The instruction immediately prior to VFilter will be an + ** OP_Integer that sets the "argc" value for the VFilter. See + ** the code where OP_VFilter is generated at tag-20250207a. */ assert( (pOp - p->aOp) >= 3 ); assert( pOp[-1].opcode==OP_Integer ); + assert( pOp[-1].p2==pOp->p3+1 ); n = pOp[-1].p1; - if( n>nMaxArgs ) nMaxArgs = n; + if( n>nMaxVtabArgs ) nMaxVtabArgs = n; /* Fall through into the default case */ /* no break */ deliberate_fall_through } @@ -86069,7 +86833,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ pParse->aLabel = 0; } pParse->nLabel = 0; - *pMaxFuncArgs = nMaxArgs; + *pMaxVtabArgs = nMaxVtabArgs; assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) ); } @@ -86298,7 +87062,7 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus( const char *zName /* Name of table or index being scanned */ ){ if( IS_STMT_SCANSTATUS(p->db) ){ - sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus); + i64 nByte = (1+(i64)p->nScan) * sizeof(ScanStatus); ScanStatus *aNew; aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); if( aNew ){ @@ -86408,6 +87172,9 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){ */ SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){ VdbeOp *pOp = sqlite3VdbeGetLastOp(p); +#ifdef SQLITE_DEBUG + while( pOp->opcode==OP_ReleaseReg ) pOp--; +#endif if( pOp->p3==iDest && pOp->opcode==OP_Column ){ pOp->p5 |= OPFLAG_TYPEOFARG; } @@ -87747,7 +88514,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( int nVar; /* Number of parameters */ int nMem; /* Number of VM memory registers */ int nCursor; /* Number of cursors required */ - int nArg; /* Number of arguments in subprograms */ + int nArg; /* Max number args to xFilter or xUpdate */ int n; /* Loop counter */ struct ReusableSpace x; /* Reusable bulk memory */ @@ -87819,6 +88586,9 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*)); } } +#ifdef SQLITE_DEBUG + p->napArg = nArg; +#endif if( db->mallocFailed ){ p->nVar = 0; @@ -89316,6 +90086,7 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord( ){ UnpackedRecord *p; /* Unpacked record to return */ int nByte; /* Number of bytes required for *p */ + assert( sizeof(UnpackedRecord) + sizeof(Mem)*65536 < 0x7fffffff ); nByte = ROUND8P(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1); p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); if( !p ) return 0; @@ -90622,10 +91393,11 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( preupdate.pCsr = pCsr; preupdate.op = op; preupdate.iNewReg = iReg; - preupdate.keyinfo.db = db; - preupdate.keyinfo.enc = ENC(db); - preupdate.keyinfo.nKeyField = pTab->nCol; - preupdate.keyinfo.aSortFlags = (u8*)&fakeSortOrder; + preupdate.pKeyinfo = (KeyInfo*)&preupdate.keyinfoSpace; + preupdate.pKeyinfo->db = db; + preupdate.pKeyinfo->enc = ENC(db); + preupdate.pKeyinfo->nKeyField = pTab->nCol; + preupdate.pKeyinfo->aSortFlags = (u8*)&fakeSortOrder; preupdate.iKey1 = iKey1; preupdate.iKey2 = iKey2; preupdate.pTab = pTab; @@ -90635,8 +91407,8 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2); db->pPreUpdate = 0; sqlite3DbFree(db, preupdate.aRecord); - vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked); - vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked); + vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pUnpacked); + vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pNewUnpacked); sqlite3VdbeMemRelease(&preupdate.oldipk); if( preupdate.aNew ){ int i; @@ -92467,7 +93239,7 @@ SQLITE_API int sqlite3_bind_text64( assert( xDel!=SQLITE_DYNAMIC ); if( enc!=SQLITE_UTF8 ){ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; - nData &= ~(u16)1; + nData &= ~(u64)1; } return bindText(pStmt, i, zData, nData, xDel, enc); } @@ -92875,7 +93647,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa if( !aRec ) goto preupdate_old_out; rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec); if( rc==SQLITE_OK ){ - p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); + p->pUnpacked = vdbeUnpackRecord(p->pKeyinfo, nRec, aRec); if( !p->pUnpacked ) rc = SQLITE_NOMEM; } if( rc!=SQLITE_OK ){ @@ -92892,7 +93664,9 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa Column *pCol = &p->pTab->aCol[iIdx]; if( pCol->iDflt>0 ){ if( p->apDflt==0 ){ - int nByte = sizeof(sqlite3_value*)*p->pTab->nCol; + int nByte; + assert( sizeof(sqlite3_value*)*UMXV(p->pTab->nCol) < 0x7fffffff ); + nByte = sizeof(sqlite3_value*)*p->pTab->nCol; p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte); if( p->apDflt==0 ) goto preupdate_old_out; } @@ -92938,7 +93712,7 @@ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ #else p = db->pPreUpdate; #endif - return (p ? p->keyinfo.nKeyField : 0); + return (p ? p->pKeyinfo->nKeyField : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -93021,7 +93795,7 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa Mem *pData = &p->v->aMem[p->iNewReg]; rc = ExpandBlob(pData); if( rc!=SQLITE_OK ) goto preupdate_new_out; - pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z); + pUnpack = vdbeUnpackRecord(p->pKeyinfo, pData->n, pData->z); if( !pUnpack ){ rc = SQLITE_NOMEM; goto preupdate_new_out; @@ -93042,7 +93816,8 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa */ assert( p->op==SQLITE_UPDATE ); if( !p->aNew ){ - p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField); + assert( sizeof(Mem)*UMXV(p->pCsr->nField) < 0x7fffffff ); + p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem)*p->pCsr->nField); if( !p->aNew ){ rc = SQLITE_NOMEM; goto preupdate_new_out; @@ -93812,11 +94587,11 @@ static VdbeCursor *allocateCursor( */ Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem; - int nByte; + i64 nByte; VdbeCursor *pCx = 0; - nByte = - ROUND8P(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + - (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0); + nByte = SZ_VDBECURSOR(nField); + assert( ROUND8(nByte)==nByte ); + if( eCurType==CURTYPE_BTREE ) nByte += sqlite3BtreeCursorSize(); assert( iCur>=0 && iCurnCursor ); if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/ @@ -93840,7 +94615,7 @@ static VdbeCursor *allocateCursor( pMem->szMalloc = 0; return 0; } - pMem->szMalloc = nByte; + pMem->szMalloc = (int)nByte; } p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc; @@ -93849,8 +94624,8 @@ static VdbeCursor *allocateCursor( pCx->nField = nField; pCx->aOffset = &pCx->aType[nField]; if( eCurType==CURTYPE_BTREE ){ - pCx->uc.pCursor = (BtCursor*) - &pMem->z[ROUND8P(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; + assert( ROUND8(SZ_VDBECURSOR(nField))==SZ_VDBECURSOR(nField) ); + pCx->uc.pCursor = (BtCursor*)&pMem->z[SZ_VDBECURSOR(nField)]; sqlite3BtreeCursorZero(pCx->uc.pCursor); } return pCx; @@ -94854,7 +95629,7 @@ case OP_Halt: { sqlite3VdbeError(p, "%s", pOp->p4.z); } pcx = (int)(pOp - aOp); - sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg); + sqlite3_log(pOp->p1, "abort at %d: %s; [%s]", pcx, p->zErrMsg, p->zSql); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); @@ -96180,7 +96955,7 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ break; } -/* Opcode: Once P1 P2 * * * +/* Opcode: Once P1 P2 P3 * * ** ** Fall through to the next instruction the first time this opcode is ** encountered on each invocation of the byte-code program. Jump to P2 @@ -96196,6 +96971,12 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ ** whether or not the jump should be taken. The bitmask is necessary ** because the self-altering code trick does not work for recursive ** triggers. +** +** The P3 operand is not used directly by this opcode. However P3 is +** used by the code generator as follows: If this opcode is the start +** of a subroutine and that subroutine uses a Bloom filter, then P3 will +** be the register that holds that Bloom filter. See tag-202407032019 +** in the source code for implementation details. */ case OP_Once: { /* jump */ u32 iAddr; /* Address of this instruction */ @@ -97241,6 +98022,7 @@ case OP_MakeRecord: { zHdr += sqlite3PutVarint(zHdr, serial_type); if( pRec->n ){ assert( pRec->z!=0 ); + assert( pRec->z!=(const char*)sqlite3CtypeMap ); memcpy(zPayload, pRec->z, pRec->n); zPayload += pRec->n; } @@ -99592,7 +100374,7 @@ case OP_RowData: { /* The OP_RowData opcodes always follow OP_NotExists or ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions ** that might invalidate the cursor. - ** If this where not the case, on of the following assert()s + ** If this were not the case, one of the following assert()s ** would fail. Should this ever change (because of changes in the code ** generator) then the fix would be to insert a call to ** sqlite3VdbeCursorMoveto(). @@ -100861,7 +101643,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */ */ case OP_Program: { /* jump0 */ int nMem; /* Number of memory registers for sub-program */ - int nByte; /* Bytes of runtime space required for sub-program */ + i64 nByte; /* Bytes of runtime space required for sub-program */ Mem *pRt; /* Register to allocate runtime space */ Mem *pMem; /* Used to iterate through memory cells */ Mem *pEnd; /* Last memory cell in new array */ @@ -100912,7 +101694,7 @@ case OP_Program: { /* jump0 */ nByte = ROUND8(sizeof(VdbeFrame)) + nMem * sizeof(Mem) + pProgram->nCsr * sizeof(VdbeCursor*) - + (pProgram->nOp + 7)/8; + + (7 + (i64)pProgram->nOp)/8; pFrame = sqlite3DbMallocZero(db, nByte); if( !pFrame ){ goto no_mem; @@ -100920,7 +101702,7 @@ case OP_Program: { /* jump0 */ sqlite3VdbeMemRelease(pRt); pRt->flags = MEM_Blob|MEM_Dyn; pRt->z = (char*)pFrame; - pRt->n = nByte; + pRt->n = (int)nByte; pRt->xDel = sqlite3VdbeFrameMemDel; pFrame->v = p; @@ -101019,12 +101801,14 @@ case OP_Param: { /* out2 */ ** statement counter is incremented (immediate foreign key constraints). */ case OP_FkCounter: { - if( db->flags & SQLITE_DeferFKs ){ - db->nDeferredImmCons += pOp->p2; - }else if( pOp->p1 ){ + if( pOp->p1 ){ db->nDeferredCons += pOp->p2; }else{ - p->nFkConstraint += pOp->p2; + if( db->flags & SQLITE_DeferFKs ){ + db->nDeferredImmCons += pOp->p2; + }else{ + p->nFkConstraint += pOp->p2; + } } break; } @@ -101239,7 +102023,7 @@ case OP_AggStep: { ** ** Note: We could avoid this by using a regular memory cell from aMem[] for ** the accumulator, instead of allocating one here. */ - nAlloc = ROUND8P( sizeof(pCtx[0]) + (n-1)*sizeof(sqlite3_value*) ); + nAlloc = ROUND8P( SZ_CONTEXT(n) ); pCtx = sqlite3DbMallocRawNN(db, nAlloc + sizeof(Mem)); if( pCtx==0 ) goto no_mem; pCtx->pOut = (Mem*)((u8*)pCtx + nAlloc); @@ -101899,6 +102683,7 @@ case OP_VFilter: { /* jump, ncycle */ /* Invoke the xFilter method */ apArg = p->apArg; + assert( nArg<=p->napArg ); for(i = 0; ivtabOnConflict; apArg = p->apArg; pX = &aMem[pOp->p3]; + assert( nArg<=p->napArg ); for(i=0; irc = rc; sqlite3SystemError(db, rc); testcase( sqlite3GlobalConfig.xLog!=0 ); - sqlite3_log(rc, "statement aborts at %d: [%s] %s", - (int)(pOp - aOp), p->zSql, p->zErrMsg); + sqlite3_log(rc, "statement aborts at %d: %s; [%s]", + (int)(pOp - aOp), p->zErrMsg, p->zSql); if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p); if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db); if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){ @@ -102895,6 +103681,7 @@ SQLITE_API int sqlite3_blob_open( char *zErr = 0; Table *pTab; Incrblob *pBlob = 0; + int iDb; Parse sParse; #ifdef SQLITE_ENABLE_API_ARMOR @@ -102940,7 +103727,10 @@ SQLITE_API int sqlite3_blob_open( sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable); } #endif - if( !pTab ){ + if( pTab==0 + || ((iDb = sqlite3SchemaToIndex(db, pTab->pSchema))==1 && + sqlite3OpenTempDatabase(&sParse)) + ){ if( sParse.zErrMsg ){ sqlite3DbFree(db, zErr); zErr = sParse.zErrMsg; @@ -102951,15 +103741,11 @@ SQLITE_API int sqlite3_blob_open( goto blob_open_out; } pBlob->pTab = pTab; - pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; + pBlob->zDb = db->aDb[iDb].zDbSName; /* Now search pTab for the exact column. */ - for(iCol=0; iColnCol; iCol++) { - if( sqlite3StrICmp(pTab->aCol[iCol].zCnName, zColumn)==0 ){ - break; - } - } - if( iCol==pTab->nCol ){ + iCol = sqlite3ColumnIndex(pTab, zColumn); + if( iCol<0 ){ sqlite3DbFree(db, zErr); zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn); rc = SQLITE_ERROR; @@ -103039,7 +103825,6 @@ SQLITE_API int sqlite3_blob_open( {OP_Halt, 0, 0, 0}, /* 5 */ }; Vdbe *v = (Vdbe *)pBlob->pStmt; - int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); VdbeOp *aOp; sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag, @@ -103617,9 +104402,12 @@ struct VdbeSorter { u8 iPrev; /* Previous thread used to flush PMA */ u8 nTask; /* Size of aTask[] array */ u8 typeMask; - SortSubtask aTask[1]; /* One or more subtasks */ + SortSubtask aTask[FLEXARRAY]; /* One or more subtasks */ }; +/* Size (in bytes) of a VdbeSorter object that works with N or fewer subtasks */ +#define SZ_VDBESORTER(N) (offsetof(VdbeSorter,aTask)+(N)*sizeof(SortSubtask)) + #define SORTER_TYPE_INTEGER 0x01 #define SORTER_TYPE_TEXT 0x02 @@ -104221,7 +105009,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( VdbeSorter *pSorter; /* The new sorter */ KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */ int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */ - int sz; /* Size of pSorter in bytes */ + i64 sz; /* Size of pSorter in bytes */ int rc = SQLITE_OK; #if SQLITE_MAX_WORKER_THREADS==0 # define nWorker 0 @@ -104249,8 +105037,10 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( assert( pCsr->pKeyInfo ); assert( !pCsr->isEphemeral ); assert( pCsr->eCurType==CURTYPE_SORTER ); - szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*); - sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); + assert( sizeof(KeyInfo) + UMXV(pCsr->pKeyInfo->nKeyField)*sizeof(CollSeq*) + < 0x7fffffff ); + szKeyInfo = SZ_KEYINFO(pCsr->pKeyInfo->nKeyField+1); + sz = SZ_VDBESORTER(nWorker+1); pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); pCsr->uc.pSorter = pSorter; @@ -104462,7 +105252,7 @@ static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){ */ static MergeEngine *vdbeMergeEngineNew(int nReader){ int N = 2; /* Smallest power of two >= nReader */ - int nByte; /* Total bytes of space to allocate */ + i64 nByte; /* Total bytes of space to allocate */ MergeEngine *pNew; /* Pointer to allocated object to return */ assert( nReader<=SORTER_MAX_MERGE_COUNT ); @@ -104714,6 +105504,10 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ p->u.pNext = 0; for(i=0; aSlot[i]; i++){ p = vdbeSorterMerge(pTask, p, aSlot[i]); + /* ,--Each aSlot[] holds twice as much as the previous. So we cannot use + ** | up all 64 aSlots[] with only a 64-bit address space. + ** v */ + assert( iop on success */ Table *pTab = 0; /* Table holding the row */ - Column *pCol; /* A column of pTab */ ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */ const char *zCol = pRight->u.zToken; @@ -107556,7 +108349,6 @@ static int lookupName( if( pSrcList ){ for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ - u8 hCol; pTab = pItem->pSTab; assert( pTab!=0 && pTab->zName!=0 ); assert( pTab->nCol>0 || pParse->nErr ); @@ -107644,43 +108436,38 @@ static int lookupName( sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab); } } - hCol = sqlite3StrIHash(zCol); - for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ - if( pCol->hName==hCol - && sqlite3StrICmp(pCol->zCnName, zCol)==0 - ){ - if( cnt>0 ){ - if( pItem->fg.isUsing==0 - || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0 - ){ - /* Two or more tables have the same column name which is - ** not joined by USING. This is an error. Signal as much - ** by clearing pFJMatch and letting cnt go above 1. */ - sqlite3ExprListDelete(db, pFJMatch); - pFJMatch = 0; - }else - if( (pItem->fg.jointype & JT_RIGHT)==0 ){ - /* An INNER or LEFT JOIN. Use the left-most table */ - continue; - }else - if( (pItem->fg.jointype & JT_LEFT)==0 ){ - /* A RIGHT JOIN. Use the right-most table */ - cnt = 0; - sqlite3ExprListDelete(db, pFJMatch); - pFJMatch = 0; - }else{ - /* For a FULL JOIN, we must construct a coalesce() func */ - extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); - } - } - cnt++; - pMatch = pItem; - /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ - pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; - if( pItem->fg.isNestedFrom ){ - sqlite3SrcItemColumnUsed(pItem, j); + j = sqlite3ColumnIndex(pTab, zCol); + if( j>=0 ){ + if( cnt>0 ){ + if( pItem->fg.isUsing==0 + || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0 + ){ + /* Two or more tables have the same column name which is + ** not joined by USING. This is an error. Signal as much + ** by clearing pFJMatch and letting cnt go above 1. */ + sqlite3ExprListDelete(db, pFJMatch); + pFJMatch = 0; + }else + if( (pItem->fg.jointype & JT_RIGHT)==0 ){ + /* An INNER or LEFT JOIN. Use the left-most table */ + continue; + }else + if( (pItem->fg.jointype & JT_LEFT)==0 ){ + /* A RIGHT JOIN. Use the right-most table */ + cnt = 0; + sqlite3ExprListDelete(db, pFJMatch); + pFJMatch = 0; + }else{ + /* For a FULL JOIN, we must construct a coalesce() func */ + extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); } - break; + } + cnt++; + pMatch = pItem; + /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ + pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; + if( pItem->fg.isNestedFrom ){ + sqlite3SrcItemColumnUsed(pItem, j); } } if( 0==cnt && VisibleRowid(pTab) ){ @@ -107770,23 +108557,18 @@ static int lookupName( if( pTab ){ int iCol; - u8 hCol = sqlite3StrIHash(zCol); pSchema = pTab->pSchema; cntTab++; - for(iCol=0, pCol=pTab->aCol; iColnCol; iCol++, pCol++){ - if( pCol->hName==hCol - && sqlite3StrICmp(pCol->zCnName, zCol)==0 - ){ - if( iCol==pTab->iPKey ){ - iCol = -1; - } - break; + iCol = sqlite3ColumnIndex(pTab, zCol); + if( iCol>=0 ){ + if( pTab->iPKey==iCol ) iCol = -1; + }else{ + if( sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){ + iCol = -1; + }else{ + iCol = pTab->nCol; } } - if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){ - /* IMP: R-51414-32910 */ - iCol = -1; - } if( iColnCol ){ cnt++; pMatch = 0; @@ -108425,13 +109207,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ ** sqlite_version() that might change over time cannot be used ** in an index or generated column. Curiously, they can be used ** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all - ** all this. */ + ** allow this. */ sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr|NC_PartIdx|NC_GenCol, 0, pExpr); }else{ assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */ pExpr->op2 = pNC->ncFlags & NC_SelfRef; - if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); } if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 && pParse->nested==0 @@ -108447,6 +109228,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 && !IN_RENAME_OBJECT ){ + if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); sqlite3ExprFunctionUsable(pParse, pExpr, pDef); } } @@ -109500,20 +110282,22 @@ SQLITE_PRIVATE int sqlite3ResolveSelfReference( Expr *pExpr, /* Expression to resolve. May be NULL. */ ExprList *pList /* Expression list to resolve. May be NULL. */ ){ - SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ + SrcList *pSrc; /* Fake SrcList for pParse->pNewTable */ NameContext sNC; /* Name context for pParse->pNewTable */ int rc; + u8 srcSpace[SZ_SRCLIST_1]; /* Memory space for the fake SrcList */ assert( type==0 || pTab!=0 ); assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr || type==NC_GenCol || pTab==0 ); memset(&sNC, 0, sizeof(sNC)); - memset(&sSrc, 0, sizeof(sSrc)); + pSrc = (SrcList*)srcSpace; + memset(pSrc, 0, SZ_SRCLIST_1); if( pTab ){ - sSrc.nSrc = 1; - sSrc.a[0].zName = pTab->zName; - sSrc.a[0].pSTab = pTab; - sSrc.a[0].iCursor = -1; + pSrc->nSrc = 1; + pSrc->a[0].zName = pTab->zName; + pSrc->a[0].pSTab = pTab; + pSrc->a[0].iCursor = -1; if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){ /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP ** schema elements */ @@ -109521,7 +110305,7 @@ SQLITE_PRIVATE int sqlite3ResolveSelfReference( } } sNC.pParse = pParse; - sNC.pSrcList = &sSrc; + sNC.pSrcList = pSrc; sNC.ncFlags = type | NC_IsDDL; if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc; if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList); @@ -111270,7 +112054,7 @@ static Expr *exprDup( SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p){ With *pRet = 0; if( p ){ - sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1); + sqlite3_int64 nByte = SZ_WITH(p->nCte); pRet = sqlite3DbMallocZero(db, nByte); if( pRet ){ int i; @@ -111381,7 +112165,6 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int } pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName); pItem->fg = pOldItem->fg; - pItem->fg.done = 0; pItem->u = pOldItem->u; } return pNew; @@ -111398,11 +112181,9 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){ SrcList *pNew; int i; - int nByte; assert( db!=0 ); if( p==0 ) return 0; - nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0); - pNew = sqlite3DbMallocRawNN(db, nByte ); + pNew = sqlite3DbMallocRawNN(db, SZ_SRCLIST(p->nSrc) ); if( pNew==0 ) return 0; pNew->nSrc = pNew->nAlloc = p->nSrc; for(i=0; inSrc; i++){ @@ -111464,7 +112245,7 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){ int i; assert( db!=0 ); if( p==0 ) return 0; - pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew)+(p->nId-1)*sizeof(p->a[0]) ); + pNew = sqlite3DbMallocRawNN(db, SZ_IDLIST(p->nId)); if( pNew==0 ) return 0; pNew->nId = p->nId; for(i=0; inId; i++){ @@ -111496,7 +112277,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int fla pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); pNew->iLimit = 0; pNew->iOffset = 0; - pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; + pNew->selFlags = p->selFlags & ~(u32)SF_UsesEphemeral; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = p->nSelectRow; @@ -111548,7 +112329,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendNew( struct ExprList_item *pItem; ExprList *pList; - pList = sqlite3DbMallocRawNN(db, sizeof(ExprList)+sizeof(pList->a[0])*4 ); + pList = sqlite3DbMallocRawNN(db, SZ_EXPRLIST(4)); if( pList==0 ){ sqlite3ExprDelete(db, pExpr); return 0; @@ -111568,8 +112349,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendGrow( struct ExprList_item *pItem; ExprList *pNew; pList->nAlloc *= 2; - pNew = sqlite3DbRealloc(db, pList, - sizeof(*pList)+(pList->nAlloc-1)*sizeof(pList->a[0])); + pNew = sqlite3DbRealloc(db, pList, SZ_EXPRLIST(pList->nAlloc)); if( pNew==0 ){ sqlite3ExprListDelete(db, pList); sqlite3ExprDelete(db, pExpr); @@ -112498,13 +113278,7 @@ SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab){ int ii; assert( VisibleRowid(pTab) ); for(ii=0; iinCol; iCol++){ - if( sqlite3_stricmp(azOpt[ii], pTab->aCol[iCol].zCnName)==0 ) break; - } - if( iCol==pTab->nCol ){ - return azOpt[ii]; - } + if( sqlite3ColumnIndex(pTab, azOpt[ii])<0 ) return azOpt[ii]; } return 0; } @@ -112908,7 +113682,7 @@ static char *exprINAffinity(Parse *pParse, const Expr *pExpr){ char *zRet; assert( pExpr->op==TK_IN ); - zRet = sqlite3DbMallocRaw(pParse->db, nVal+1); + zRet = sqlite3DbMallocRaw(pParse->db, 1+(i64)nVal); if( zRet ){ int i; for(i=0; idb, pCopy); sqlite3DbFree(pParse->db, dest.zAffSdst); if( addrBloom ){ + /* Remember that location of the Bloom filter in the P3 operand + ** of the OP_Once that began this subroutine. tag-202407032019 */ sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; if( dest.iSDParm2==0 ){ - sqlite3VdbeChangeToNoop(v, addrBloom); - }else{ - sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; + /* If the Bloom filter won't actually be used, keep it small */ + sqlite3VdbeGetOp(v, addrBloom)->p1 = 10; } } if( rc ){ @@ -113619,7 +114394,7 @@ static void sqlite3ExprCodeIN( if( ExprHasProperty(pExpr, EP_Subrtn) ){ const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr); assert( pOp->opcode==OP_Once || pParse->nErr ); - if( pOp->opcode==OP_Once && pOp->p3>0 ){ + if( pOp->opcode==OP_Once && pOp->p3>0 ){ /* tag-202407032019 */ assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ); sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse, rLhs, nVector); VdbeCoverage(v); @@ -114211,7 +114986,7 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup( /* -** Expresion pExpr is guaranteed to be a TK_COLUMN or equivalent. This +** Expression pExpr is guaranteed to be a TK_COLUMN or equivalent. This ** function checks the Parse.pIdxPartExpr list to see if this column ** can be replaced with a constant value. If so, it generates code to ** put the constant value in a register (ideally, but not necessarily, @@ -115468,11 +116243,11 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - sqlite3VdbeTypeofColumn(v, r1); + assert( regFree1==0 || regFree1==r1 ); + if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1); sqlite3VdbeAddOp2(v, op, r1, dest); VdbeCoverageIf(v, op==TK_ISNULL); VdbeCoverageIf(v, op==TK_NOTNULL); - testcase( regFree1==0 ); break; } case TK_BETWEEN: { @@ -115643,11 +116418,11 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int case TK_ISNULL: case TK_NOTNULL: { r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - sqlite3VdbeTypeofColumn(v, r1); + assert( regFree1==0 || regFree1==r1 ); + if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1); sqlite3VdbeAddOp2(v, op, r1, dest); testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL); testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL); - testcase( regFree1==0 ); break; } case TK_BETWEEN: { @@ -117452,13 +118227,13 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ assert( pNew->nCol>0 ); nAlloc = (((pNew->nCol-1)/8)*8)+8; assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 ); - pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc); + pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*(u32)nAlloc); pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName); if( !pNew->aCol || !pNew->zName ){ assert( db->mallocFailed ); goto exit_begin_add_column; } - memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); + memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*(size_t)pNew->nCol); for(i=0; inCol; i++){ Column *pCol = &pNew->aCol[i]; pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName); @@ -117553,10 +118328,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn( ** altered. Set iCol to be the index of the column being renamed */ zOld = sqlite3NameFromToken(db, pOld); if( !zOld ) goto exit_rename_column; - for(iCol=0; iColnCol; iCol++){ - if( 0==sqlite3StrICmp(pTab->aCol[iCol].zCnName, zOld) ) break; - } - if( iCol==pTab->nCol ){ + iCol = sqlite3ColumnIndex(pTab, zOld); + if( iCol<0 ){ sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pOld); goto exit_rename_column; } @@ -118059,6 +118832,7 @@ static int renameParseSql( int bTemp /* True if SQL is from temp schema */ ){ int rc; + u64 flags; sqlite3ParseObjectInit(p, db); if( zSql==0 ){ @@ -118067,11 +118841,21 @@ static int renameParseSql( if( sqlite3StrNICmp(zSql,"CREATE ",7)!=0 ){ return SQLITE_CORRUPT_BKPT; } - db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb); + if( bTemp ){ + db->init.iDb = 1; + }else{ + int iDb = sqlite3FindDbName(db, zDb); + assert( iDb>=0 && iDb<=0xff ); + db->init.iDb = (u8)iDb; + } p->eParseMode = PARSE_MODE_RENAME; p->db = db; p->nQueryLoop = 1; + flags = db->flags; + testcase( (db->flags & SQLITE_Comments)==0 && strstr(zSql," /* ")!=0 ); + db->flags |= SQLITE_Comments; rc = sqlite3RunParser(p, zSql); + db->flags = flags; if( db->mallocFailed ) rc = SQLITE_NOMEM; if( rc==SQLITE_OK && NEVER(p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0) @@ -118134,10 +118918,11 @@ static int renameEditSql( nQuot = sqlite3Strlen30(zQuot)-1; } - assert( nQuot>=nNew ); - zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1); + assert( nQuot>=nNew && nSql>=0 && nNew>=0 ); + zOut = sqlite3DbMallocZero(db, (u64)nSql + pRename->nList*(u64)nQuot + 1); }else{ - zOut = (char*)sqlite3DbMallocZero(db, (nSql*2+1) * 3); + assert( nSql>0 ); + zOut = (char*)sqlite3DbMallocZero(db, (2*(u64)nSql + 1) * 3); if( zOut ){ zBuf1 = &zOut[nSql*2+1]; zBuf2 = &zOut[nSql*4+2]; @@ -118149,16 +118934,17 @@ static int renameEditSql( ** with the new column name, or with single-quoted versions of themselves. ** All that remains is to construct and return the edited SQL string. */ if( zOut ){ - int nOut = nSql; - memcpy(zOut, zSql, nSql); + i64 nOut = nSql; + assert( nSql>0 ); + memcpy(zOut, zSql, (size_t)nSql); while( pRename->pList ){ int iOff; /* Offset of token to replace in zOut */ - u32 nReplace; + i64 nReplace; const char *zReplace; RenameToken *pBest = renameColumnTokenNext(pRename); if( zNew ){ - if( bQuote==0 && sqlite3IsIdChar(*pBest->t.z) ){ + if( bQuote==0 && sqlite3IsIdChar(*(u8*)pBest->t.z) ){ nReplace = nNew; zReplace = zNew; }else{ @@ -118176,14 +118962,15 @@ static int renameEditSql( memcpy(zBuf1, pBest->t.z, pBest->t.n); zBuf1[pBest->t.n] = 0; sqlite3Dequote(zBuf1); - sqlite3_snprintf(nSql*2, zBuf2, "%Q%s", zBuf1, + assert( nSql < 0x15555554 /* otherwise malloc would have failed */ ); + sqlite3_snprintf((int)(nSql*2), zBuf2, "%Q%s", zBuf1, pBest->t.z[pBest->t.n]=='\'' ? " " : "" ); zReplace = zBuf2; nReplace = sqlite3Strlen30(zReplace); } - iOff = pBest->t.z - zSql; + iOff = (int)(pBest->t.z - zSql); if( pBest->t.n!=nReplace ){ memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n], nOut - (iOff + pBest->t.n) @@ -118209,11 +118996,12 @@ static int renameEditSql( ** Set all pEList->a[].fg.eEName fields in the expression-list to val. */ static void renameSetENames(ExprList *pEList, int val){ + assert( val==ENAME_NAME || val==ENAME_TAB || val==ENAME_SPAN ); if( pEList ){ int i; for(i=0; inExpr; i++){ assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME ); - pEList->a[i].fg.eEName = val; + pEList->a[i].fg.eEName = val&0x3; } } } @@ -118470,7 +119258,7 @@ static void renameColumnFunc( if( sParse.pNewTable ){ if( IsView(sParse.pNewTable) ){ Select *pSelect = sParse.pNewTable->u.view.pSelect; - pSelect->selFlags &= ~SF_View; + pSelect->selFlags &= ~(u32)SF_View; sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, pSelect, 0); rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); @@ -118688,7 +119476,7 @@ static void renameTableFunc( sNC.pParse = &sParse; assert( pSelect->selFlags & SF_View ); - pSelect->selFlags &= ~SF_View; + pSelect->selFlags &= ~(u32)SF_View; sqlite3SelectPrep(&sParse, pTab->u.view.pSelect, &sNC); if( sParse.nErr ){ rc = sParse.rc; @@ -118861,7 +119649,7 @@ static void renameQuotefixFunc( if( sParse.pNewTable ){ if( IsView(sParse.pNewTable) ){ Select *pSelect = sParse.pNewTable->u.view.pSelect; - pSelect->selFlags &= ~SF_View; + pSelect->selFlags &= ~(u32)SF_View; sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, pSelect, 0); rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); @@ -118960,10 +119748,10 @@ static void renameTableTest( if( zDb && zInput ){ int rc; Parse sParse; - int flags = db->flags; + u64 flags = db->flags; if( bNoDQS ) db->flags &= ~(SQLITE_DqsDML|SQLITE_DqsDDL); rc = renameParseSql(&sParse, zDb, db, zInput, bTemp); - db->flags |= (flags & (SQLITE_DqsDML|SQLITE_DqsDDL)); + db->flags = flags; if( rc==SQLITE_OK ){ if( isLegacy==0 && sParse.pNewTable && IsView(sParse.pNewTable) ){ NameContext sNC; @@ -119455,7 +120243,8 @@ static void openStatTable( sqlite3NestedParse(pParse, "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols ); - aRoot[i] = (u32)pParse->regRoot; + assert( pParse->isCreate || pParse->nErr ); + aRoot[i] = (u32)pParse->u1.cr.regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; } }else{ @@ -119646,7 +120435,7 @@ static void statInit( int nCol; /* Number of columns in index being sampled */ int nKeyCol; /* Number of key columns */ int nColUp; /* nCol rounded up for alignment */ - int n; /* Bytes of space to allocate */ + i64 n; /* Bytes of space to allocate */ sqlite3 *db = sqlite3_context_db_handle(context); /* Database connection */ #ifdef SQLITE_ENABLE_STAT4 /* Maximum number of samples. 0 if STAT4 data is not collected */ @@ -119682,7 +120471,7 @@ static void statInit( p->db = db; p->nEst = sqlite3_value_int64(argv[2]); p->nRow = 0; - p->nLimit = sqlite3_value_int64(argv[3]); + p->nLimit = sqlite3_value_int(argv[3]); p->nCol = nCol; p->nKeyCol = nKeyCol; p->nSkipAhead = 0; @@ -120815,16 +121604,6 @@ static void decodeIntArray( while( z[0]!=0 && z[0]!=' ' ) z++; while( z[0]==' ' ) z++; } - - /* Set the bLowQual flag if the peak number of rows obtained - ** from a full equality match is so large that a full table scan - ** seems likely to be faster than using the index. - */ - if( aLog[0] > 66 /* Index has more than 100 rows */ - && aLog[0] <= aLog[nOut-1] /* And only a single value seen */ - ){ - pIndex->bLowQual = 1; - } } } @@ -121420,7 +122199,7 @@ static void attachFunc( if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ - aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); + aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(1+(i64)db->nDb)); if( aNew==0 ) return; } db->aDb = aNew; @@ -121491,6 +122270,13 @@ static void attachFunc( sqlite3BtreeEnterAll(db); db->init.iDb = 0; db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( db->setlkFlags & SQLITE_SETLK_BLOCK_ON_CONNECT ){ + int val = 1; + sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pNew->pBt)); + sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, &val); + } +#endif if( !REOPEN_AS_MEMDB(db) ){ rc = sqlite3Init(db, &zErrDyn); } @@ -122213,6 +122999,7 @@ static SQLITE_NOINLINE void lockTable( } } + assert( pToplevel->nTableLock < 0x7fff0000 ); nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1); pToplevel->aTableLock = sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes); @@ -122313,10 +123100,12 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort)); if( v ){ if( pParse->bReturning ){ - Returning *pReturning = pParse->u1.pReturning; + Returning *pReturning; int addrRewind; int reg; + assert( !pParse->isCreate ); + pReturning = pParse->u1.d.pReturning; if( pReturning->nRetCol ){ sqlite3VdbeAddOp0(v, OP_FkCheck); addrRewind = @@ -122392,7 +123181,9 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ } if( pParse->bReturning ){ - Returning *pRet = pParse->u1.pReturning; + Returning *pRet; + assert( !pParse->isCreate ); + pRet = pParse->u1.d.pReturning; if( pRet->nRetCol ){ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol); } @@ -123207,10 +123998,16 @@ SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table *pTab){ ** find the (first) offset of that column in index pIdx. Or return -1 ** if column iCol is not used in index pIdx. */ -SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){ +SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index *pIdx, int iCol){ int i; + i16 iCol16; + assert( iCol>=(-1) && iCol<=SQLITE_MAX_COLUMN ); + assert( pIdx->nColumn<=SQLITE_MAX_COLUMN+1 ); + iCol16 = iCol; for(i=0; inColumn; i++){ - if( iCol==pIdx->aiColumn[i] ) return i; + if( iCol16==pIdx->aiColumn[i] ){ + return i; + } } return -1; } @@ -123464,8 +124261,9 @@ SQLITE_PRIVATE void sqlite3StartTable( /* If the file format and encoding in the database have not been set, ** set them now. */ - reg1 = pParse->regRowid = ++pParse->nMem; - reg2 = pParse->regRoot = ++pParse->nMem; + assert( pParse->isCreate ); + reg1 = pParse->u1.cr.regRowid = ++pParse->nMem; + reg2 = pParse->u1.cr.regRoot = ++pParse->nMem; reg3 = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT); sqlite3VdbeUsesBtree(v, iDb); @@ -123480,8 +124278,8 @@ SQLITE_PRIVATE void sqlite3StartTable( ** The record created does not contain anything yet. It will be replaced ** by the real entry in code generated at sqlite3EndTable(). ** - ** The rowid for the new entry is left in register pParse->regRowid. - ** The root page number of the new table is left in reg pParse->regRoot. + ** The rowid for the new entry is left in register pParse->u1.cr.regRowid. + ** The root page of the new table is left in reg pParse->u1.cr.regRoot. ** The rowid and root page number values are needed by the code that ** sqlite3EndTable will generate. */ @@ -123492,7 +124290,7 @@ SQLITE_PRIVATE void sqlite3StartTable( #endif { assert( !pParse->bReturning ); - pParse->u1.addrCrTab = + pParse->u1.cr.addrCrTab = sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY); } sqlite3OpenSchemaTable(pParse, iDb); @@ -123570,7 +124368,8 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){ sqlite3ExprListDelete(db, pList); return; } - pParse->u1.pReturning = pRet; + assert( !pParse->isCreate ); + pParse->u1.d.pReturning = pRet; pRet->pParse = pParse; pRet->pReturnEL = pList; sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet); @@ -123612,7 +124411,6 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ char *zType; Column *pCol; sqlite3 *db = pParse->db; - u8 hName; Column *aNew; u8 eType = COLTYPE_CUSTOM; u8 szEst = 1; @@ -123666,13 +124464,10 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ memcpy(z, sName.z, sName.n); z[sName.n] = 0; sqlite3Dequote(z); - hName = sqlite3StrIHash(z); - for(i=0; inCol; i++){ - if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zCnName)==0 ){ - sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); - sqlite3DbFree(db, z); - return; - } + if( p->nCol && sqlite3ColumnIndex(p, z)>=0 ){ + sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); + sqlite3DbFree(db, z); + return; } aNew = sqlite3DbRealloc(db,p->aCol,((i64)p->nCol+1)*sizeof(p->aCol[0])); if( aNew==0 ){ @@ -123683,7 +124478,7 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ pCol = &p->aCol[p->nCol]; memset(pCol, 0, sizeof(p->aCol[0])); pCol->zCnName = z; - pCol->hName = hName; + pCol->hName = sqlite3StrIHash(z); sqlite3ColumnPropertiesFromName(p, pCol); if( sType.n==0 ){ @@ -123707,9 +124502,14 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ pCol->affinity = sqlite3AffinityType(zType, pCol); pCol->colFlags |= COLFLAG_HASTYPE; } + if( p->nCol<=0xff ){ + u8 h = pCol->hName % sizeof(p->aHx); + p->aHx[h] = p->nCol; + } p->nCol++; p->nNVCol++; - pParse->constraintName.n = 0; + assert( pParse->isCreate ); + pParse->u1.cr.constraintName.n = 0; } /* @@ -123973,15 +124773,11 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( assert( pCExpr!=0 ); sqlite3StringToId(pCExpr); if( pCExpr->op==TK_ID ){ - const char *zCName; assert( !ExprHasProperty(pCExpr, EP_IntValue) ); - zCName = pCExpr->u.zToken; - for(iCol=0; iColnCol; iCol++){ - if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zCnName)==0 ){ - pCol = &pTab->aCol[iCol]; - makeColumnPartOfPrimaryKey(pParse, pCol); - break; - } + iCol = sqlite3ColumnIndex(pTab, pCExpr->u.zToken); + if( iCol>=0 ){ + pCol = &pTab->aCol[iCol]; + makeColumnPartOfPrimaryKey(pParse, pCol); } } } @@ -124033,8 +124829,10 @@ SQLITE_PRIVATE void sqlite3AddCheckConstraint( && !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt) ){ pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); - if( pParse->constraintName.n ){ - sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1); + assert( pParse->isCreate ); + if( pParse->u1.cr.constraintName.n ){ + sqlite3ExprListSetName(pParse, pTab->pCheck, + &pParse->u1.cr.constraintName, 1); }else{ Token t; for(zStart++; sqlite3Isspace(zStart[0]); zStart++){} @@ -124229,7 +125027,8 @@ static void identPut(char *z, int *pIdx, char *zSignedIdent){ ** from sqliteMalloc() and must be freed by the calling function. */ static char *createTableStmt(sqlite3 *db, Table *p){ - int i, k, n; + int i, k, len; + i64 n; char *zStmt; char *zSep, *zSep2, *zEnd; Column *pCol; @@ -124253,8 +125052,9 @@ static char *createTableStmt(sqlite3 *db, Table *p){ sqlite3OomFault(db); return 0; } - sqlite3_snprintf(n, zStmt, "CREATE TABLE "); - k = sqlite3Strlen30(zStmt); + assert( n>14 && n<=0x7fffffff ); + memcpy(zStmt, "CREATE TABLE ", 13); + k = 13; identPut(zStmt, &k, p->zName); zStmt[k++] = '('; for(pCol=p->aCol, i=0; inCol; i++, pCol++){ @@ -124266,13 +125066,15 @@ static char *createTableStmt(sqlite3 *db, Table *p){ /* SQLITE_AFF_REAL */ " REAL", /* SQLITE_AFF_FLEXNUM */ " NUM", }; - int len; const char *zType; - sqlite3_snprintf(n-k, &zStmt[k], zSep); - k += sqlite3Strlen30(&zStmt[k]); + len = sqlite3Strlen30(zSep); + assert( k+lenzCnName); + assert( kaffinity-SQLITE_AFF_BLOB >= 0 ); assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) ); testcase( pCol->affinity==SQLITE_AFF_BLOB ); @@ -124287,11 +125089,14 @@ static char *createTableStmt(sqlite3 *db, Table *p){ assert( pCol->affinity==SQLITE_AFF_BLOB || pCol->affinity==SQLITE_AFF_FLEXNUM || pCol->affinity==sqlite3AffinityType(zType, 0) ); + assert( k+lennColumn>=N ) return SQLITE_OK; + db = pParse->db; + assert( N>0 ); + assert( N <= SQLITE_MAX_COLUMN*2 /* tag-20250221-1 */ ); + testcase( N==2*pParse->db->aLimit[SQLITE_LIMIT_COLUMN] ); assert( pIdx->isResized==0 ); - nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*N; + nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*(u64)N; zExtra = sqlite3DbMallocZero(db, nByte); if( zExtra==0 ) return SQLITE_NOMEM_BKPT; memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn); @@ -124318,7 +125128,7 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){ zExtra += sizeof(i16)*N; memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn); pIdx->aSortOrder = (u8*)zExtra; - pIdx->nColumn = N; + pIdx->nColumn = (u16)N; /* See tag-20250221-1 above for proof of safety */ pIdx->isResized = 1; return SQLITE_OK; } @@ -124484,9 +125294,9 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ ** into BTREE_BLOBKEY. */ assert( !pParse->bReturning ); - if( pParse->u1.addrCrTab ){ + if( pParse->u1.cr.addrCrTab ){ assert( v ); - sqlite3VdbeChangeP3(v, pParse->u1.addrCrTab, BTREE_BLOBKEY); + sqlite3VdbeChangeP3(v, pParse->u1.cr.addrCrTab, BTREE_BLOBKEY); } /* Locate the PRIMARY KEY index. Or, if this table was originally @@ -124572,14 +125382,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ pIdx->nColumn = pIdx->nKeyCol; continue; } - if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return; + if( resizeIndexObject(pParse, pIdx, pIdx->nKeyCol+n) ) return; for(i=0, j=pIdx->nKeyCol; inKeyCol, pPk, i) ){ testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); pIdx->aiColumn[j] = pPk->aiColumn[i]; pIdx->azColl[j] = pPk->azColl[i]; if( pPk->aSortOrder[i] ){ - /* See ticket https://www.sqlite.org/src/info/bba7b69f9849b5bf */ + /* See ticket https://sqlite.org/src/info/bba7b69f9849b5bf */ pIdx->bAscKeyBug = 1; } j++; @@ -124596,7 +125406,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ if( !hasColumn(pPk->aiColumn, nPk, i) && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++; } - if( resizeIndexObject(db, pPk, nPk+nExtra) ) return; + if( resizeIndexObject(pParse, pPk, nPk+nExtra) ) return; for(i=0, j=nPk; inCol; i++){ if( !hasColumn(pPk->aiColumn, j, i) && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 @@ -124926,7 +125736,7 @@ SQLITE_PRIVATE void sqlite3EndTable( /* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT ** statement to populate the new table. The root-page number for the - ** new table is in register pParse->regRoot. + ** new table is in register pParse->u1.cr.regRoot. ** ** Once the SELECT has been coded by sqlite3Select(), it is in a ** suitable state to query for the column names and types to be used @@ -124957,7 +125767,8 @@ SQLITE_PRIVATE void sqlite3EndTable( regRec = ++pParse->nMem; regRowid = ++pParse->nMem; sqlite3MayAbort(pParse); - sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->regRoot, iDb); + assert( pParse->isCreate ); + sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->u1.cr.regRoot, iDb); sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG); addrTop = sqlite3VdbeCurrentAddr(v) + 1; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); @@ -125002,6 +125813,7 @@ SQLITE_PRIVATE void sqlite3EndTable( ** schema table. We just need to update that slot with all ** the information we've collected. */ + assert( pParse->isCreate ); sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q" @@ -125010,9 +125822,9 @@ SQLITE_PRIVATE void sqlite3EndTable( zType, p->zName, p->zName, - pParse->regRoot, + pParse->u1.cr.regRoot, zStmt, - pParse->regRowid + pParse->u1.cr.regRowid ); sqlite3DbFree(db, zStmt); sqlite3ChangeCookie(pParse, iDb); @@ -125752,7 +126564,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( }else{ nCol = pFromCol->nExpr; } - nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1; + nByte = SZ_FKEY(nCol) + pTo->n + 1; if( pToCol ){ for(i=0; inExpr; i++){ nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1; @@ -125954,7 +126766,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ ** not work for UNIQUE constraint indexes on WITHOUT ROWID tables ** with DESC primary keys, since those indexes have there keys in ** a different order from the main table. - ** See ticket: https://www.sqlite.org/src/info/bba7b69f9849b5bf + ** See ticket: https://sqlite.org/src/info/bba7b69f9849b5bf */ sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); } @@ -125978,13 +126790,14 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ */ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( sqlite3 *db, /* Database connection */ - i16 nCol, /* Total number of columns in the index */ + int nCol, /* Total number of columns in the index */ int nExtra, /* Number of bytes of extra space to alloc */ char **ppExtra /* Pointer to the "extra" space */ ){ Index *p; /* Allocated index object */ - int nByte; /* Bytes of space for Index object + arrays */ + i64 nByte; /* Bytes of space for Index object + arrays */ + assert( nCol <= 2*db->aLimit[SQLITE_LIMIT_COLUMN] ); nByte = ROUND8(sizeof(Index)) + /* Index structure */ ROUND8(sizeof(char*)*nCol) + /* Index.azColl */ ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */ @@ -125997,8 +126810,9 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1); p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol; p->aSortOrder = (u8*)pExtra; - p->nColumn = nCol; - p->nKeyCol = nCol - 1; + assert( nCol>0 ); + p->nColumn = (u16)nCol; + p->nKeyCol = (u16)(nCol - 1); *ppExtra = ((char*)p) + nByte; } return p; @@ -126336,6 +127150,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex( assert( j<=0x7fff ); if( j<0 ){ j = pTab->iPKey; + pIndex->bIdxRowid = 1; }else{ if( pTab->aCol[j].notNull==0 ){ pIndex->uniqNotNull = 0; @@ -126809,12 +127624,11 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token * sqlite3 *db = pParse->db; int i; if( pList==0 ){ - pList = sqlite3DbMallocZero(db, sizeof(IdList) ); + pList = sqlite3DbMallocZero(db, SZ_IDLIST(1)); if( pList==0 ) return 0; }else{ IdList *pNew; - pNew = sqlite3DbRealloc(db, pList, - sizeof(IdList) + pList->nId*sizeof(pList->a)); + pNew = sqlite3DbRealloc(db, pList, SZ_IDLIST(pList->nId+1)); if( pNew==0 ){ sqlite3IdListDelete(db, pList); return 0; @@ -126913,8 +127727,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( return 0; } if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST; - pNew = sqlite3DbRealloc(db, pSrc, - sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) ); + pNew = sqlite3DbRealloc(db, pSrc, SZ_SRCLIST(nAlloc)); if( pNew==0 ){ assert( db->mallocFailed ); return 0; @@ -126989,7 +127802,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( assert( pParse->db!=0 ); db = pParse->db; if( pList==0 ){ - pList = sqlite3DbMallocRawNN(pParse->db, sizeof(SrcList) ); + pList = sqlite3DbMallocRawNN(pParse->db, SZ_SRCLIST(1)); if( pList==0 ) return 0; pList->nAlloc = 1; pList->nSrc = 1; @@ -127875,10 +128688,9 @@ SQLITE_PRIVATE With *sqlite3WithAdd( } if( pWith ){ - sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte); - pNew = sqlite3DbRealloc(db, pWith, nByte); + pNew = sqlite3DbRealloc(db, pWith, SZ_WITH(pWith->nCte+1)); }else{ - pNew = sqlite3DbMallocZero(db, sizeof(*pWith)); + pNew = sqlite3DbMallocZero(db, SZ_WITH(1)); } assert( (pNew!=0 && zName!=0) || db->mallocFailed ); @@ -129852,11 +130664,6 @@ static void substrFunc( i64 p1, p2; assert( argc==3 || argc==2 ); - if( sqlite3_value_type(argv[1])==SQLITE_NULL - || (argc==3 && sqlite3_value_type(argv[2])==SQLITE_NULL) - ){ - return; - } p0type = sqlite3_value_type(argv[0]); p1 = sqlite3_value_int64(argv[1]); if( p0type==SQLITE_BLOB ){ @@ -129874,19 +130681,23 @@ static void substrFunc( } } } -#ifdef SQLITE_SUBSTR_COMPATIBILITY - /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as - ** as substr(X,1,N) - it returns the first N characters of X. This - ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8] - ** from 2009-02-02 for compatibility of applications that exploited the - ** old buggy behavior. */ - if( p1==0 ) p1 = 1; /* */ -#endif if( argc==3 ){ p2 = sqlite3_value_int64(argv[2]); + if( p2==0 && sqlite3_value_type(argv[2])==SQLITE_NULL ) return; }else{ p2 = sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH]; } + if( p1==0 ){ +#ifdef SQLITE_SUBSTR_COMPATIBILITY + /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as + ** as substr(X,1,N) - it returns the first N characters of X. This + ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8] + ** from 2009-02-02 for compatibility of applications that exploited the + ** old buggy behavior. */ + p1 = 1; /* */ +#endif + if( sqlite3_value_type(argv[1])==SQLITE_NULL ) return; + } if( p1<0 ){ p1 += len; if( p1<0 ){ @@ -130587,7 +131398,7 @@ static const char hexdigits[] = { ** Append to pStr text that is the SQL literal representation of the ** value contained in pValue. */ -SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ +SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){ /* As currently implemented, the string must be initially empty. ** we might relax this requirement in the future, but that will ** require enhancements to the implementation. */ @@ -130635,7 +131446,7 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ } case SQLITE_TEXT: { const unsigned char *zArg = sqlite3_value_text(pValue); - sqlite3_str_appendf(pStr, "%Q", zArg); + sqlite3_str_appendf(pStr, bEscape ? "%#Q" : "%Q", zArg); break; } default: { @@ -130646,6 +131457,105 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ } } +/* +** Return true if z[] begins with N hexadecimal digits, and write +** a decoding of those digits into *pVal. Or return false if any +** one of the first N characters in z[] is not a hexadecimal digit. +*/ +static int isNHex(const char *z, int N, u32 *pVal){ + int i; + int v = 0; + for(i=0; i0 ){ + memmove(&zOut[j], &zIn[i], n); + j += n; + i += n; + } + if( zIn[i+1]=='\\' ){ + i += 2; + zOut[j++] = '\\'; + }else if( sqlite3Isxdigit(zIn[i+1]) ){ + if( !isNHex(&zIn[i+1], 4, &v) ) goto unistr_error; + i += 5; + j += sqlite3AppendOneUtf8Character(&zOut[j], v); + }else if( zIn[i+1]=='+' ){ + if( !isNHex(&zIn[i+2], 6, &v) ) goto unistr_error; + i += 8; + j += sqlite3AppendOneUtf8Character(&zOut[j], v); + }else if( zIn[i+1]=='u' ){ + if( !isNHex(&zIn[i+2], 4, &v) ) goto unistr_error; + i += 6; + j += sqlite3AppendOneUtf8Character(&zOut[j], v); + }else if( zIn[i+1]=='U' ){ + if( !isNHex(&zIn[i+2], 8, &v) ) goto unistr_error; + i += 10; + j += sqlite3AppendOneUtf8Character(&zOut[j], v); + }else{ + goto unistr_error; + } + } + zOut[j] = 0; + sqlite3_result_text64(context, zOut, j, sqlite3_free, SQLITE_UTF8); + return; + +unistr_error: + sqlite3_free(zOut); + sqlite3_result_error(context, "invalid Unicode escape", -1); + return; +} + + /* ** Implementation of the QUOTE() function. ** @@ -130655,6 +131565,10 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ ** as needed. BLOBs are encoded as hexadecimal literals. Strings with ** embedded NUL characters cannot be represented as string literals in SQL ** and hence the returned string literal is truncated prior to the first NUL. +** +** If sqlite3_user_data() is non-zero, then the UNISTR_QUOTE() function is +** implemented instead. The difference is that UNISTR_QUOTE() uses the +** UNISTR() function to escape control characters. */ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3_str str; @@ -130662,7 +131576,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ assert( argc==1 ); UNUSED_PARAMETER(argc); sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); - sqlite3QuoteValue(&str,argv[0]); + sqlite3QuoteValue(&str,argv[0],SQLITE_PTR_TO_INT(sqlite3_user_data(context))); sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar, SQLITE_DYNAMIC); if( str.accError!=SQLITE_OK ){ @@ -130917,7 +131831,7 @@ static void replaceFunc( assert( zRep==sqlite3_value_text(argv[2]) ); nOut = nStr + 1; assert( nOutselFlags); } pSelect = sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0); - pLeft->selFlags &= ~SF_MultiValue; + pLeft->selFlags &= ~(u32)SF_MultiValue; if( pSelect ){ pSelect->op = TK_ALL; pSelect->pPrior = pLeft; @@ -134902,28 +135818,22 @@ SQLITE_PRIVATE void sqlite3Insert( aTabColMap = sqlite3DbMallocZero(db, pTab->nCol*sizeof(int)); if( aTabColMap==0 ) goto insert_cleanup; for(i=0; inId; i++){ - const char *zCName = pColumn->a[i].zName; - u8 hName = sqlite3StrIHash(zCName); - for(j=0; jnCol; j++){ - if( pTab->aCol[j].hName!=hName ) continue; - if( sqlite3StrICmp(zCName, pTab->aCol[j].zCnName)==0 ){ - if( aTabColMap[j]==0 ) aTabColMap[j] = i+1; - if( i!=j ) bIdListInOrder = 0; - if( j==pTab->iPKey ){ - ipkColumn = i; assert( !withoutRowid ); - } + j = sqlite3ColumnIndex(pTab, pColumn->a[i].zName); + if( j>=0 ){ + if( aTabColMap[j]==0 ) aTabColMap[j] = i+1; + if( i!=j ) bIdListInOrder = 0; + if( j==pTab->iPKey ){ + ipkColumn = i; assert( !withoutRowid ); + } #ifndef SQLITE_OMIT_GENERATED_COLUMNS - if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ - sqlite3ErrorMsg(pParse, - "cannot INSERT into generated column \"%s\"", - pTab->aCol[j].zCnName); - goto insert_cleanup; - } -#endif - break; + if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ + sqlite3ErrorMsg(pParse, + "cannot INSERT into generated column \"%s\"", + pTab->aCol[j].zCnName); + goto insert_cleanup; } - } - if( j>=pTab->nCol ){ +#endif + }else{ if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){ ipkColumn = i; bIdListInOrder = 0; @@ -135221,7 +136131,7 @@ SQLITE_PRIVATE void sqlite3Insert( continue; }else if( pColumn==0 ){ /* Hidden columns that are not explicitly named in the INSERT - ** get there default value */ + ** get their default value */ sqlite3ExprCodeFactorable(pParse, sqlite3ColumnExpr(pTab, &pTab->aCol[i]), iRegStore); @@ -135946,7 +136856,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( ** could happen in any order, but they are grouped up front for ** convenience. ** - ** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43 + ** 2018-08-14: Ticket https://sqlite.org/src/info/908f001483982c43 ** The order of constraints used to have OE_Update as (2) and OE_Abort ** and so forth as (1). But apparently PostgreSQL checks the OE_Update ** constraint before any others, so it had to be moved. @@ -137756,6 +138666,8 @@ struct sqlite3_api_routines { /* Version 3.44.0 and later */ void *(*get_clientdata)(sqlite3*,const char*); int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); + /* Version 3.50.0 and later */ + int (*setlk_timeout)(sqlite3*,int,int); }; /* @@ -138089,6 +139001,8 @@ typedef int (*sqlite3_loadext_entry)( /* Version 3.44.0 and later */ #define sqlite3_get_clientdata sqlite3_api->get_clientdata #define sqlite3_set_clientdata sqlite3_api->set_clientdata +/* Version 3.50.0 and later */ +#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -138610,7 +139524,9 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_stmt_explain, /* Version 3.44.0 and later */ sqlite3_get_clientdata, - sqlite3_set_clientdata + sqlite3_set_clientdata, + /* Version 3.50.0 and later */ + sqlite3_setlk_timeout }; /* True if x is the directory separator character @@ -139132,48 +140048,48 @@ static const char *const pragCName[] = { /* 13 */ "pk", /* 14 */ "hidden", /* table_info reuses 8 */ - /* 15 */ "schema", /* Used by: table_list */ - /* 16 */ "name", + /* 15 */ "name", /* Used by: function_list */ + /* 16 */ "builtin", /* 17 */ "type", - /* 18 */ "ncol", - /* 19 */ "wr", - /* 20 */ "strict", - /* 21 */ "seqno", /* Used by: index_xinfo */ - /* 22 */ "cid", - /* 23 */ "name", - /* 24 */ "desc", - /* 25 */ "coll", - /* 26 */ "key", - /* 27 */ "name", /* Used by: function_list */ - /* 28 */ "builtin", - /* 29 */ "type", - /* 30 */ "enc", - /* 31 */ "narg", - /* 32 */ "flags", - /* 33 */ "tbl", /* Used by: stats */ - /* 34 */ "idx", - /* 35 */ "wdth", - /* 36 */ "hght", - /* 37 */ "flgs", - /* 38 */ "seq", /* Used by: index_list */ - /* 39 */ "name", - /* 40 */ "unique", - /* 41 */ "origin", - /* 42 */ "partial", + /* 18 */ "enc", + /* 19 */ "narg", + /* 20 */ "flags", + /* 21 */ "schema", /* Used by: table_list */ + /* 22 */ "name", + /* 23 */ "type", + /* 24 */ "ncol", + /* 25 */ "wr", + /* 26 */ "strict", + /* 27 */ "seqno", /* Used by: index_xinfo */ + /* 28 */ "cid", + /* 29 */ "name", + /* 30 */ "desc", + /* 31 */ "coll", + /* 32 */ "key", + /* 33 */ "seq", /* Used by: index_list */ + /* 34 */ "name", + /* 35 */ "unique", + /* 36 */ "origin", + /* 37 */ "partial", + /* 38 */ "tbl", /* Used by: stats */ + /* 39 */ "idx", + /* 40 */ "wdth", + /* 41 */ "hght", + /* 42 */ "flgs", /* 43 */ "table", /* Used by: foreign_key_check */ /* 44 */ "rowid", /* 45 */ "parent", /* 46 */ "fkid", - /* index_info reuses 21 */ - /* 47 */ "seq", /* Used by: database_list */ - /* 48 */ "name", - /* 49 */ "file", - /* 50 */ "busy", /* Used by: wal_checkpoint */ - /* 51 */ "log", - /* 52 */ "checkpointed", - /* collation_list reuses 38 */ + /* 47 */ "busy", /* Used by: wal_checkpoint */ + /* 48 */ "log", + /* 49 */ "checkpointed", + /* 50 */ "seq", /* Used by: database_list */ + /* 51 */ "name", + /* 52 */ "file", + /* index_info reuses 27 */ /* 53 */ "database", /* Used by: lock_status */ /* 54 */ "status", + /* collation_list reuses 33 */ /* 55 */ "cache_size", /* Used by: default_cache_size */ /* module_list pragma_list reuses 9 */ /* 56 */ "timeout", /* Used by: busy_timeout */ @@ -139266,7 +140182,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "collation_list", /* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 38, 2, + /* ColNames: */ 33, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) @@ -139301,7 +140217,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 47, 3, + /* ColNames: */ 50, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) @@ -139381,7 +140297,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "function_list", /* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 27, 6, + /* ColNames: */ 15, 6, /* iArg: */ 0 }, #endif #endif @@ -139410,17 +140326,17 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "index_info", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 21, 3, + /* ColNames: */ 27, 3, /* iArg: */ 0 }, {/* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 38, 5, + /* ColNames: */ 33, 5, /* iArg: */ 0 }, {/* zName: */ "index_xinfo", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 21, 6, + /* ColNames: */ 27, 6, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) @@ -139599,7 +140515,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, - /* ColNames: */ 33, 5, + /* ColNames: */ 38, 5, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -139618,7 +140534,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "table_list", /* ePragTyp: */ PragTyp_TABLE_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1, - /* ColNames: */ 15, 6, + /* ColNames: */ 21, 6, /* iArg: */ 0 }, {/* zName: */ "table_xinfo", /* ePragTyp: */ PragTyp_TABLE_INFO, @@ -139695,7 +140611,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, - /* ColNames: */ 50, 3, + /* ColNames: */ 47, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -139717,7 +140633,7 @@ static const PragmaName aPragmaName[] = { ** the following macro or to the actual analysis_limit if it is non-zero, ** in order to prevent PRAGMA optimize from running for too long. ** -** The value of 2000 is chosen emperically so that the worst-case run-time +** The value of 2000 is chosen empirically so that the worst-case run-time ** for PRAGMA optimize does not exceed 100 milliseconds against a variety ** of test databases on a RaspberryPI-4 compiled using -Os and without ** -DSQLITE_DEBUG. Of course, your mileage may vary. For the purpose of @@ -140834,7 +141750,10 @@ SQLITE_PRIVATE void sqlite3Pragma( } }else{ db->flags &= ~mask; - if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; + if( mask==SQLITE_DeferFKs ){ + db->nDeferredImmCons = 0; + db->nDeferredCons = 0; + } if( (mask & SQLITE_WriteSchema)!=0 && sqlite3_stricmp(zRight, "reset")==0 ){ @@ -144003,7 +144922,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = 0; - if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc)); + if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1); pNew->pSrc = pSrc; pNew->pWhere = pWhere; pNew->pGroupBy = pGroupBy; @@ -144168,10 +145087,33 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p */ SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol){ int i; - u8 h = sqlite3StrIHash(zCol); - Column *pCol; - for(pCol=pTab->aCol, i=0; inCol; pCol++, i++){ - if( pCol->hName==h && sqlite3StrICmp(pCol->zCnName, zCol)==0 ) return i; + u8 h; + const Column *aCol; + int nCol; + + h = sqlite3StrIHash(zCol); + aCol = pTab->aCol; + nCol = pTab->nCol; + + /* See if the aHx gives us a lucky match */ + i = pTab->aHx[h % sizeof(pTab->aHx)]; + assert( i=nCol ) break; } return -1; } @@ -145363,8 +146305,8 @@ static void selectInnerLoop( ** X extra columns. */ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ - int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*); - KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra); + int nExtra = (N+X)*(sizeof(CollSeq*)+1); + KeyInfo *p = sqlite3DbMallocRawNN(db, SZ_KEYINFO(0) + nExtra); if( p ){ p->aSortFlags = (u8*)&p->aColl[N+X]; p->nKeyField = (u16)N; @@ -145372,7 +146314,7 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ p->enc = ENC(db); p->db = db; p->nRef = 1; - memset(&p[1], 0, nExtra); + memset(p->aColl, 0, nExtra); }else{ return (KeyInfo*)sqlite3OomFault(db); } @@ -147073,6 +148015,7 @@ static int multiSelect( multi_select_end: pDest->iSdst = dest.iSdst; pDest->nSdst = dest.nSdst; + pDest->iSDParm2 = dest.iSDParm2; if( pDelete ){ sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete); } @@ -148683,7 +149626,8 @@ static void constInsert( return; /* Already present. Return without doing anything. */ } } - if( sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){ + assert( SQLITE_AFF_NONEbHasAffBlob = 1; } @@ -148758,7 +149702,8 @@ static int propagateConstantExprRewriteOne( if( pColumn==pExpr ) continue; if( pColumn->iTable!=pExpr->iTable ) continue; if( pColumn->iColumn!=pExpr->iColumn ) continue; - if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){ + assert( SQLITE_AFF_NONEpWinDefn = 0; #endif - p->selFlags &= ~SF_Compound; + p->selFlags &= ~(u32)SF_Compound; assert( (p->selFlags & SF_Converted)==0 ); p->selFlags |= SF_Converted; assert( pNew->pPrior!=0 ); @@ -149888,7 +150833,7 @@ static int selectExpander(Walker *pWalker, Select *p){ pEList = p->pEList; if( pParse->pWith && (p->selFlags & SF_View) ){ if( p->pWith==0 ){ - p->pWith = (With*)sqlite3DbMallocZero(db, sizeof(With)); + p->pWith = (With*)sqlite3DbMallocZero(db, SZ_WITH(1) ); if( p->pWith==0 ){ return WRC_Abort; } @@ -151027,6 +151972,7 @@ static void agginfoFree(sqlite3 *db, void *pArg){ ** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries ** * The outer query is a simple count(*) with no WHERE clause or other ** extraneous syntax. +** * None of the subqueries are DISTINCT (forumpost/a860f5fb2e 2025-03-10) ** ** Return TRUE if the optimization is undertaken. */ @@ -151059,7 +152005,11 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ if( pSub->pWhere ) return 0; /* No WHERE clause */ if( pSub->pLimit ) return 0; /* No LIMIT clause */ - if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ + if( pSub->selFlags & (SF_Aggregate|SF_Distinct) ){ + testcase( pSub->selFlags & SF_Aggregate ); + testcase( pSub->selFlags & SF_Distinct ); + return 0; /* Not an aggregate nor DISTINCT */ + } assert( pSub->pHaving==0 ); /* Due to the previous */ pSub = pSub->pPrior; /* Repeat over compound */ }while( pSub ); @@ -151071,14 +152021,14 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ pExpr = 0; pSub = sqlite3SubqueryDetach(db, pFrom); sqlite3SrcListDelete(db, p->pSrc); - p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc)); + p->pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1); while( pSub ){ Expr *pTerm; pPrior = pSub->pPrior; pSub->pPrior = 0; pSub->pNext = 0; pSub->selFlags |= SF_Aggregate; - pSub->selFlags &= ~SF_Compound; + pSub->selFlags &= ~(u32)SF_Compound; pSub->nSelectRow = 0; sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList); pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount; @@ -151093,7 +152043,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ pSub = pPrior; } p->pEList->a[0].pExpr = pExpr; - p->selFlags &= ~SF_Aggregate; + p->selFlags &= ~(u32)SF_Aggregate; #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x200 ){ @@ -151300,7 +152250,7 @@ SQLITE_PRIVATE int sqlite3Select( testcase( pParse->earlyCleanup ); p->pOrderBy = 0; } - p->selFlags &= ~SF_Distinct; + p->selFlags &= ~(u32)SF_Distinct; p->selFlags |= SF_NoopOrderBy; } sqlite3SelectPrep(pParse, p, 0); @@ -151339,7 +152289,7 @@ SQLITE_PRIVATE int sqlite3Select( ** and leaving this flag set can cause errors if a compound sub-query ** in p->pSrc is flattened into this query and this function called ** again as part of compound SELECT processing. */ - p->selFlags &= ~SF_UFSrcCheck; + p->selFlags &= ~(u32)SF_UFSrcCheck; } if( pDest->eDest==SRT_Output ){ @@ -151828,7 +152778,7 @@ SQLITE_PRIVATE int sqlite3Select( && p->pWin==0 #endif ){ - p->selFlags &= ~SF_Distinct; + p->selFlags &= ~(u32)SF_Distinct; pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0); if( pGroupBy ){ for(i=0; inExpr; i++){ @@ -151937,6 +152887,12 @@ SQLITE_PRIVATE int sqlite3Select( if( pWInfo==0 ) goto select_end; if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); + if( pDest->eDest<=SRT_DistQueue && pDest->eDest>=SRT_DistFifo ){ + /* TUNING: For a UNION CTE, because UNION is implies DISTINCT, + ** reduce the estimated output row count by 8 (LogEst 30). + ** Search for tag-20250414a to see other cases */ + p->nSelectRow -= 30; + } } if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); @@ -152310,6 +153266,10 @@ SQLITE_PRIVATE int sqlite3Select( if( iOrderByCol ){ Expr *pX = p->pEList->a[iOrderByCol-1].pExpr; Expr *pBase = sqlite3ExprSkipCollateAndLikely(pX); + while( ALWAYS(pBase!=0) && pBase->op==TK_IF_NULL_ROW ){ + pX = pBase->pLeft; + pBase = sqlite3ExprSkipCollateAndLikely(pX); + } if( ALWAYS(pBase!=0) && pBase->op!=TK_AGG_COLUMN && pBase->op!=TK_REGISTER @@ -152893,7 +153853,8 @@ SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ assert( pParse->db->pVtabCtx==0 ); #endif assert( pParse->bReturning ); - assert( &(pParse->u1.pReturning->retTrig) == pTrig ); + assert( !pParse->isCreate ); + assert( &(pParse->u1.d.pReturning->retTrig) == pTrig ); pTrig->table = pTab->zName; pTrig->pTabSchema = pTab->pSchema; pTrig->pNext = pList; @@ -153861,7 +154822,8 @@ static void codeReturningTrigger( ExprList *pNew; Returning *pReturning; Select sSelect; - SrcList sFrom; + SrcList *pFrom; + u8 fromSpace[SZ_SRCLIST_1]; assert( v!=0 ); if( !pParse->bReturning ){ @@ -153870,19 +154832,21 @@ static void codeReturningTrigger( return; } assert( db->pParse==pParse ); - pReturning = pParse->u1.pReturning; + assert( !pParse->isCreate ); + pReturning = pParse->u1.d.pReturning; if( pTrigger != &(pReturning->retTrig) ){ /* This RETURNING trigger is for a different statement */ return; } memset(&sSelect, 0, sizeof(sSelect)); - memset(&sFrom, 0, sizeof(sFrom)); + pFrom = (SrcList*)fromSpace; + memset(pFrom, 0, SZ_SRCLIST_1); sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0); - sSelect.pSrc = &sFrom; - sFrom.nSrc = 1; - sFrom.a[0].pSTab = pTab; - sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */ - sFrom.a[0].iCursor = -1; + sSelect.pSrc = pFrom; + pFrom->nSrc = 1; + pFrom->a[0].pSTab = pTab; + pFrom->a[0].zName = pTab->zName; /* tag-20240424-1 */ + pFrom->a[0].iCursor = -1; sqlite3SelectPrep(pParse, &sSelect, 0); if( pParse->nErr==0 ){ assert( db->mallocFailed==0 ); @@ -154100,6 +155064,8 @@ static TriggerPrg *codeRowTrigger( sSubParse.eTriggerOp = pTrigger->op; sSubParse.nQueryLoop = pParse->nQueryLoop; sSubParse.prepFlags = pParse->prepFlags; + sSubParse.oldmask = 0; + sSubParse.newmask = 0; v = sqlite3GetVdbe(&sSubParse); if( v ){ @@ -154854,38 +155820,32 @@ SQLITE_PRIVATE void sqlite3Update( */ chngRowid = chngPk = 0; for(i=0; inExpr; i++){ - u8 hCol = sqlite3StrIHash(pChanges->a[i].zEName); /* If this is an UPDATE with a FROM clause, do not resolve expressions ** here. The call to sqlite3Select() below will do that. */ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){ goto update_cleanup; } - for(j=0; jnCol; j++){ - if( pTab->aCol[j].hName==hCol - && sqlite3StrICmp(pTab->aCol[j].zCnName, pChanges->a[i].zEName)==0 - ){ - if( j==pTab->iPKey ){ - chngRowid = 1; - pRowidExpr = pChanges->a[i].pExpr; - iRowidExpr = i; - }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ - chngPk = 1; - } + j = sqlite3ColumnIndex(pTab, pChanges->a[i].zEName); + if( j>=0 ){ + if( j==pTab->iPKey ){ + chngRowid = 1; + pRowidExpr = pChanges->a[i].pExpr; + iRowidExpr = i; + }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ + chngPk = 1; + } #ifndef SQLITE_OMIT_GENERATED_COLUMNS - else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){ - testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ); - testcase( pTab->aCol[j].colFlags & COLFLAG_STORED ); - sqlite3ErrorMsg(pParse, - "cannot UPDATE generated column \"%s\"", - pTab->aCol[j].zCnName); - goto update_cleanup; - } -#endif - aXRef[j] = i; - break; + else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){ + testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ); + testcase( pTab->aCol[j].colFlags & COLFLAG_STORED ); + sqlite3ErrorMsg(pParse, + "cannot UPDATE generated column \"%s\"", + pTab->aCol[j].zCnName); + goto update_cleanup; } - } - if( j>=pTab->nCol ){ +#endif + aXRef[j] = i; + }else{ if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zEName) ){ j = -1; chngRowid = 1; @@ -156208,7 +157168,7 @@ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){ #else /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments ** to VACUUM are silently ignored. This is a back-out of a bug fix that - ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270). + ** occurred on 2016-08-19 (https://sqlite.org/src/info/083f9e6270). ** The buggy behavior is required for binary compatibility with some ** legacy applications. */ iDb = sqlite3FindDb(pParse->db, pNm); @@ -156287,7 +157247,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; saved_mTrace = db->mTrace; - db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; + db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_Comments; db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum; db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_Defensive | SQLITE_CountRows); @@ -156992,11 +157952,12 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ ** schema table. We just need to update that slot with all ** the information we've collected. ** - ** The VM register number pParse->regRowid holds the rowid of an + ** The VM register number pParse->u1.cr.regRowid holds the rowid of an ** entry in the sqlite_schema table that was created for this vtab ** by sqlite3StartTable(). */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( pParse->isCreate ); sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " @@ -157005,7 +157966,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ pTab->zName, pTab->zName, zStmt, - pParse->regRowid + pParse->u1.cr.regRowid ); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); @@ -158415,9 +159376,14 @@ struct WhereInfo { Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ WhereClause sWC; /* Decomposition of the WHERE clause */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ - WhereLevel a[1]; /* Information about each nest loop in WHERE */ + WhereLevel a[FLEXARRAY]; /* Information about each nest loop in WHERE */ }; +/* +** The size (in bytes) of a WhereInfo object that holds N WhereLevels. +*/ +#define SZ_WHEREINFO(N) ROUND8(offsetof(WhereInfo,a)+(N)*sizeof(WhereLevel)) + /* ** Private interfaces - callable only by other where.c routines. ** @@ -159097,7 +160063,7 @@ static void adjustOrderByCol(ExprList *pOrderBy, ExprList *pEList){ /* ** pX is an expression of the form: (vector) IN (SELECT ...) ** In other words, it is a vector IN operator with a SELECT clause on the -** LHS. But not all terms in the vector are indexable and the terms might +** RHS. But not all terms in the vector are indexable and the terms might ** not be in the correct order for indexing. ** ** This routine makes a copy of the input pX expression and then adjusts @@ -160163,6 +161129,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); + /* The instruction immediately prior to OP_VFilter must be an OP_Integer + ** that sets the "argc" value for xVFilter. This is necessary for + ** resolveP2() to work correctly. See tag-20250207a. */ sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pLoop->u.vtab.idxStr, pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC); @@ -160865,8 +161834,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int nNotReady; /* The number of notReady tables */ SrcItem *origSrc; /* Original list of tables */ nNotReady = pWInfo->nLevel - iLevel - 1; - pOrTab = sqlite3DbMallocRawNN(db, - sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0])); + pOrTab = sqlite3DbMallocRawNN(db, SZ_SRCLIST(nNotReady+1)); if( pOrTab==0 ) return notReady; pOrTab->nAlloc = (u8)(nNotReady + 1); pOrTab->nSrc = pOrTab->nAlloc; @@ -160917,7 +161885,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** ** This optimization also only applies if the (x1 OR x2 OR ...) term ** is not contained in the ON clause of a LEFT JOIN. - ** See ticket http://www.sqlite.org/src/info/f2369304e4 + ** See ticket http://sqlite.org/src/info/f2369304e4 ** ** 2022-02-04: Do not push down slices of a row-value comparison. ** In other words, "w" or "y" may not be a slice of a vector. Otherwise, @@ -161409,7 +162377,8 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( WhereInfo *pSubWInfo; WhereLoop *pLoop = pLevel->pWLoop; SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; - SrcList sFrom; + SrcList *pFrom; + u8 fromSpace[SZ_SRCLIST_1]; Bitmask mAll = 0; int k; @@ -161453,13 +162422,14 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( sqlite3ExprDup(pParse->db, pTerm->pExpr, 0)); } } - sFrom.nSrc = 1; - sFrom.nAlloc = 1; - memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem)); - sFrom.a[0].fg.jointype = 0; + pFrom = (SrcList*)fromSpace; + pFrom->nSrc = 1; + pFrom->nAlloc = 1; + memcpy(&pFrom->a[0], pTabItem, sizeof(SrcItem)); + pFrom->a[0].fg.jointype = 0; assert( pParse->withinRJSubrtn < 100 ); pParse->withinRJSubrtn++; - pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0, + pSubWInfo = sqlite3WhereBegin(pParse, pFrom, pSubWhere, 0, 0, 0, WHERE_RIGHT_JOIN, 0); if( pSubWInfo ){ int iCur = pLevel->iTabCur; @@ -163447,11 +164417,16 @@ struct HiddenIndexInfo { int eDistinct; /* Value to return from sqlite3_vtab_distinct() */ u32 mIn; /* Mask of terms that are IN (...) */ u32 mHandleIn; /* Terms that vtab will handle as IN (...) */ - sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST - ** because extra space is allocated to hold up - ** to nTerm such values */ + sqlite3_value *aRhs[FLEXARRAY]; /* RHS values for constraints. MUST BE LAST + ** Extra space is allocated to hold up + ** to nTerm such values */ }; +/* Size (in bytes) of a HiddenIndeInfo object sufficient to hold as +** many as N constraints */ +#define SZ_HIDDENINDEXINFO(N) \ + (offsetof(HiddenIndexInfo,aRhs) + (N)*sizeof(sqlite3_value*)) + /* Forward declaration of methods */ static int whereLoopResize(sqlite3*, WhereLoop*, int); @@ -164516,6 +165491,8 @@ static SQLITE_NOINLINE void constructAutomaticIndex( } /* Construct the Index object to describe this index */ + assert( nKeyCol <= pTable->nCol + MAX(0, pTable->nCol - BMS + 1) ); + /* ^-- This guarantees that the number of index columns will fit in the u16 */ pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+HasRowid(pTable), 0, &zNotUsed); if( pIdx==0 ) goto end_auto_index_create; @@ -164927,8 +165904,8 @@ static sqlite3_index_info *allocateIndexInfo( */ pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo) + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm - + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) - + sizeof(sqlite3_value*)*nTerm ); + + sizeof(*pIdxOrderBy)*nOrderBy + + SZ_HIDDENINDEXINFO(nTerm) ); if( pIdxInfo==0 ){ sqlite3ErrorMsg(pParse, "out of memory"); return 0; @@ -166564,11 +167541,8 @@ static int whereLoopAddBtreeIndex( assert( pNew->u.btree.nBtm==0 ); opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; } - if( pProbe->bUnordered || pProbe->bLowQual ){ - if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); - if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){ - opMask &= ~(WO_EQ|WO_IN|WO_IS); - } + if( pProbe->bUnordered ){ + opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); } assert( pNew->u.btree.nEqnColumn ); @@ -166881,7 +167855,7 @@ static int whereLoopAddBtreeIndex( if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->u.btree.nEqnColumn && (pNew->u.btree.nEqnKeyCol || - pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY) + (pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY && !pProbe->bIdxRowid)) ){ if( pNew->u.btree.nEq>3 ){ sqlite3ProgressCheck(pParse); @@ -167010,6 +167984,7 @@ static int whereUsablePartialIndex( if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab) && ((jointype & JT_OUTER)==0 || ExprHasProperty(pExpr, EP_OuterON)) && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) + && !sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, -1) && (pTerm->wtFlags & TERM_VNULL)==0 ){ return 1; @@ -167505,7 +168480,7 @@ static int whereLoopAddBtree( && (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700)) ){ WHERETRACE(0x200, - ("-> %s a covering index according to bitmasks\n", + ("-> %s is a covering index according to bitmasks\n", pProbe->zName, m==0 ? "is" : "is not")); pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; } @@ -170122,10 +171097,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( ** field (type Bitmask) it must be aligned on an 8-byte boundary on ** some architectures. Hence the ROUND8() below. */ - nByteWInfo = ROUND8P(sizeof(WhereInfo)); - if( nTabList>1 ){ - nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel)); - } + nByteWInfo = SZ_WHEREINFO(nTabList); pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop)); if( db->mallocFailed ){ sqlite3DbFree(db, pWInfo); @@ -170342,7 +171314,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } /* TUNING: Assume that a DISTINCT clause on a subquery reduces - ** the output size by a factor of 8 (LogEst -30). + ** the output size by a factor of 8 (LogEst -30). Search for + ** tag-20250414a to see other cases. */ if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){ WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n", @@ -172077,7 +173050,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ p->pWhere = 0; p->pGroupBy = 0; p->pHaving = 0; - p->selFlags &= ~SF_Aggregate; + p->selFlags &= ~(u32)SF_Aggregate; p->selFlags |= SF_WinRewrite; /* Create the ORDER BY clause for the sub-select. This is the concatenation @@ -174217,6 +175190,11 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( /* #include "sqliteInt.h" */ +/* +** Verify that the pParse->isCreate field is set +*/ +#define ASSERT_IS_CREATE assert(pParse->isCreate) + /* ** Disable all error recovery processing in the parser push-down ** automaton. @@ -174280,6 +175258,10 @@ static void parserSyntaxError(Parse *pParse, Token *p){ static void disableLookaside(Parse *pParse){ sqlite3 *db = pParse->db; pParse->disableLookaside++; +#ifdef SQLITE_DEBUG + pParse->isCreate = 1; +#endif + memset(&pParse->u1.cr, 0, sizeof(pParse->u1.cr)); DisableLookaside; } @@ -177916,7 +178898,9 @@ static YYACTIONTYPE yy_reduce( } break; case 14: /* createkw ::= CREATE */ -{disableLookaside(pParse);} +{ + disableLookaside(pParse); +} break; case 15: /* ifnotexists ::= */ case 18: /* temp ::= */ yytestcase(yyruleno==18); @@ -178008,7 +178992,7 @@ static YYACTIONTYPE yy_reduce( break; case 32: /* ccons ::= CONSTRAINT nm */ case 67: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==67); -{pParse->constraintName = yymsp[0].minor.yy0;} +{ASSERT_IS_CREATE; pParse->u1.cr.constraintName = yymsp[0].minor.yy0;} break; case 33: /* ccons ::= DEFAULT scantok term */ {sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy590,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} @@ -178118,7 +179102,7 @@ static YYACTIONTYPE yy_reduce( {yymsp[-1].minor.yy502 = 0;} break; case 66: /* tconscomma ::= COMMA */ -{pParse->constraintName.n = 0;} +{ASSERT_IS_CREATE; pParse->u1.cr.constraintName.n = 0;} break; case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ {sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy402,yymsp[0].minor.yy502,yymsp[-2].minor.yy502,0);} @@ -178205,8 +179189,8 @@ static YYACTIONTYPE yy_reduce( if( pRhs ){ pRhs->op = (u8)yymsp[-1].minor.yy502; pRhs->pPrior = pLhs; - if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; - pRhs->selFlags &= ~SF_MultiValue; + if( ALWAYS(pLhs) ) pLhs->selFlags &= ~(u32)SF_MultiValue; + pRhs->selFlags &= ~(u32)SF_MultiValue; if( yymsp[-1].minor.yy502!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, pLhs); @@ -179011,6 +179995,10 @@ static YYACTIONTYPE yy_reduce( { sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy502, yymsp[-4].minor.yy28.a, yymsp[-4].minor.yy28.b, yymsp[-2].minor.yy563, yymsp[0].minor.yy590, yymsp[-10].minor.yy502, yymsp[-8].minor.yy502); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ +#ifdef SQLITE_DEBUG + assert( pParse->isCreate ); /* Set by createkw reduce action */ + pParse->isCreate = 0; /* But, should not be set for CREATE TRIGGER */ +#endif } break; case 262: /* trigger_time ::= BEFORE|AFTER */ @@ -180946,7 +181934,11 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){ assert( n==6 ); tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed); #endif /* SQLITE_OMIT_WINDOWFUNC */ - }else if( tokenType==TK_COMMENT && (db->flags & SQLITE_Comments)!=0 ){ + }else if( tokenType==TK_COMMENT + && (db->init.busy || (db->flags & SQLITE_Comments)!=0) + ){ + /* Ignore SQL comments if either (1) we are reparsing the schema or + ** (2) SQLITE_DBCONFIG_ENABLE_COMMENTS is turned on (the default). */ zSql += n; continue; }else if( tokenType!=TK_QNUMBER ){ @@ -181841,6 +182833,14 @@ SQLITE_API int sqlite3_initialize(void){ if( rc==SQLITE_OK ){ sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage, sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage); +#ifdef SQLITE_EXTRA_INIT_MUTEXED + { + int SQLITE_EXTRA_INIT_MUTEXED(const char*); + rc = SQLITE_EXTRA_INIT_MUTEXED(0); + } +#endif + } + if( rc==SQLITE_OK ){ sqlite3MemoryBarrier(); sqlite3GlobalConfig.isInit = 1; #ifdef SQLITE_EXTRA_INIT @@ -182297,17 +183297,22 @@ SQLITE_API int sqlite3_config(int op, ...){ ** If lookaside is already active, return SQLITE_BUSY. ** ** The sz parameter is the number of bytes in each lookaside slot. -** The cnt parameter is the number of slots. If pStart is NULL the -** space for the lookaside memory is obtained from sqlite3_malloc(). -** If pStart is not NULL then it is sz*cnt bytes of memory to use for -** the lookaside memory. +** The cnt parameter is the number of slots. If pBuf is NULL the +** space for the lookaside memory is obtained from sqlite3_malloc() +** or similar. If pBuf is not NULL then it is sz*cnt bytes of memory +** to use for the lookaside memory. */ -static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ +static int setupLookaside( + sqlite3 *db, /* Database connection being configured */ + void *pBuf, /* Memory to use for lookaside. May be NULL */ + int sz, /* Desired size of each lookaside memory slot */ + int cnt /* Number of slots to allocate */ +){ #ifndef SQLITE_OMIT_LOOKASIDE - void *pStart; - sqlite3_int64 szAlloc; - int nBig; /* Number of full-size slots */ - int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */ + void *pStart; /* Start of the lookaside buffer */ + sqlite3_int64 szAlloc; /* Total space set aside for lookaside memory */ + int nBig; /* Number of full-size slots */ + int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */ if( sqlite3LookasideUsed(db,0)>0 ){ return SQLITE_BUSY; @@ -182320,19 +183325,22 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ sqlite3_free(db->lookaside.pStart); } /* The size of a lookaside slot after ROUNDDOWN8 needs to be larger - ** than a pointer to be useful. + ** than a pointer and small enough to fit in a u16. */ - sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */ + sz = ROUNDDOWN8(sz); if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0; if( sz>65528 ) sz = 65528; - if( cnt<0 ) cnt = 0; + /* Count must be at least 1 to be useful, but not so large as to use + ** more than 0x7fff0000 total bytes for lookaside. */ + if( cnt<1 ) cnt = 0; + if( sz>0 && cnt>(0x7fff0000/sz) ) cnt = 0x7fff0000/sz; szAlloc = (i64)sz*(i64)cnt; - if( sz==0 || cnt==0 ){ + if( szAlloc==0 ){ sz = 0; pStart = 0; }else if( pBuf==0 ){ sqlite3BeginBenignMalloc(); - pStart = sqlite3Malloc( szAlloc ); /* IMP: R-61949-35727 */ + pStart = sqlite3Malloc( szAlloc ); sqlite3EndBenignMalloc(); if( pStart ) szAlloc = sqlite3MallocSize(pStart); }else{ @@ -183309,6 +184317,9 @@ SQLITE_API int sqlite3_busy_handler( db->busyHandler.pBusyArg = pArg; db->busyHandler.nBusy = 0; db->busyTimeout = 0; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + db->setlkTimeout = 0; +#endif sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -183358,12 +184369,47 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback, (void*)db); db->busyTimeout = ms; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + db->setlkTimeout = ms; +#endif }else{ sqlite3_busy_handler(db, 0, 0); } return SQLITE_OK; } +/* +** Set the setlk timeout value. +*/ +SQLITE_API int sqlite3_setlk_timeout(sqlite3 *db, int ms, int flags){ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + int iDb; + int bBOC = ((flags & SQLITE_SETLK_BLOCK_ON_CONNECT) ? 1 : 0); +#endif +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + if( ms<-1 ) return SQLITE_RANGE; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + db->setlkTimeout = ms; + db->setlkFlags = flags; + sqlite3BtreeEnterAll(db); + for(iDb=0; iDbnDb; iDb++){ + Btree *pBt = db->aDb[iDb].pBt; + if( pBt ){ + sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pBt)); + sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, (void*)&bBOC); + } + } + sqlite3BtreeLeaveAll(db); +#endif +#if !defined(SQLITE_ENABLE_API_ARMOR) && !defined(SQLITE_ENABLE_SETLK_TIMEOUT) + UNUSED_PARAMETER(db); + UNUSED_PARAMETER(flags); +#endif + return SQLITE_OK; +} + /* ** Cause any pending operation to stop at its earliest opportunity. */ @@ -185329,7 +186375,7 @@ SQLITE_API int sqlite3_set_clientdata( return SQLITE_OK; }else{ size_t n = strlen(zName); - p = sqlite3_malloc64( sizeof(DbClientData)+n+1 ); + p = sqlite3_malloc64( SZ_DBCLIENTDATA(n+1) ); if( p==0 ){ if( xDestructor ) xDestructor(pData); sqlite3_mutex_leave(db->mutex); @@ -185483,13 +186529,10 @@ SQLITE_API int sqlite3_table_column_metadata( if( zColumnName==0 ){ /* Query for existence of table only */ }else{ - for(iCol=0; iColnCol; iCol++){ + iCol = sqlite3ColumnIndex(pTab, zColumnName); + if( iCol>=0 ){ pCol = &pTab->aCol[iCol]; - if( 0==sqlite3StrICmp(pCol->zCnName, zColumnName) ){ - break; - } - } - if( iCol==pTab->nCol ){ + }else{ if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){ iCol = pTab->iPKey; pCol = iCol>=0 ? &pTab->aCol[iCol] : 0; @@ -185698,8 +186741,8 @@ SQLITE_API int sqlite3_test_control(int op, ...){ /* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlite3 *db, int b); ** ** If b is true, then activate the SQLITE_FkNoAction setting. If b is - ** false then clearn that setting. If the SQLITE_FkNoAction setting is - ** abled, all foreign key ON DELETE and ON UPDATE actions behave as if + ** false then clear that setting. If the SQLITE_FkNoAction setting is + ** enabled, all foreign key ON DELETE and ON UPDATE actions behave as if ** they were NO ACTION, regardless of how they are defined. ** ** NB: One must usually run "PRAGMA writable_schema=RESET" after @@ -187046,7 +188089,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){ ** Here, array { X } means zero or more occurrences of X, adjacent in ** memory. A "position" is an index of a token in the token stream ** generated by the tokenizer. Note that POS_END and POS_COLUMN occur -** in the same logical place as the position element, and act as sentinals +** in the same logical place as the position element, and act as sentinels ** ending a position list array. POS_END is 0. POS_COLUMN is 1. ** The positions numbers are not stored literally but rather as two more ** than the difference from the prior position, or the just the position plus @@ -187265,6 +188308,13 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){ #ifndef _FTSINT_H #define _FTSINT_H +/* #include */ +/* #include */ +/* #include */ +/* #include */ +/* #include */ +/* #include */ + #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif @@ -187734,6 +188784,19 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */ #define deliberate_fall_through +/* +** Macros needed to provide flexible arrays in a portable way +*/ +#ifndef offsetof +# define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD)) +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEXARRAY +#else +# define FLEXARRAY 1 +#endif + + #endif /* SQLITE_AMALGAMATION */ #ifdef SQLITE_DEBUG @@ -187838,7 +188901,7 @@ struct Fts3Table { #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - /* True to disable the incremental doclist optimization. This is controled + /* True to disable the incremental doclist optimization. This is controlled ** by special insert command 'test-no-incr-doclist'. */ int bNoIncrDoclist; @@ -187890,7 +188953,7 @@ struct Fts3Cursor { /* ** The Fts3Cursor.eSearch member is always set to one of the following. -** Actualy, Fts3Cursor.eSearch can be greater than or equal to +** Actually, Fts3Cursor.eSearch can be greater than or equal to ** FTS3_FULLTEXT_SEARCH. If so, then Fts3Cursor.eSearch - 2 is the index ** of the column to be searched. For example, in ** @@ -187963,9 +189026,13 @@ struct Fts3Phrase { */ int nToken; /* Number of tokens in the phrase */ int iColumn; /* Index of column this phrase must match */ - Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */ + Fts3PhraseToken aToken[FLEXARRAY]; /* One for each token in the phrase */ }; +/* Size (in bytes) of an Fts3Phrase object large enough to hold N tokens */ +#define SZ_FTS3PHRASE(N) \ + (offsetof(Fts3Phrase,aToken)+(N)*sizeof(Fts3PhraseToken)) + /* ** A tree of these objects forms the RHS of a MATCH operator. ** @@ -188199,12 +189266,6 @@ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk); # define SQLITE_CORE 1 #endif -/* #include */ -/* #include */ -/* #include */ -/* #include */ -/* #include */ -/* #include */ /* #include "fts3.h" */ #ifndef SQLITE_CORE @@ -190543,7 +191604,7 @@ static int fts3DoclistOrMerge( ** sizes of the two inputs, plus enough space for exactly one of the input ** docids to grow. ** - ** A symetric argument may be made if the doclists are in descending + ** A symmetric argument may be made if the doclists are in descending ** order. */ aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING); @@ -192342,7 +193403,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ nDistance = iPrev - nMaxUndeferred; } - aOut = (char *)sqlite3Fts3MallocZero(nPoslist+FTS3_BUFFER_PADDING); + aOut = (char *)sqlite3Fts3MallocZero(((i64)nPoslist)+FTS3_BUFFER_PADDING); if( !aOut ){ sqlite3_free(aPoslist); return SQLITE_NOMEM; @@ -192641,7 +193702,7 @@ static int incrPhraseTokenNext( ** ** * does not contain any deferred tokens. ** -** Advance it to the next matching documnent in the database and populate +** Advance it to the next matching document in the database and populate ** the Fts3Doclist.pList and nList fields. ** ** If there is no "next" entry and no error occurs, then *pbEof is set to @@ -193648,7 +194709,7 @@ static int fts3EvalNext(Fts3Cursor *pCsr){ } /* -** Restart interation for expression pExpr so that the next call to +** Restart iteration for expression pExpr so that the next call to ** fts3EvalNext() visits the first row. Do not allow incremental ** loading or merging of phrase doclists for this iteration. ** @@ -194840,6 +195901,23 @@ SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer( */ static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *); +/* +** Search buffer z[], size n, for a '"' character. Or, if enable_parenthesis +** is defined, search for '(' and ')' as well. Return the index of the first +** such character in the buffer. If there is no such character, return -1. +*/ +static int findBarredChar(const char *z, int n){ + int ii; + for(ii=0; iiiLangid, z, i, &pCursor); + *pnConsumed = n; + rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor); if( rc==SQLITE_OK ){ const char *zToken; int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; @@ -194881,7 +195952,18 @@ static int getNextToken( rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); if( rc==SQLITE_OK ){ - nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; + /* Check that this tokenization did not gobble up any " characters. Or, + ** if enable_parenthesis is true, that it did not gobble up any + ** open or close parenthesis characters either. If it did, call + ** getNextToken() again, but pass only that part of the input buffer + ** up to the first such character. */ + int iBarred = findBarredChar(z, iEnd); + if( iBarred>=0 ){ + pModule->xClose(pCursor); + return getNextToken(pParse, iCol, z, iBarred, ppExpr, pnConsumed); + } + + nByte = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1) + nToken; pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte); if( !pRet ){ rc = SQLITE_NOMEM; @@ -194891,7 +195973,7 @@ static int getNextToken( pRet->pPhrase->nToken = 1; pRet->pPhrase->iColumn = iCol; pRet->pPhrase->aToken[0].n = nToken; - pRet->pPhrase->aToken[0].z = (char *)&pRet->pPhrase[1]; + pRet->pPhrase->aToken[0].z = (char*)&pRet->pPhrase->aToken[1]; memcpy(pRet->pPhrase->aToken[0].z, zToken, nToken); if( iEnd=0 ){ + *pnConsumed = iBarred; + } rc = SQLITE_OK; } @@ -194962,9 +196048,9 @@ static int getNextString( Fts3Expr *p = 0; sqlite3_tokenizer_cursor *pCursor = 0; char *zTemp = 0; - int nTemp = 0; + i64 nTemp = 0; - const int nSpace = sizeof(Fts3Expr) + sizeof(Fts3Phrase); + const int nSpace = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1); int nToken = 0; /* The final Fts3Expr data structure, including the Fts3Phrase, @@ -195336,7 +196422,7 @@ static int fts3ExprParse( /* The isRequirePhrase variable is set to true if a phrase or ** an expression contained in parenthesis is required. If a - ** binary operator (AND, OR, NOT or NEAR) is encounted when + ** binary operator (AND, OR, NOT or NEAR) is encountered when ** isRequirePhrase is set, this is a syntax error. */ if( !isPhrase && isRequirePhrase ){ @@ -195918,7 +197004,6 @@ static void fts3ExprTestCommon( } if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ - sqlite3Fts3ExprFree(pExpr); sqlite3_result_error(context, "Error parsing expression", -1); }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){ sqlite3_result_error_nomem(context); @@ -196161,7 +197246,7 @@ static void fts3HashInsertElement( } -/* Resize the hash table so that it cantains "new_size" buckets. +/* Resize the hash table so that it contains "new_size" buckets. ** "new_size" must be a power of 2. The hash table might fail ** to resize if sqliteMalloc() fails. ** @@ -196616,7 +197701,7 @@ static int star_oh(const char *z){ /* ** If the word ends with zFrom and xCond() is true for the stem -** of the word that preceeds the zFrom ending, then change the +** of the word that precedes the zFrom ending, then change the ** ending to zTo. ** ** The input word *pz and zFrom are both in reverse order. zTo @@ -198127,7 +199212,7 @@ static int fts3tokFilterMethod( fts3tokResetCursor(pCsr); if( idxNum==1 ){ const char *zByte = (const char *)sqlite3_value_text(apVal[0]); - int nByte = sqlite3_value_bytes(apVal[0]); + sqlite3_int64 nByte = sqlite3_value_bytes(apVal[0]); pCsr->zInput = sqlite3_malloc64(nByte+1); if( pCsr->zInput==0 ){ rc = SQLITE_NOMEM; @@ -202199,7 +203284,7 @@ static int fts3IncrmergePush( ** ** It is assumed that the buffer associated with pNode is already large ** enough to accommodate the new entry. The buffer associated with pPrev -** is extended by this function if requrired. +** is extended by this function if required. ** ** If an error (i.e. OOM condition) occurs, an SQLite error code is ** returned. Otherwise, SQLITE_OK. @@ -203862,7 +204947,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken( /* ** SQLite value pRowid contains the rowid of a row that may or may not be ** present in the FTS3 table. If it is, delete it and adjust the contents -** of subsiduary data structures accordingly. +** of subsidiary data structures accordingly. */ static int fts3DeleteByRowid( Fts3Table *p, @@ -204188,9 +205273,13 @@ struct MatchinfoBuffer { int nElem; int bGlobal; /* Set if global data is loaded */ char *zMatchinfo; - u32 aMatchinfo[1]; + u32 aMI[FLEXARRAY]; }; +/* Size (in bytes) of a MatchinfoBuffer sufficient for N elements */ +#define SZ_MATCHINFOBUFFER(N) \ + (offsetof(MatchinfoBuffer,aMI)+(((N)+1)/2)*sizeof(u64)) + /* ** The snippet() and offsets() functions both return text values. An instance @@ -204215,13 +205304,13 @@ struct StrBuffer { static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ MatchinfoBuffer *pRet; sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1) - + sizeof(MatchinfoBuffer); + + SZ_MATCHINFOBUFFER(1); sqlite3_int64 nStr = strlen(zMatchinfo); pRet = sqlite3Fts3MallocZero(nByte + nStr+1); if( pRet ){ - pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; - pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + pRet->aMI[0] = (u8*)(&pRet->aMI[1]) - (u8*)pRet; + pRet->aMI[1+nElem] = pRet->aMI[0] + sizeof(u32)*((int)nElem+1); pRet->nElem = (int)nElem; pRet->zMatchinfo = ((char*)pRet) + nByte; @@ -204235,10 +205324,10 @@ static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ static void fts3MIBufferFree(void *p){ MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]); - assert( (u32*)p==&pBuf->aMatchinfo[1] - || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2] + assert( (u32*)p==&pBuf->aMI[1] + || (u32*)p==&pBuf->aMI[pBuf->nElem+2] ); - if( (u32*)p==&pBuf->aMatchinfo[1] ){ + if( (u32*)p==&pBuf->aMI[1] ){ pBuf->aRef[1] = 0; }else{ pBuf->aRef[2] = 0; @@ -204255,18 +205344,18 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){ if( p->aRef[1]==0 ){ p->aRef[1] = 1; - aOut = &p->aMatchinfo[1]; + aOut = &p->aMI[1]; xRet = fts3MIBufferFree; } else if( p->aRef[2]==0 ){ p->aRef[2] = 1; - aOut = &p->aMatchinfo[p->nElem+2]; + aOut = &p->aMI[p->nElem+2]; xRet = fts3MIBufferFree; }else{ aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32)); if( aOut ){ xRet = sqlite3_free; - if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32)); + if( p->bGlobal ) memcpy(aOut, &p->aMI[1], p->nElem*sizeof(u32)); } } @@ -204276,7 +205365,7 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){ static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){ p->bGlobal = 1; - memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32)); + memcpy(&p->aMI[2+p->nElem], &p->aMI[1], p->nElem*sizeof(u32)); } /* @@ -204691,7 +205780,7 @@ static int fts3StringAppend( } /* If there is insufficient space allocated at StrBuffer.z, use realloc() - ** to grow the buffer until so that it is big enough to accomadate the + ** to grow the buffer until so that it is big enough to accommodate the ** appended data. */ if( pStr->n+nAppend+1>=pStr->nAlloc ){ @@ -205103,16 +206192,16 @@ static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ break; case FTS3_MATCHINFO_LHITS: - nVal = pInfo->nCol * pInfo->nPhrase; + nVal = (size_t)pInfo->nCol * pInfo->nPhrase; break; case FTS3_MATCHINFO_LHITS_BM: - nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32); + nVal = (size_t)pInfo->nPhrase * ((pInfo->nCol + 31) / 32); break; default: assert( cArg==FTS3_MATCHINFO_HITS ); - nVal = pInfo->nCol * pInfo->nPhrase * 3; + nVal = (size_t)pInfo->nCol * pInfo->nPhrase * 3; break; } @@ -206670,8 +207759,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ ** Beginning with version 3.45.0 (circa 2024-01-01), these routines also ** accept BLOB values that have JSON encoded using a binary representation ** called "JSONB". The name JSONB comes from PostgreSQL, however the on-disk -** format SQLite JSONB is completely different and incompatible with -** PostgreSQL JSONB. +** format for SQLite-JSONB is completely different and incompatible with +** PostgreSQL-JSONB. ** ** Decoding and interpreting JSONB is still O(N) where N is the size of ** the input, the same as text JSON. However, the constant of proportionality @@ -206728,7 +207817,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ ** ** The payload size need not be expressed in its minimal form. For example, ** if the payload size is 10, the size can be expressed in any of 5 different -** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte, +** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by one 0x0a byte, ** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by ** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and ** a single byte of 0x0a. The shorter forms are preferred, of course, but @@ -206738,7 +207827,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ ** the size when it becomes known, resulting in a non-minimal encoding. ** ** The value (X>>4)==15 is not actually used in the current implementation -** (as SQLite is currently unable handle BLOBs larger than about 2GB) +** (as SQLite is currently unable to handle BLOBs larger than about 2GB) ** but is included in the design to allow for future enhancements. ** ** The payload follows the header. NULL, TRUE, and FALSE have no payload and @@ -206798,23 +207887,47 @@ static const char * const jsonbType[] = { ** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). */ static const char jsonIsSpace[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#ifdef SQLITE_ASCII +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */ +#endif +#ifdef SQLITE_EBCDIC +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */ +#endif + }; #define jsonIsspace(x) (jsonIsSpace[(unsigned char)x]) @@ -206822,7 +207935,13 @@ static const char jsonIsSpace[] = { ** The set of all space characters recognized by jsonIsspace(). ** Useful as the second argument to strspn(). */ +#ifdef SQLITE_ASCII static const char jsonSpaces[] = "\011\012\015\040"; +#endif +#ifdef SQLITE_EBCDIC +static const char jsonSpaces[] = "\005\045\015\100"; +#endif + /* ** Characters that are special to JSON. Control characters, @@ -206831,23 +207950,46 @@ static const char jsonSpaces[] = "\011\012\015\040"; ** it in the set of special characters. */ static const char jsonIsOk[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +#ifdef SQLITE_ASCII +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ + 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 2 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 5 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */ +#endif +#ifdef SQLITE_EBCDIC +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 3 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 5 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, /* 7 */ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */ +#endif }; /* Objects */ @@ -206992,7 +208134,7 @@ struct JsonParse { ** Forward references **************************************************************************/ static void jsonReturnStringAsBlob(JsonString*); -static int jsonFuncArgMightBeBinary(sqlite3_value *pJson); +static int jsonArgIsJsonb(sqlite3_value *pJson, JsonParse *p); static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*); static void jsonReturnParse(sqlite3_context*,JsonParse*); static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32); @@ -207066,7 +208208,7 @@ static int jsonCacheInsert( ** most-recently used entry if it isn't so already. ** ** The JsonParse object returned still belongs to the Cache and might -** be deleted at any moment. If the caller whants the JsonParse to +** be deleted at any moment. If the caller wants the JsonParse to ** linger, it needs to increment the nPJRef reference counter. */ static JsonParse *jsonCacheSearch( @@ -207410,11 +208552,9 @@ static void jsonAppendSqlValue( break; } default: { - if( jsonFuncArgMightBeBinary(pValue) ){ - JsonParse px; - memset(&px, 0, sizeof(px)); - px.aBlob = (u8*)sqlite3_value_blob(pValue); - px.nBlob = sqlite3_value_bytes(pValue); + JsonParse px; + memset(&px, 0, sizeof(px)); + if( jsonArgIsJsonb(pValue, &px) ){ jsonTranslateBlobToText(&px, 0, p); }else if( p->eErr==0 ){ sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); @@ -207733,7 +208873,7 @@ static void jsonWrongNumArgs( */ static int jsonBlobExpand(JsonParse *pParse, u32 N){ u8 *aNew; - u32 t; + u64 t; assert( N>pParse->nBlobAlloc ); if( pParse->nBlobAlloc==0 ){ t = 100; @@ -207743,8 +208883,9 @@ static int jsonBlobExpand(JsonParse *pParse, u32 N){ if( tdb, pParse->aBlob, t); if( aNew==0 ){ pParse->oom = 1; return 1; } + assert( t<0x7fffffff ); pParse->aBlob = aNew; - pParse->nBlobAlloc = t; + pParse->nBlobAlloc = (u32)t; return 0; } @@ -207811,7 +208952,7 @@ static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode( } -/* Append an node type byte together with the payload size and +/* Append a node type byte together with the payload size and ** possibly also the payload. ** ** If aPayload is not NULL, then it is a pointer to the payload which @@ -208351,7 +209492,12 @@ static int jsonTranslateTextToBlob(JsonParse *pParse, u32 i){ || c=='n' || c=='r' || c=='t' || (c=='u' && jsonIs4Hex(&z[j+1])) ){ if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ; - }else if( c=='\'' || c=='0' || c=='v' || c=='\n' + }else if( c=='\'' || c=='v' || c=='\n' +#ifdef SQLITE_BUG_COMPATIBLE_20250510 + || (c=='0') /* Legacy bug compatible */ +#else + || (c=='0' && !sqlite3Isdigit(z[j+1])) /* Correct implementation */ +#endif || (0xe2==(u8)c && 0x80==(u8)z[j+1] && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])) || (c=='x' && jsonIs2Hex(&z[j+1])) ){ @@ -208701,10 +209847,7 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ u8 x; u32 sz; u32 n; - if( NEVER(i>pParse->nBlob) ){ - *pSz = 0; - return 0; - } + assert( i<=pParse->nBlob ); x = pParse->aBlob[i]>>4; if( x<=11 ){ sz = x; @@ -208741,15 +209884,15 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ *pSz = 0; return 0; } - sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + + sz = ((u32)pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8]; n = 9; } if( (i64)i+sz+n > pParse->nBlob && (i64)i+sz+n > pParse->nBlob-pParse->delta ){ - sz = 0; - n = 0; + *pSz = 0; + return 0; } *pSz = sz; return n; @@ -208846,9 +209989,12 @@ static u32 jsonTranslateBlobToText( } case JSONB_TEXT: case JSONB_TEXTJ: { - jsonAppendChar(pOut, '"'); - jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz); - jsonAppendChar(pOut, '"'); + if( pOut->nUsed+sz+2<=pOut->nAlloc || jsonStringGrow(pOut, sz+2)==0 ){ + pOut->zBuf[pOut->nUsed] = '"'; + memcpy(pOut->zBuf+pOut->nUsed+1,(const char*)&pParse->aBlob[i+n],sz); + pOut->zBuf[pOut->nUsed+sz+1] = '"'; + pOut->nUsed += sz+2; + } break; } case JSONB_TEXT5: { @@ -209087,33 +210233,6 @@ static u32 jsonTranslateBlobToPrettyText( return i; } - -/* Return true if the input pJson -** -** For performance reasons, this routine does not do a detailed check of the -** input BLOB to ensure that it is well-formed. Hence, false positives are -** possible. False negatives should never occur, however. -*/ -static int jsonFuncArgMightBeBinary(sqlite3_value *pJson){ - u32 sz, n; - const u8 *aBlob; - int nBlob; - JsonParse s; - if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0; - aBlob = sqlite3_value_blob(pJson); - nBlob = sqlite3_value_bytes(pJson); - if( nBlob<1 ) return 0; - if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0; - memset(&s, 0, sizeof(s)); - s.aBlob = (u8*)aBlob; - s.nBlob = nBlob; - n = jsonbPayloadSize(&s, 0, &sz); - if( n==0 ) return 0; - if( sz+n!=(u32)nBlob ) return 0; - if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0; - return sz+n==(u32)nBlob; -} - /* ** Given that a JSONB_ARRAY object starts at offset i, return ** the number of entries in that array. @@ -209146,6 +210265,82 @@ static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){ pParse->delta += jsonBlobChangePayloadSize(pParse, iRoot, sz); } +/* +** If the JSONB at aIns[0..nIns-1] can be expanded (by denormalizing the +** size field) by d bytes, then write the expansion into aOut[] and +** return true. In this way, an overwrite happens without changing the +** size of the JSONB, which reduces memcpy() operations and also make it +** faster and easier to update the B-Tree entry that contains the JSONB +** in the database. +** +** If the expansion of aIns[] by d bytes cannot be (easily) accomplished +** then return false. +** +** The d parameter is guaranteed to be between 1 and 8. +** +** This routine is an optimization. A correct answer is obtained if it +** always leaves the output unchanged and returns false. +*/ +static int jsonBlobOverwrite( + u8 *aOut, /* Overwrite here */ + const u8 *aIns, /* New content */ + u32 nIns, /* Bytes of new content */ + u32 d /* Need to expand new content by this much */ +){ + u32 szPayload; /* Bytes of payload */ + u32 i; /* New header size, after expansion & a loop counter */ + u8 szHdr; /* Size of header before expansion */ + + /* Lookup table for finding the upper 4 bits of the first byte of the + ** expanded aIns[], based on the size of the expanded aIns[] header: + ** + ** 2 3 4 5 6 7 8 9 */ + static const u8 aType[] = { 0xc0, 0xd0, 0, 0xe0, 0, 0, 0, 0xf0 }; + + if( (aIns[0]&0x0f)<=2 ) return 0; /* Cannot enlarge NULL, true, false */ + switch( aIns[0]>>4 ){ + default: { /* aIns[] header size 1 */ + if( ((1<=2 && i<=9 && aType[i-2]!=0 ); + aOut[0] = (aIns[0] & 0x0f) | aType[i-2]; + memcpy(&aOut[i], &aIns[szHdr], nIns-szHdr); + szPayload = nIns - szHdr; + while( 1/*edit-by-break*/ ){ + i--; + aOut[i] = szPayload & 0xff; + if( i==1 ) break; + szPayload >>= 8; + } + assert( (szPayload>>8)==0 ); + return 1; +} + /* ** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of ** content beginning at iDel, and replacing them with nIns bytes of @@ -209167,6 +210362,11 @@ static void jsonBlobEdit( u32 nIns /* Bytes of content to insert */ ){ i64 d = (i64)nIns - (i64)nDel; + if( d<0 && d>=(-8) && aIns!=0 + && jsonBlobOverwrite(&pParse->aBlob[iDel], aIns, nIns, (int)-d) + ){ + return; + } if( d!=0 ){ if( pParse->nBlob + d > pParse->nBlobAlloc ){ jsonBlobExpand(pParse, pParse->nBlob+d); @@ -209178,7 +210378,9 @@ static void jsonBlobEdit( pParse->nBlob += d; pParse->delta += d; } - if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns); + if( nIns && aIns ){ + memcpy(&pParse->aBlob[iDel], aIns, nIns); + } } /* @@ -209263,7 +210465,21 @@ static u32 jsonUnescapeOneChar(const char *z, u32 n, u32 *piOut){ case 'r': { *piOut = '\r'; return 2; } case 't': { *piOut = '\t'; return 2; } case 'v': { *piOut = '\v'; return 2; } - case '0': { *piOut = 0; return 2; } + case '0': { + /* JSON5 requires that the \0 escape not be followed by a digit. + ** But SQLite did not enforce this restriction in versions 3.42.0 + ** through 3.49.2. That was a bug. But some applications might have + ** come to depend on that bug. Use the SQLITE_BUG_COMPATIBLE_20250510 + ** option to restore the old buggy behavior. */ +#ifdef SQLITE_BUG_COMPATIBLE_20250510 + /* Legacy bug-compatible behavior */ + *piOut = 0; +#else + /* Correct behavior */ + *piOut = (n>2 && sqlite3Isdigit(z[2])) ? JSON_INVALID_CHAR : 0; +#endif + return 2; + } case '\'': case '"': case '/': @@ -209763,7 +210979,7 @@ static void jsonReturnFromBlob( char *zOut; u32 nOut = sz; z = (const char*)&pParse->aBlob[i+n]; - zOut = sqlite3DbMallocRaw(db, nOut+1); + zOut = sqlite3DbMallocRaw(db, ((u64)nOut)+1); if( zOut==0 ) goto returnfromblob_oom; for(iIn=iOut=0; iInaBlob = (u8*)sqlite3_value_blob(pArg); - pParse->nBlob = sqlite3_value_bytes(pArg); - }else{ + if( !jsonArgIsJsonb(pArg, pParse) ){ sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1); return 1; } @@ -209941,7 +211154,7 @@ static char *jsonBadPathError( } /* argv[0] is a BLOB that seems likely to be a JSONB. Subsequent -** arguments come in parse where each pair contains a JSON path and +** arguments come in pairs where each pair contains a JSON path and ** content to insert or set at that patch. Do the updates ** and return the result. ** @@ -210012,27 +211225,46 @@ static void jsonInsertIntoBlob( /* ** If pArg is a blob that seems like a JSONB blob, then initialize ** p to point to that JSONB and return TRUE. If pArg does not seem like -** a JSONB blob, then return FALSE; -** -** This routine is only called if it is already known that pArg is a -** blob. The only open question is whether or not the blob appears -** to be a JSONB blob. +** a JSONB blob, then return FALSE. +** +** For small BLOBs (having no more than 7 bytes of payload) a full +** validity check is done. So for small BLOBs this routine only returns +** true if the value is guaranteed to be a valid JSONB. For larger BLOBs +** (8 byte or more of payload) only the size of the outermost element is +** checked to verify that the BLOB is superficially valid JSONB. +** +** A full JSONB validation is done on smaller BLOBs because those BLOBs might +** also be text JSON that has been incorrectly cast into a BLOB. +** (See tag-20240123-a and https://sqlite.org/forum/forumpost/012136abd5) +** If the BLOB is 9 bytes are larger, then it is not possible for the +** superficial size check done here to pass if the input is really text +** JSON so we do not need to look deeper in that case. +** +** Why we only need to do full JSONB validation for smaller BLOBs: +** +** The first byte of valid JSON text must be one of: '{', '[', '"', ' ', '\n', +** '\r', '\t', '-', or a digit '0' through '9'. Of these, only a subset +** can also be the first byte of JSONB: '{', '[', and digits '3' +** through '9'. In every one of those cases, the payload size is 7 bytes +** or less. So if we do full JSONB validation for every BLOB where the +** payload is less than 7 bytes, we will never get a false positive for +** JSONB on an input that is really text JSON. */ static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){ u32 n, sz = 0; + u8 c; + if( sqlite3_value_type(pArg)!=SQLITE_BLOB ) return 0; p->aBlob = (u8*)sqlite3_value_blob(pArg); p->nBlob = (u32)sqlite3_value_bytes(pArg); - if( p->nBlob==0 ){ - p->aBlob = 0; - return 0; - } - if( NEVER(p->aBlob==0) ){ - return 0; - } - if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT + if( p->nBlob>0 + && ALWAYS(p->aBlob!=0) + && ((c = p->aBlob[0]) & 0x0f)<=JSONB_OBJECT && (n = jsonbPayloadSize(p, 0, &sz))>0 && sz+n==p->nBlob - && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0) + && ((c & 0x0f)>JSONB_FALSE || sz==0) + && (sz>7 + || (c!=0x7b && c!=0x5b && !sqlite3Isdigit(c)) + || jsonbValidityCheck(p, 0, p->nBlob, 1)==0) ){ return 1; } @@ -210110,7 +211342,7 @@ static JsonParse *jsonParseFuncArg( ** JSON functions were suppose to work. From the beginning, blob was ** reserved for expansion and a blob value should have raised an error. ** But it did not, due to a bug. And many applications came to depend - ** upon this buggy behavior, espeically when using the CLI and reading + ** upon this buggy behavior, especially when using the CLI and reading ** JSON text using readfile(), which returns a blob. For this reason ** we will continue to support the bug moving forward. ** See for example https://sqlite.org/forum/forumpost/012136abd5292b8d @@ -211125,21 +212357,17 @@ static void jsonValidFunc( return; } case SQLITE_BLOB: { - if( jsonFuncArgMightBeBinary(argv[0]) ){ + JsonParse py; + memset(&py, 0, sizeof(py)); + if( jsonArgIsJsonb(argv[0], &py) ){ if( flags & 0x04 ){ /* Superficial checking only - accomplished by the - ** jsonFuncArgMightBeBinary() call above. */ + ** jsonArgIsJsonb() call above. */ res = 1; }else if( flags & 0x08 ){ /* Strict checking. Check by translating BLOB->TEXT->BLOB. If ** no errors occur, call that a "strict check". */ - JsonParse px; - u32 iErr; - memset(&px, 0, sizeof(px)); - px.aBlob = (u8*)sqlite3_value_blob(argv[0]); - px.nBlob = sqlite3_value_bytes(argv[0]); - iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1); - res = iErr==0; + res = 0==jsonbValidityCheck(&py, 0, py.nBlob, 1); } break; } @@ -211197,9 +212425,7 @@ static void jsonErrorFunc( UNUSED_PARAMETER(argc); memset(&s, 0, sizeof(s)); s.db = sqlite3_context_db_handle(ctx); - if( jsonFuncArgMightBeBinary(argv[0]) ){ - s.aBlob = (u8*)sqlite3_value_blob(argv[0]); - s.nBlob = sqlite3_value_bytes(argv[0]); + if( jsonArgIsJsonb(argv[0], &s) ){ iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1); }else{ s.zJson = (char*)sqlite3_value_text(argv[0]); @@ -211360,18 +212586,20 @@ static void jsonObjectStep( UNUSED_PARAMETER(argc); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ + z = (const char*)sqlite3_value_text(argv[0]); + n = sqlite3Strlen30(z); if( pStr->zBuf==0 ){ jsonStringInit(pStr, ctx); jsonAppendChar(pStr, '{'); - }else if( pStr->nUsed>1 ){ + }else if( pStr->nUsed>1 && z!=0 ){ jsonAppendChar(pStr, ','); } pStr->pCtx = ctx; - z = (const char*)sqlite3_value_text(argv[0]); - n = sqlite3Strlen30(z); - jsonAppendString(pStr, z, n); - jsonAppendChar(pStr, ':'); - jsonAppendSqlValue(pStr, argv[1]); + if( z!=0 ){ + jsonAppendString(pStr, z, n); + jsonAppendChar(pStr, ':'); + jsonAppendSqlValue(pStr, argv[1]); + } } } static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ @@ -211884,9 +213112,8 @@ static int jsonEachFilter( memset(&p->sParse, 0, sizeof(p->sParse)); p->sParse.nJPRef = 1; p->sParse.db = p->db; - if( jsonFuncArgMightBeBinary(argv[0]) ){ - p->sParse.nBlob = sqlite3_value_bytes(argv[0]); - p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]); + if( jsonArgIsJsonb(argv[0], &p->sParse) ){ + /* We have JSONB */ }else{ p->sParse.zJson = (char*)sqlite3_value_text(argv[0]); p->sParse.nJson = sqlite3_value_bytes(argv[0]); @@ -212210,6 +213437,14 @@ typedef unsigned int u32; # define ALWAYS(X) (X) # define NEVER(X) (X) #endif +#ifndef offsetof +#define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD)) +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEXARRAY +#else +# define FLEXARRAY 1 +#endif #endif /* !defined(SQLITE_AMALGAMATION) */ /* Macro to check for 4-byte alignment. Only used inside of assert() */ @@ -212530,9 +213765,13 @@ struct RtreeMatchArg { RtreeGeomCallback cb; /* Info about the callback functions */ int nParam; /* Number of parameters to the SQL function */ sqlite3_value **apSqlParam; /* Original SQL parameter values */ - RtreeDValue aParam[1]; /* Values for parameters to the SQL function */ + RtreeDValue aParam[FLEXARRAY]; /* Values for parameters to the SQL function */ }; +/* Size of an RtreeMatchArg object with N parameters */ +#define SZ_RTREEMATCHARG(N) \ + (offsetof(RtreeMatchArg,aParam)+(N)*sizeof(RtreeDValue)) + #ifndef MAX # define MAX(x,y) ((x) < (y) ? (y) : (x)) #endif @@ -214221,7 +215460,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ } /* -** Return the N-dimensional volumn of the cell stored in *p. +** Return the N-dimensional volume of the cell stored in *p. */ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){ RtreeDValue area = (RtreeDValue)1; @@ -215987,7 +217226,7 @@ static sqlite3_stmt *rtreeCheckPrepare( /* ** The second and subsequent arguments to this function are a printf() ** style format string and arguments. This function formats the string and -** appends it to the report being accumuated in pCheck. +** appends it to the report being accumulated in pCheck. */ static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){ va_list ap; @@ -217175,7 +218414,7 @@ static void geopolyBBoxFinal( ** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2). ** Returns: ** -** +2 x0,y0 is on the line segement +** +2 x0,y0 is on the line segment ** ** +1 x0,y0 is beneath line segment ** @@ -217281,7 +218520,7 @@ static void geopolyWithinFunc( sqlite3_free(p2); } -/* Objects used by the overlap algorihm. */ +/* Objects used by the overlap algorithm. */ typedef struct GeoEvent GeoEvent; typedef struct GeoSegment GeoSegment; typedef struct GeoOverlap GeoOverlap; @@ -218328,8 +219567,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ sqlite3_int64 nBlob; int memErr = 0; - nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue) - + nArg*sizeof(sqlite3_value*); + nBlob = SZ_RTREEMATCHARG(nArg) + nArg*sizeof(sqlite3_value*); pBlob = (RtreeMatchArg *)sqlite3_malloc64(nBlob); if( !pBlob ){ sqlite3_result_error_nomem(ctx); @@ -219424,7 +220662,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** ** "RBU" stands for "Resumable Bulk Update". As in a large database update ** transmitted via a wireless network to a mobile device. A transaction -** applied using this extension is hence refered to as an "RBU update". +** applied using this extension is hence referred to as an "RBU update". ** ** ** LIMITATIONS @@ -219721,7 +220959,7 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open( ** the next call to sqlite3rbu_vacuum() opens a handle that starts a ** new RBU vacuum operation. ** -** As with sqlite3rbu_open(), Zipvfs users should rever to the comment +** As with sqlite3rbu_open(), Zipvfs users should refer to the comment ** describing the sqlite3rbu_create_vfs() API function below for ** a description of the complications associated with using RBU with ** zipvfs databases. @@ -219817,7 +221055,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu); ** ** If the RBU update has been completely applied, mark the RBU database ** as fully applied. Otherwise, assuming no error has occurred, save the -** current state of the RBU update appliation to the RBU database. +** current state of the RBU update application to the RBU database. ** ** If an error has already occurred as part of an sqlite3rbu_step() ** or sqlite3rbu_open() call, or if one occurs within this function, an @@ -224743,7 +225981,7 @@ static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ /* If this is an RBU vacuum operation and this is the target database, ** pretend that it has at least one page. Otherwise, SQLite will not - ** check for the existance of a *-wal file. rbuVfsRead() contains + ** check for the existence of a *-wal file. rbuVfsRead() contains ** similar logic. */ if( rc==SQLITE_OK && *pSize==0 && p->pRbu && rbuIsVacuum(p->pRbu) @@ -226675,8 +227913,8 @@ static int dbpageUpdate( /* "INSERT INTO dbpage($PGNO,NULL)" causes page number $PGNO and ** all subsequent pages to be deleted. */ pTab->iDbTrunc = iDb; - pgno--; - pTab->pgnoTrunc = pgno; + pTab->pgnoTrunc = pgno-1; + pgno = 1; }else{ zErr = "bad page value"; goto update_fail; @@ -227973,7 +229211,7 @@ static int sessionTableInfo( /* ** This function is called to initialize the SessionTable.nCol, azCol[] ** abPK[] and azDflt[] members of SessionTable object pTab. If these -** fields are already initilialized, this function is a no-op. +** fields are already initialized, this function is a no-op. ** ** If an error occurs, an error code is stored in sqlite3_session.rc and ** non-zero returned. Or, if no error occurs but the table has no primary @@ -227992,6 +229230,8 @@ static int sessionInitTable( if( pTab->nCol==0 ){ u8 *abPK; assert( pTab->azCol==0 || pTab->abPK==0 ); + sqlite3_free(pTab->azCol); + pTab->abPK = 0; rc = sessionTableInfo(pSession, db, zDb, pTab->zName, &pTab->nCol, &pTab->nTotalCol, 0, &pTab->azCol, &pTab->azDflt, &pTab->aiIdx, &abPK, @@ -228999,7 +230239,9 @@ SQLITE_API int sqlite3session_diff( SessionTable *pTo; /* Table zTbl */ /* Locate and if necessary initialize the target table object */ + pSession->bAutoAttach++; rc = sessionFindTable(pSession, zTbl, &pTo); + pSession->bAutoAttach--; if( pTo==0 ) goto diff_out; if( sessionInitTable(pSession, pTo, pSession->db, pSession->zDb) ){ rc = pSession->rc; @@ -229010,17 +230252,43 @@ SQLITE_API int sqlite3session_diff( if( rc==SQLITE_OK ){ int bHasPk = 0; int bMismatch = 0; - int nCol; /* Columns in zFrom.zTbl */ + int nCol = 0; /* Columns in zFrom.zTbl */ int bRowid = 0; - u8 *abPK; + u8 *abPK = 0; const char **azCol = 0; - rc = sessionTableInfo(0, db, zFrom, zTbl, - &nCol, 0, 0, &azCol, 0, 0, &abPK, - pSession->bImplicitPK ? &bRowid : 0 - ); + char *zDbExists = 0; + + /* Check that database zFrom is attached. */ + zDbExists = sqlite3_mprintf("SELECT * FROM %Q.sqlite_schema", zFrom); + if( zDbExists==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3_stmt *pDbExists = 0; + rc = sqlite3_prepare_v2(db, zDbExists, -1, &pDbExists, 0); + if( rc==SQLITE_ERROR ){ + rc = SQLITE_OK; + nCol = -1; + } + sqlite3_finalize(pDbExists); + sqlite3_free(zDbExists); + } + + if( rc==SQLITE_OK && nCol==0 ){ + rc = sessionTableInfo(0, db, zFrom, zTbl, + &nCol, 0, 0, &azCol, 0, 0, &abPK, + pSession->bImplicitPK ? &bRowid : 0 + ); + } if( rc==SQLITE_OK ){ if( pTo->nCol!=nCol ){ - bMismatch = 1; + if( nCol<=0 ){ + rc = SQLITE_SCHEMA; + if( pzErrMsg ){ + *pzErrMsg = sqlite3_mprintf("no such table: %s.%s", zFrom, zTbl); + } + }else{ + bMismatch = 1; + } }else{ int i; for(i=0; idb; /* Source database handle */ SessionTable *pTab; /* Used to iterate through attached tables */ - SessionBuffer buf = {0,0,0}; /* Buffer in which to accumlate changeset */ + SessionBuffer buf = {0,0,0}; /* Buffer in which to accumulate changeset */ int rc; /* Return code */ assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0) ); @@ -230149,14 +231417,15 @@ SQLITE_API int sqlite3changeset_start_v2_strm( ** object and the buffer is full, discard some data to free up space. */ static void sessionDiscardData(SessionInput *pIn){ - if( pIn->xInput && pIn->iNext>=sessions_strm_chunk_size ){ - int nMove = pIn->buf.nBuf - pIn->iNext; + if( pIn->xInput && pIn->iCurrent>=sessions_strm_chunk_size ){ + int nMove = pIn->buf.nBuf - pIn->iCurrent; assert( nMove>=0 ); if( nMove>0 ){ - memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove); + memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iCurrent], nMove); } - pIn->buf.nBuf -= pIn->iNext; - pIn->iNext = 0; + pIn->buf.nBuf -= pIn->iCurrent; + pIn->iNext -= pIn->iCurrent; + pIn->iCurrent = 0; pIn->nData = pIn->buf.nBuf; } } @@ -230510,8 +231779,8 @@ static int sessionChangesetNextOne( p->rc = sessionInputBuffer(&p->in, 2); if( p->rc!=SQLITE_OK ) return p->rc; - sessionDiscardData(&p->in); p->in.iCurrent = p->in.iNext; + sessionDiscardData(&p->in); /* If the iterator is already at the end of the changeset, return DONE. */ if( p->in.iNext>=p->in.nData ){ @@ -232870,14 +234139,19 @@ SQLITE_API int sqlite3changegroup_add_change( sqlite3_changegroup *pGrp, sqlite3_changeset_iter *pIter ){ + int rc = SQLITE_OK; + if( pIter->in.iCurrent==pIter->in.iNext || pIter->rc!=SQLITE_OK || pIter->bInvert ){ /* Iterator does not point to any valid entry or is an INVERT iterator. */ - return SQLITE_ERROR; + rc = SQLITE_ERROR; + }else{ + pIter->in.bNoDiscard = 1; + rc = sessionOneChangeToHash(pGrp, pIter, 0); } - return sessionOneChangeToHash(pGrp, pIter, 0); + return rc; } /* @@ -234230,6 +235504,18 @@ typedef sqlite3_uint64 u64; # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) #endif +/* +** Macros needed to provide flexible arrays in a portable way +*/ +#ifndef offsetof +# define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD)) +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEXARRAY +#else +# define FLEXARRAY 1 +#endif + #endif /* Truncate very long tokens to this many bytes. Hard limit is @@ -234302,10 +235588,11 @@ typedef struct Fts5Colset Fts5Colset; */ struct Fts5Colset { int nCol; - int aiCol[1]; + int aiCol[FLEXARRAY]; }; - +/* Size (int bytes) of a complete Fts5Colset object with N columns. */ +#define SZ_FTS5COLSET(N) (sizeof(i64)*((N+2)/2)) /************************************************************************** ** Interface to code in fts5_config.c. fts5_config.c contains contains code @@ -235134,7 +236421,7 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*); ** ** The "lemon" program processes an LALR(1) input grammar file, then uses ** this template to construct a parser. The "lemon" program inserts text -** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the +** at each "%%" line. Also, any "P-a-r-s-e" identifier prefix (without the ** interstitial "-" characters) contained in this template is changed into ** the value of the %name directive from the grammar. Otherwise, the content ** of this template is copied straight through into the generate parser @@ -237288,7 +238575,7 @@ static int fts5Bm25GetData( ** under consideration. ** ** The problem with this is that if (N < 2*nHit), the IDF is - ** negative. Which is undesirable. So the mimimum allowable IDF is + ** negative. Which is undesirable. So the minimum allowable IDF is ** (1e-6) - roughly the same as a term that appears in just over ** half of set of 5,000,000 documents. */ double idf = log( (nRow - nHit + 0.5) / (nHit + 0.5) ); @@ -237751,7 +239038,7 @@ static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){ ** * The 52 upper and lower case ASCII characters, and ** * The 10 integer ASCII characters. ** * The underscore character "_" (0x5F). -** * The unicode "subsitute" character (0x1A). +** * The unicode "substitute" character (0x1A). */ static int sqlite3Fts5IsBareword(char t){ u8 aBareword[128] = { @@ -239069,9 +240356,13 @@ struct Fts5ExprNode { /* Child nodes. For a NOT node, this array always contains 2 entries. For ** AND or OR nodes, it contains 2 or more entries. */ int nChild; /* Number of child nodes */ - Fts5ExprNode *apChild[1]; /* Array of child nodes */ + Fts5ExprNode *apChild[FLEXARRAY]; /* Array of child nodes */ }; +/* Size (in bytes) of an Fts5ExprNode object that holds up to N children */ +#define SZ_FTS5EXPRNODE(N) \ + (offsetof(Fts5ExprNode,apChild) + (N)*sizeof(Fts5ExprNode*)) + #define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING) /* @@ -239102,9 +240393,13 @@ struct Fts5ExprPhrase { Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */ Fts5Buffer poslist; /* Current position list */ int nTerm; /* Number of entries in aTerm[] */ - Fts5ExprTerm aTerm[1]; /* Terms that make up this phrase */ + Fts5ExprTerm aTerm[FLEXARRAY]; /* Terms that make up this phrase */ }; +/* Size (in bytes) of an Fts5ExprPhrase object that holds up to N terms */ +#define SZ_FTS5EXPRPHRASE(N) \ + (offsetof(Fts5ExprPhrase,aTerm) + (N)*sizeof(Fts5ExprTerm)) + /* ** One or more phrases that must appear within a certain token distance of ** each other within each matching document. @@ -239113,9 +240408,12 @@ struct Fts5ExprNearset { int nNear; /* NEAR parameter */ Fts5Colset *pColset; /* Columns to search (NULL -> all columns) */ int nPhrase; /* Number of entries in aPhrase[] array */ - Fts5ExprPhrase *apPhrase[1]; /* Array of phrase pointers */ + Fts5ExprPhrase *apPhrase[FLEXARRAY]; /* Array of phrase pointers */ }; +/* Size (in bytes) of an Fts5ExprNearset object covering up to N phrases */ +#define SZ_FTS5EXPRNEARSET(N) \ + (offsetof(Fts5ExprNearset,apPhrase)+(N)*sizeof(Fts5ExprPhrase*)) /* ** Parse context. @@ -239275,7 +240573,7 @@ static int sqlite3Fts5ExprNew( /* If the LHS of the MATCH expression was a user column, apply the ** implicit column-filter. */ if( sParse.rc==SQLITE_OK && iColnCol ){ - int n = sizeof(Fts5Colset); + int n = SZ_FTS5COLSET(1); Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n); if( pColset ){ pColset->nCol = 1; @@ -240633,7 +241931,7 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( if( pParse->rc==SQLITE_OK ){ if( pNear==0 ){ sqlite3_int64 nByte; - nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); + nByte = SZ_FTS5EXPRNEARSET(SZALLOC+1); pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; @@ -240644,7 +241942,7 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( int nNew = pNear->nPhrase + SZALLOC; sqlite3_int64 nByte; - nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*); + nByte = SZ_FTS5EXPRNEARSET(nNew+1); pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; @@ -240735,12 +242033,12 @@ static int fts5ParseTokenize( int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0); pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase, - sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew + SZ_FTS5EXPRPHRASE(nNew+1) ); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ - if( pPhrase==0 ) memset(pNew, 0, sizeof(Fts5ExprPhrase)); + if( pPhrase==0 ) memset(pNew, 0, SZ_FTS5EXPRPHRASE(1)); pCtx->pPhrase = pPhrase = pNew; pNew->nTerm = nNew - SZALLOC; } @@ -240848,7 +242146,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( if( sCtx.pPhrase==0 ){ /* This happens when parsing a token or quoted phrase that contains ** no token characters at all. (e.g ... MATCH '""'). */ - sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase)); + sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, SZ_FTS5EXPRPHRASE(1)); }else if( sCtx.pPhrase->nTerm ){ sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix; } @@ -240883,19 +242181,18 @@ static int sqlite3Fts5ExprClonePhrase( sizeof(Fts5ExprPhrase*)); } if( rc==SQLITE_OK ){ - pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, - sizeof(Fts5ExprNode)); + pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRNODE(1)); } if( rc==SQLITE_OK ){ pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, - sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); + SZ_FTS5EXPRNEARSET(2)); } if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; if( pColsetOrig ){ sqlite3_int64 nByte; Fts5Colset *pColset; - nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); + nByte = SZ_FTS5COLSET(pColsetOrig->nCol); pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); if( pColset ){ memcpy(pColset, pColsetOrig, (size_t)nByte); @@ -240923,7 +242220,7 @@ static int sqlite3Fts5ExprClonePhrase( }else{ /* This happens when parsing a token or quoted phrase that contains ** no token characters at all. (e.g ... MATCH '""'). */ - sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); + sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRPHRASE(1)); } } @@ -240988,7 +242285,8 @@ static void sqlite3Fts5ParseSetDistance( ); return; } - nNear = nNear * 10 + (p->p[i] - '0'); + if( nNear<214748363 ) nNear = nNear * 10 + (p->p[i] - '0'); + /* ^^^^^^^^^^^^^^^--- Prevent integer overflow */ } }else{ nNear = FTS5_DEFAULT_NEARDIST; @@ -241017,7 +242315,7 @@ static Fts5Colset *fts5ParseColset( assert( pParse->rc==SQLITE_OK ); assert( iCol>=0 && iColpConfig->nCol ); - pNew = sqlite3_realloc64(p, sizeof(Fts5Colset) + sizeof(int)*nCol); + pNew = sqlite3_realloc64(p, SZ_FTS5COLSET(nCol+1)); if( pNew==0 ){ pParse->rc = SQLITE_NOMEM; }else{ @@ -241052,7 +242350,7 @@ static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p int nCol = pParse->pConfig->nCol; pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, - sizeof(Fts5Colset) + sizeof(int)*nCol + SZ_FTS5COLSET(nCol+1) ); if( pRet ){ int i; @@ -241113,7 +242411,7 @@ static Fts5Colset *sqlite3Fts5ParseColset( static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){ Fts5Colset *pRet; if( pOrig ){ - sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int); + sqlite3_int64 nByte = SZ_FTS5COLSET(pOrig->nCol); pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte); if( pRet ){ memcpy(pRet, pOrig, (size_t)nByte); @@ -241281,7 +242579,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd( assert( pNear->nPhrase==1 ); assert( pParse->bPhraseToAnd ); - nByte = sizeof(Fts5ExprNode) + nTerm*sizeof(Fts5ExprNode*); + nByte = SZ_FTS5EXPRNODE(nTerm+1); pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); if( pRet ){ pRet->eType = FTS5_AND; @@ -241291,7 +242589,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd( pParse->nPhrase--; for(ii=0; iirc, sizeof(Fts5ExprPhrase) + &pParse->rc, SZ_FTS5EXPRPHRASE(1) ); if( pPhrase ){ if( parseGrowPhraseArray(pParse) ){ @@ -241360,7 +242658,7 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( if( pRight->eType==eType ) nChild += pRight->nChild-1; } - nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1); + nByte = SZ_FTS5EXPRNODE(nChild); pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); if( pRet ){ @@ -242235,7 +243533,7 @@ static int sqlite3Fts5ExprInstToken( } /* -** Clear the token mappings for all Fts5IndexIter objects mannaged by +** Clear the token mappings for all Fts5IndexIter objects managed by ** the expression passed as the only argument. */ static void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){ @@ -242270,7 +243568,7 @@ typedef struct Fts5HashEntry Fts5HashEntry; /* ** This file contains the implementation of an in-memory hash table used -** to accumuluate "term -> doclist" content before it is flused to a level-0 +** to accumulate "term -> doclist" content before it is flushed to a level-0 ** segment. */ @@ -242327,7 +243625,7 @@ struct Fts5HashEntry { }; /* -** Eqivalent to: +** Equivalent to: ** ** char *fts5EntryKey(Fts5HashEntry *pEntry){ return zKey; } */ @@ -243263,9 +244561,13 @@ struct Fts5Structure { u64 nOriginCntr; /* Origin value for next top-level segment */ int nSegment; /* Total segments in this structure */ int nLevel; /* Number of levels in this index */ - Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */ + Fts5StructureLevel aLevel[FLEXARRAY]; /* Array of nLevel level objects */ }; +/* Size (in bytes) of an Fts5Structure object holding up to N levels */ +#define SZ_FTS5STRUCTURE(N) \ + (offsetof(Fts5Structure,aLevel) + (N)*sizeof(Fts5StructureLevel)) + /* ** An object of type Fts5SegWriter is used to write to segments. */ @@ -243395,11 +244697,15 @@ struct Fts5SegIter { ** Array of tombstone pages. Reference counted. */ struct Fts5TombstoneArray { - int nRef; /* Number of pointers to this object */ + int nRef; /* Number of pointers to this object */ int nTombstone; - Fts5Data *apTombstone[1]; /* Array of tombstone pages */ + Fts5Data *apTombstone[FLEXARRAY]; /* Array of tombstone pages */ }; +/* Size (in bytes) of an Fts5TombstoneArray holding up to N tombstones */ +#define SZ_FTS5TOMBSTONEARRAY(N) \ + (offsetof(Fts5TombstoneArray,apTombstone)+(N)*sizeof(Fts5Data*)) + /* ** Argument is a pointer to an Fts5Data structure that contains a ** leaf page. @@ -243468,9 +244774,12 @@ struct Fts5Iter { i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */ Fts5CResult *aFirst; /* Current merge state (see above) */ - Fts5SegIter aSeg[1]; /* Array of segment iterators */ + Fts5SegIter aSeg[FLEXARRAY]; /* Array of segment iterators */ }; +/* Size (in bytes) of an Fts5Iter object holding up to N segment iterators */ +#define SZ_FTS5ITER(N) (offsetof(Fts5Iter,aSeg)+(N)*sizeof(Fts5SegIter)) + /* ** An instance of the following type is used to iterate through the contents ** of a doclist-index record. @@ -243497,9 +244806,13 @@ struct Fts5DlidxLvl { struct Fts5DlidxIter { int nLvl; int iSegid; - Fts5DlidxLvl aLvl[1]; + Fts5DlidxLvl aLvl[FLEXARRAY]; }; +/* Size (in bytes) of an Fts5DlidxIter object with up to N levels */ +#define SZ_FTS5DLIDXITER(N) \ + (offsetof(Fts5DlidxIter,aLvl)+(N)*sizeof(Fts5DlidxLvl)) + static void fts5PutU16(u8 *aOut, u16 iVal){ aOut[0] = (iVal>>8); aOut[1] = (iVal&0xFF); @@ -243867,7 +245180,7 @@ static int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){ static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){ Fts5Structure *p = *pp; if( *pRc==SQLITE_OK && p->nRef>1 ){ - i64 nByte = sizeof(Fts5Structure)+(p->nLevel-1)*sizeof(Fts5StructureLevel); + i64 nByte = SZ_FTS5STRUCTURE(p->nLevel); Fts5Structure *pNew; pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte); if( pNew ){ @@ -243941,10 +245254,7 @@ static int fts5StructureDecode( ){ return FTS5_CORRUPT; } - nByte = ( - sizeof(Fts5Structure) + /* Main structure */ - sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */ - ); + nByte = SZ_FTS5STRUCTURE(nLevel); pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte); if( pRet ){ @@ -244024,10 +245334,7 @@ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){ if( *pRc==SQLITE_OK ){ Fts5Structure *pStruct = *ppStruct; int nLevel = pStruct->nLevel; - sqlite3_int64 nByte = ( - sizeof(Fts5Structure) + /* Main structure */ - sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */ - ); + sqlite3_int64 nByte = SZ_FTS5STRUCTURE(nLevel+2); pStruct = sqlite3_realloc64(pStruct, nByte); if( pStruct ){ @@ -244566,7 +245873,7 @@ static Fts5DlidxIter *fts5DlidxIterInit( int bDone = 0; for(i=0; p->rc==SQLITE_OK && bDone==0; i++){ - sqlite3_int64 nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl); + sqlite3_int64 nByte = SZ_FTS5DLIDXITER(i+1); Fts5DlidxIter *pNew; pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte); @@ -244784,7 +246091,7 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){ static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){ const int nTomb = pIter->pSeg->nPgTombstone; if( nTomb>0 ){ - int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray); + int nByte = SZ_FTS5TOMBSTONEARRAY(nTomb+1); Fts5TombstoneArray *pNew; pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte); if( pNew ){ @@ -246245,8 +247552,7 @@ static Fts5Iter *fts5MultiIterAlloc( for(nSlot=2; nSlotaSeg[] */ + SZ_FTS5ITER(nSlot) + /* pNew + pNew->aSeg[] */ sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */ ); if( pNew ){ @@ -248047,7 +249353,7 @@ static void fts5DoSecureDelete( int iDelKeyOff = 0; /* Offset of deleted key, if any */ nIdx = nPg-iPgIdx; - aIdx = sqlite3Fts5MallocZero(&p->rc, nIdx+16); + aIdx = sqlite3Fts5MallocZero(&p->rc, ((i64)nIdx)+16); if( p->rc ) return; memcpy(aIdx, &aPg[iPgIdx], nIdx); @@ -248612,7 +249918,7 @@ static Fts5Structure *fts5IndexOptimizeStruct( Fts5Structure *pStruct ){ Fts5Structure *pNew = 0; - sqlite3_int64 nByte = sizeof(Fts5Structure); + sqlite3_int64 nByte = SZ_FTS5STRUCTURE(1); int nSeg = pStruct->nSegment; int i; @@ -248641,7 +249947,8 @@ static Fts5Structure *fts5IndexOptimizeStruct( assert( pStruct->aLevel[i].nMerge<=nThis ); } - nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel); + nByte += (((i64)pStruct->nLevel)+1) * sizeof(Fts5StructureLevel); + assert( nByte==SZ_FTS5STRUCTURE(pStruct->nLevel+2) ); pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte); if( pNew ){ @@ -249218,9 +250525,13 @@ struct Fts5TokenDataIter { int nIterAlloc; Fts5PoslistReader *aPoslistReader; int *aPoslistToIter; - Fts5Iter *apIter[1]; + Fts5Iter *apIter[FLEXARRAY]; }; +/* Size in bytes of an Fts5TokenDataIter object holding up to N iterators */ +#define SZ_FTS5TOKENDATAITER(N) \ + (offsetof(Fts5TokenDataIter,apIter) + (N)*sizeof(Fts5Iter)) + /* ** The two input arrays - a1[] and a2[] - are in sorted order. This function ** merges the two arrays together and writes the result to output array @@ -249292,7 +250603,7 @@ static void fts5TokendataIterAppendMap( /* ** Sort the contents of the pT->aMap[] array. ** -** The sorting algorithm requries a malloc(). If this fails, an error code +** The sorting algorithm requires a malloc(). If this fails, an error code ** is left in Fts5Index.rc before returning. */ static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){ @@ -249483,7 +250794,7 @@ static void fts5SetupPrefixIter( && p->pConfig->bPrefixInsttoken ){ s.pTokendata = &s2; - s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, sizeof(*s2.pT)); + s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, SZ_FTS5TOKENDATAITER(1)); } if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ @@ -249529,7 +250840,8 @@ static void fts5SetupPrefixIter( } } - pData = fts5IdxMalloc(p, sizeof(*pData)+s.doclist.n+FTS5_DATA_ZERO_PADDING); + pData = fts5IdxMalloc(p, sizeof(*pData) + + ((i64)s.doclist.n)+FTS5_DATA_ZERO_PADDING); assert( pData!=0 || p->rc!=SQLITE_OK ); if( pData ){ pData->p = (u8*)&pData[1]; @@ -249610,15 +250922,17 @@ static int sqlite3Fts5IndexRollback(Fts5Index *p){ ** and the initial version of the "averages" record (a zero-byte blob). */ static int sqlite3Fts5IndexReinit(Fts5Index *p){ - Fts5Structure s; + Fts5Structure *pTmp; + u8 tmpSpace[SZ_FTS5STRUCTURE(1)]; fts5StructureInvalidate(p); fts5IndexDiscardData(p); - memset(&s, 0, sizeof(Fts5Structure)); + pTmp = (Fts5Structure*)tmpSpace; + memset(pTmp, 0, SZ_FTS5STRUCTURE(1)); if( p->pConfig->bContentlessDelete ){ - s.nOriginCntr = 1; + pTmp->nOriginCntr = 1; } fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0); - fts5StructureWrite(p, &s); + fts5StructureWrite(p, pTmp); return fts5IndexReturn(p); } @@ -249826,7 +251140,7 @@ static Fts5TokenDataIter *fts5AppendTokendataIter( if( p->rc==SQLITE_OK ){ if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){ int nAlloc = pIn ? pIn->nIterAlloc*2 : 16; - int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter); + int nByte = SZ_FTS5TOKENDATAITER(nAlloc+1); Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte); if( pNew==0 ){ @@ -250342,7 +251656,8 @@ static int fts5SetupPrefixIterTokendata( fts5BufferGrow(&p->rc, &token, nToken+1); assert( token.p!=0 || p->rc!=SQLITE_OK ); - ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*ctx.pT)); + ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, + SZ_FTS5TOKENDATAITER(1)); if( p->rc==SQLITE_OK ){ @@ -250473,7 +251788,8 @@ static int sqlite3Fts5IndexIterWriteTokendata( if( pIter->nSeg>0 ){ /* This is a prefix term iterator. */ if( pT==0 ){ - pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*pT)); + pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, + SZ_FTS5TOKENDATAITER(1)); pIter->pTokenDataIter = pT; } if( pT ){ @@ -251507,7 +252823,7 @@ static void fts5DecodeRowid( #if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ - int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid compenents */ + int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid components */ fts5DecodeRowid(iKey, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno); if( iSegid==0 ){ @@ -251753,7 +253069,7 @@ static void fts5DecodeFunction( ** buffer overreads even if the record is corrupt. */ n = sqlite3_value_bytes(apVal[1]); aBlob = sqlite3_value_blob(apVal[1]); - nSpace = n + FTS5_DATA_ZERO_PADDING; + nSpace = ((i64)n) + FTS5_DATA_ZERO_PADDING; a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace); if( a==0 ) goto decode_out; if( n>0 ) memcpy(a, aBlob, n); @@ -252468,9 +253784,11 @@ struct Fts5Sorter { i64 iRowid; /* Current rowid */ const u8 *aPoslist; /* Position lists for current row */ int nIdx; /* Number of entries in aIdx[] */ - int aIdx[1]; /* Offsets into aPoslist for current row */ + int aIdx[FLEXARRAY]; /* Offsets into aPoslist for current row */ }; +/* Size (int bytes) of an Fts5Sorter object with N indexes */ +#define SZ_FTS5SORTER(N) (offsetof(Fts5Sorter,nIdx)+((N+2)/2)*sizeof(i64)) /* ** Virtual-table cursor object. @@ -253348,7 +254666,7 @@ static int fts5CursorFirstSorted( const char *zRankArgs = pCsr->zRankArgs; nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); - nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); + nByte = SZ_FTS5SORTER(nPhrase); pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte); if( pSorter==0 ) return SQLITE_NOMEM; memset(pSorter, 0, (size_t)nByte); @@ -255874,7 +257192,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f10e70", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2025-05-29 14:26:00 dfc790f998f450d9c35e3ba1c8c89c17466cb559f87b0239e4aab9d34e28f742", -1, SQLITE_TRANSIENT); } /* @@ -256099,8 +257417,8 @@ static int fts5Init(sqlite3 *db){ ** its entry point to enable the matchinfo() demo. */ #ifdef SQLITE_FTS5_ENABLE_TEST_MI if( rc==SQLITE_OK ){ - extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*); - rc = sqlite3Fts5TestRegisterMatchinfo(db); + extern int sqlite3Fts5TestRegisterMatchinfoAPI(fts5_api*); + rc = sqlite3Fts5TestRegisterMatchinfoAPI(&pGlobal->api); } #endif @@ -259938,7 +261256,6 @@ static void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ aAscii[0] = 0; /* 0x00 is never a token character */ } - /* ** 2015 May 30 ** @@ -260479,12 +261796,12 @@ static int fts5VocabInitVtab( *pzErr = sqlite3_mprintf("wrong number of vtable arguments"); rc = SQLITE_ERROR; }else{ - int nByte; /* Bytes of space to allocate */ + i64 nByte; /* Bytes of space to allocate */ const char *zDb = bDb ? argv[3] : argv[1]; const char *zTab = bDb ? argv[4] : argv[3]; const char *zType = bDb ? argv[5] : argv[4]; - int nDb = (int)strlen(zDb)+1; - int nTab = (int)strlen(zTab)+1; + i64 nDb = strlen(zDb)+1; + i64 nTab = strlen(zTab)+1; int eType = 0; rc = fts5VocabTableType(zType, pzErr, &eType); diff --git a/deps/sqlite/sqlite3.h b/deps/sqlite/sqlite3.h index 082a9f9dc44e93..f61a1485754531 100644 --- a/deps/sqlite/sqlite3.h +++ b/deps/sqlite/sqlite3.h @@ -133,7 +133,7 @@ extern "C" { ** ** Since [version 3.6.18] ([dateof:3.6.18]), ** SQLite source code has been stored in the -** Fossil configuration management +** Fossil configuration management ** system. ^The SQLITE_SOURCE_ID macro evaluates to ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID @@ -146,9 +146,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.49.1" -#define SQLITE_VERSION_NUMBER 3049001 -#define SQLITE_SOURCE_ID "2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f10e70" +#define SQLITE_VERSION "3.50.0" +#define SQLITE_VERSION_NUMBER 3050000 +#define SQLITE_SOURCE_ID "2025-05-29 14:26:00 dfc790f998f450d9c35e3ba1c8c89c17466cb559f87b0239e4aab9d34e28f742" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -1163,6 +1163,12 @@ struct sqlite3_io_methods { ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** +**
  • [[SQLITE_FCNTL_BLOCK_ON_CONNECT]] +** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the +** VFS to block when taking a SHARED lock to connect to a wal mode database. +** This is used to implement the functionality associated with +** SQLITE_SETLK_BLOCK_ON_CONNECT. +** **
  • [[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. @@ -1259,6 +1265,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 #define SQLITE_FCNTL_NULL_IO 43 +#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -1989,13 +1996,16 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_CONFIG_LOOKASIDE]]
    SQLITE_CONFIG_LOOKASIDE
    **
    ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine -** the default size of lookaside memory on each [database connection]. +** the default size of [lookaside memory] on each [database connection]. ** The first argument is the -** size of each lookaside buffer slot and the second is the number of -** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE -** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] -** option to [sqlite3_db_config()] can be used to change the lookaside -** configuration on individual connections.)^
    +** size of each lookaside buffer slot ("sz") and the second is the number of +** slots allocated to each database connection ("cnt").)^ +** ^(SQLITE_CONFIG_LOOKASIDE sets the default lookaside size. +** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can +** be used to change the lookaside configuration on individual connections.)^ +** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the +** default lookaside configuration at compile-time. +**
  • ** ** [[SQLITE_CONFIG_PCACHE2]]
    SQLITE_CONFIG_PCACHE2
    **
    ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is @@ -2232,31 +2242,50 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    **
    The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the -** configuration of the lookaside memory allocator within a database +** configuration of the [lookaside memory allocator] within a database ** connection. ** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are not ** in the [DBCONFIG arguments|usual format]. ** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two, ** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE ** should have a total of five parameters. -** ^The first argument (the third parameter to [sqlite3_db_config()] is a +**
      +**
    1. The first argument ("buf") is a ** pointer to a memory buffer to use for lookaside memory. -** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb -** may be NULL in which case SQLite will allocate the -** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the -** size of each lookaside buffer slot. ^The third argument is the number of -** slots. The size of the buffer in the first argument must be greater than -** or equal to the product of the second and third arguments. The buffer -** must be aligned to an 8-byte boundary. ^If the second argument to -** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally -** rounded down to the next smaller multiple of 8. ^(The lookaside memory +** The first argument may be NULL in which case SQLite will allocate the +** lookaside buffer itself using [sqlite3_malloc()]. +**

    2. The second argument ("sz") is the +** size of each lookaside buffer slot. Lookaside is disabled if "sz" +** is less than 8. The "sz" argument should be a multiple of 8 less than +** 65536. If "sz" does not meet this constraint, it is reduced in size until +** it does. +**

    3. The third argument ("cnt") is the number of slots. Lookaside is disabled +** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so +** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt" +** parameter is usually chosen so that the product of "sz" and "cnt" is less +** than 1,000,000. +**

    +**

    If the "buf" argument is not NULL, then it must +** point to a memory buffer with a size that is greater than +** or equal to the product of "sz" and "cnt". +** The buffer must be aligned to an 8-byte boundary. +** The lookaside memory ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words -** when the "current value" returned by -** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero. +** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns -** [SQLITE_BUSY].)^

    +** [SQLITE_BUSY]. +** If the "buf" argument is NULL and an attempt +** to allocate memory based on "sz" and "cnt" fails, then +** lookaside is silently disabled. +**

    +** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the +** default lookaside configuration at initialization. The +** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside +** configuration at compile-time. Typical values for lookaside are 1200 for +** "sz" and 40 to 100 for "cnt". +** ** ** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **

    SQLITE_DBCONFIG_ENABLE_FKEY
    @@ -2993,6 +3022,44 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); +/* +** CAPI3REF: Set the Setlk Timeout +** METHOD: sqlite3 +** +** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If +** the VFS supports blocking locks, it sets the timeout in ms used by +** eligible locks taken on wal mode databases by the specified database +** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does +** not support blocking locks, this function is a no-op. +** +** Passing 0 to this function disables blocking locks altogether. Passing +** -1 to this function requests that the VFS blocks for a long time - +** indefinitely if possible. The results of passing any other negative value +** are undefined. +** +** Internally, each SQLite database handle store two timeout values - the +** busy-timeout (used for rollback mode databases, or if the VFS does not +** support blocking locks) and the setlk-timeout (used for blocking locks +** on wal-mode databases). The sqlite3_busy_timeout() method sets both +** values, this function sets only the setlk-timeout value. Therefore, +** to configure separate busy-timeout and setlk-timeout values for a single +** database handle, call sqlite3_busy_timeout() followed by this function. +** +** Whenever the number of connections to a wal mode database falls from +** 1 to 0, the last connection takes an exclusive lock on the database, +** then checkpoints and deletes the wal file. While it is doing this, any +** new connection that tries to read from the database fails with an +** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is +** passed to this API, the new connection blocks until the exclusive lock +** has been released. +*/ +SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags); + +/* +** CAPI3REF: Flags for sqlite3_setlk_timeout() +*/ +#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01 + /* ** CAPI3REF: Convenience Routines For Running Queries ** METHOD: sqlite3 @@ -5108,7 +5175,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from -** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], +** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1]), ** sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility @@ -7004,6 +7071,8 @@ SQLITE_API int sqlite3_autovacuum_pages( ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. +** ^The update hook is disabled by invoking sqlite3_update_hook() +** with a NULL pointer as the second parameter. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], @@ -11486,9 +11555,10 @@ SQLITE_API void sqlite3session_table_filter( ** is inserted while a session object is enabled, then later deleted while ** the same session object is disabled, no INSERT record will appear in the ** changeset, even though the delete took place while the session was disabled. -** Or, if one field of a row is updated while a session is disabled, and -** another field of the same row is updated while the session is enabled, the -** resulting changeset will contain an UPDATE change that updates both fields. +** Or, if one field of a row is updated while a session is enabled, and +** then another field of the same row is updated while the session is disabled, +** the resulting changeset will contain an UPDATE change that updates both +** fields. */ SQLITE_API int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ @@ -11560,8 +11630,9 @@ SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession ** database zFrom the contents of the two compatible tables would be ** identical. ** -** It an error if database zFrom does not exist or does not contain the -** required compatible table. +** Unless the call to this function is a no-op as described above, it is an +** error if database zFrom does not exist or does not contain the required +** compatible table. ** ** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite ** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg @@ -11696,7 +11767,7 @@ SQLITE_API int sqlite3changeset_start_v2( ** The following flags may passed via the 4th parameter to ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: ** -**
    SQLITE_CHANGESETAPPLY_INVERT
    +**
    SQLITE_CHANGESETSTART_INVERT
    ** Invert the changeset while iterating through it. This is equivalent to ** inverting a changeset using sqlite3changeset_invert() before applying it. ** It is an error to specify this flag with a patchset. @@ -12011,19 +12082,6 @@ SQLITE_API int sqlite3changeset_concat( void **ppOut /* OUT: Buffer containing output changeset */ ); - -/* -** CAPI3REF: Upgrade the Schema of a Changeset/Patchset -*/ -SQLITE_API int sqlite3changeset_upgrade( - sqlite3 *db, - const char *zDb, - int nIn, const void *pIn, /* Input changeset */ - int *pnOut, void **ppOut /* OUT: Inverse of input */ -); - - - /* ** CAPI3REF: Changegroup Handle ** diff --git a/deps/sqlite/sqlite3ext.h b/deps/sqlite/sqlite3ext.h index ae0949baf75ae8..cf775dfbde0fdf 100644 --- a/deps/sqlite/sqlite3ext.h +++ b/deps/sqlite/sqlite3ext.h @@ -366,6 +366,8 @@ struct sqlite3_api_routines { /* Version 3.44.0 and later */ void *(*get_clientdata)(sqlite3*,const char*); int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); + /* Version 3.50.0 and later */ + int (*setlk_timeout)(sqlite3*,int,int); }; /* @@ -699,6 +701,8 @@ typedef int (*sqlite3_loadext_entry)( /* Version 3.44.0 and later */ #define sqlite3_get_clientdata sqlite3_api->get_clientdata #define sqlite3_set_clientdata sqlite3_api->set_clientdata +/* Version 3.50.0 and later */ +#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/deps/undici/src/.gitignore b/deps/undici/src/.gitignore index 7cba7df889f509..8a85634911ad27 100644 --- a/deps/undici/src/.gitignore +++ b/deps/undici/src/.gitignore @@ -63,6 +63,7 @@ typings/ # lock files package-lock.json yarn.lock +pnpm-lock.yaml # IDE files .idea diff --git a/deps/undici/src/README.md b/deps/undici/src/README.md index 8fa1c94d697e04..23f253c45e3b9a 100644 --- a/deps/undici/src/README.md +++ b/deps/undici/src/README.md @@ -261,12 +261,22 @@ const readableWebStream = response.body const readableNodeStream = Readable.fromWeb(readableWebStream) ``` -#### Specification Compliance +## Specification Compliance -This section documents parts of the [Fetch Standard](https://fetch.spec.whatwg.org) that Undici does +This section documents parts of the [HTTP/1.1](https://www.rfc-editor.org/rfc/rfc9110.html) and [Fetch Standard](https://fetch.spec.whatwg.org) that Undici does not support or does not fully implement. -##### Garbage Collection +#### CORS + +Unlike browsers, Undici does not implement CORS (Cross-Origin Resource Sharing) checks by default. This means: + +- No preflight requests are automatically sent for cross-origin requests +- No validation of `Access-Control-Allow-Origin` headers is performed +- Requests to any origin are allowed regardless of the source + +This behavior is intentional for server-side environments where CORS restrictions are typically unnecessary. If your application requires CORS-like protections, you will need to implement these checks manually. + +#### Garbage Collection * https://fetch.spec.whatwg.org/#garbage-collection @@ -307,7 +317,7 @@ const headers = await fetch(url, { method: 'HEAD' }) .then(res => res.headers) ``` -##### Forbidden and Safelisted Header Names +#### Forbidden and Safelisted Header Names * https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name * https://fetch.spec.whatwg.org/#forbidden-header-name @@ -316,7 +326,7 @@ const headers = await fetch(url, { method: 'HEAD' }) The [Fetch Standard](https://fetch.spec.whatwg.org) requires implementations to exclude certain headers from requests and responses. In browser environments, some headers are forbidden so the user agent remains in full control over them. In Undici, these constraints are removed to give more control to the user. -### `undici.upgrade([url, options]): Promise` +#### `undici.upgrade([url, options]): Promise` Upgrade to a different protocol. See [MDN - HTTP - Protocol upgrade mechanism](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism) for more details. @@ -378,12 +388,7 @@ Returns: `URL` * **protocol** `string` (optional) * **search** `string` (optional) -## Specification Compliance - -This section documents parts of the HTTP/1.1 specification that Undici does -not support or does not fully implement. - -### Expect +#### Expect Undici does not support the `Expect` request header field. The request body is always immediately sent and the `100 Continue` response will be @@ -391,7 +396,7 @@ ignored. Refs: https://tools.ietf.org/html/rfc7231#section-5.1.1 -### Pipelining +#### Pipelining Undici will only use pipelining if configured with a `pipelining` factor greater than `1`. Also it is important to pass `blocking: false` to the @@ -412,7 +417,7 @@ aborted. * Refs: https://tools.ietf.org/html/rfc2616#section-8.1.2.2 * Refs: https://tools.ietf.org/html/rfc7230#section-6.3.2 -### Manual Redirect +#### Manual Redirect Since it is not possible to manually follow an HTTP redirect on the server-side, Undici returns the actual response instead of an `opaqueredirect` filtered one @@ -421,9 +426,9 @@ implementations in Deno and Cloudflare Workers. Refs: https://fetch.spec.whatwg.org/#atomic-http-redirect-handling -## Workarounds +### Workarounds -### Network address family autoselection. +#### Network address family autoselection. If you experience problem when connecting to a remote server that is resolved by your DNS servers to a IPv6 (AAAA record) first, there are chances that your local router or ISP might have problem connecting to IPv6 networks. In that case diff --git a/deps/undici/src/docs/docs/api/Agent.md b/deps/undici/src/docs/docs/api/Agent.md index 5141ce3d3a762f..2a8e30bac1461c 100644 --- a/deps/undici/src/docs/docs/api/Agent.md +++ b/deps/undici/src/docs/docs/api/Agent.md @@ -75,3 +75,9 @@ See [`Dispatcher.stream(options, factory[, callback])`](/docs/docs/api/Dispatche ### `Agent.upgrade(options[, callback])` See [`Dispatcher.upgrade(options[, callback])`](/docs/docs/api/Dispatcher.md#dispatcherupgradeoptions-callback). + +### `Agent.stats()` + +Returns an object of stats by origin in the format of `Record` + +See [`PoolStats`](/docs/docs/api/PoolStats.md) and [`ClientStats`](/docs/docs/api/ClientStats.md). diff --git a/deps/undici/src/docs/docs/api/CacheStore.md b/deps/undici/src/docs/docs/api/CacheStore.md index 7cd19e08786730..0f3b3eebc7f06f 100644 --- a/deps/undici/src/docs/docs/api/CacheStore.md +++ b/deps/undici/src/docs/docs/api/CacheStore.md @@ -13,8 +13,28 @@ The `MemoryCacheStore` stores the responses in-memory. **Options** +- `maxSize` - The maximum total size in bytes of all stored responses. Default `Infinity`. - `maxCount` - The maximum amount of responses to store. Default `Infinity`. -- `maxEntrySize` - The maximum size in bytes that a response's body can be. If a response's body is greater than or equal to this, the response will not be cached. +- `maxEntrySize` - The maximum size in bytes that a response's body can be. If a response's body is greater than or equal to this, the response will not be cached. Default `Infinity`. + +### Getters + +#### `MemoryCacheStore.size` + +Returns the current total size in bytes of all stored responses. + +### Methods + +#### `MemoryCacheStore.isFull()` + +Returns a boolean indicating whether the cache has reached its maximum size or count. + +### Events + +#### `'maxSizeExceeded'` + +Emitted when the cache exceeds its maximum size or count limits. The event payload contains `size`, `maxSize`, `count`, and `maxCount` properties. + ### `SqliteCacheStore` @@ -26,7 +46,7 @@ The `SqliteCacheStore` is only exposed if the `node:sqlite` api is present. - `location` - The location of the SQLite database to use. Default `:memory:`. - `maxCount` - The maximum number of entries to store in the database. Default `Infinity`. -- `maxEntrySize` - The maximum size in bytes that a resposne's body can be. If a response's body is greater than or equal to this, the response will not be cached. Default `Infinity`. +- `maxEntrySize` - The maximum size in bytes that a response's body can be. If a response's body is greater than or equal to this, the response will not be cached. Default `Infinity`. ## Defining a Custom Cache Store diff --git a/deps/undici/src/docs/docs/api/ClientStats.md b/deps/undici/src/docs/docs/api/ClientStats.md new file mode 100644 index 00000000000000..fa899d482c855b --- /dev/null +++ b/deps/undici/src/docs/docs/api/ClientStats.md @@ -0,0 +1,27 @@ +# Class: ClientStats + +Stats for a [Client](/docs/docs/api/Client.md). + +## `new ClientStats(client)` + +Arguments: + +* **client** `Client` - Client from which to return stats. + +## Instance Properties + +### `ClientStats.connected` + +Boolean if socket as open connection by this client. + +### `ClientStats.pending` + +Number of pending requests of this client. + +### `ClientStats.running` + +Number of currently active requests across this client. + +### `ClientStats.size` + +Number of active, pending, or queued requests of this clients. diff --git a/deps/undici/src/docs/docs/api/DiagnosticsChannel.md b/deps/undici/src/docs/docs/api/DiagnosticsChannel.md index a3635cbc05e5c5..4038e0e7801143 100644 --- a/deps/undici/src/docs/docs/api/DiagnosticsChannel.md +++ b/deps/undici/src/docs/docs/api/DiagnosticsChannel.md @@ -19,7 +19,7 @@ diagnosticsChannel.channel('undici:request:create').subscribe(({ request }) => { console.log('completed', request.completed) console.log('method', request.method) console.log('path', request.path) - console.log('headers') // array of strings, e.g: ['foo', 'bar'] + console.log('headers', request.headers) // array of strings, e.g: ['foo', 'bar'] request.addHeader('hello', 'world') console.log('headers', request.headers) // e.g. ['foo', 'bar', 'hello', 'world'] }) diff --git a/deps/undici/src/docs/docs/api/MockAgent.md b/deps/undici/src/docs/docs/api/MockAgent.md index e61c20803709b7..b4ce8106bb0ef4 100644 --- a/deps/undici/src/docs/docs/api/MockAgent.md +++ b/deps/undici/src/docs/docs/api/MockAgent.md @@ -20,6 +20,8 @@ Extends: [`AgentOptions`](/docs/docs/api/Agent.md#parameter-agentoptions) * **ignoreTrailingSlash** `boolean` (optional) - Default: `false` - set the default value for `ignoreTrailingSlash` for interceptors. +* **acceptNonStandardSearchParameters** `boolean` (optional) - Default: `false` - set to `true` if the matcher should also accept non standard search parameters such as multi-value items specified with `[]` (e.g. `param[]=1¶m[]=2¶m[]=3`) and multi-value items which values are comma separated (e.g. `param=1,2,3`). + ### Example - Basic MockAgent instantiation This will instantiate the MockAgent. It will not do anything until registered as the agent to use with requests and mock interceptions are added. diff --git a/deps/undici/src/docs/docs/api/Pool.md b/deps/undici/src/docs/docs/api/Pool.md index 9c4328240af292..ee0a0d3fe81aca 100644 --- a/deps/undici/src/docs/docs/api/Pool.md +++ b/deps/undici/src/docs/docs/api/Pool.md @@ -19,6 +19,7 @@ Extends: [`ClientOptions`](/docs/docs/api/Client.md#parameter-clientoptions) * **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Client(origin, opts)` * **connections** `number | null` (optional) - Default: `null` - The number of `Client` instances to create. When set to `null`, the `Pool` instance will create an unlimited amount of `Client` instances. +* **clientTtl** `number | null` (optional) - Default: `null` - The amount of time before a `Client` instance is removed from the `Pool` and closed. When set to `null`, `Client` instances will not be removed or closed based on age. ## Instance Properties diff --git a/deps/undici/src/docs/docs/api/ProxyAgent.md b/deps/undici/src/docs/docs/api/ProxyAgent.md index 932716ae7957b9..e0581a4de5164c 100644 --- a/deps/undici/src/docs/docs/api/ProxyAgent.md +++ b/deps/undici/src/docs/docs/api/ProxyAgent.md @@ -25,6 +25,7 @@ For detailed information on the parsing process and potential validation errors, * **clientFactory** `(origin: URL, opts: Object) => Dispatcher` (optional) - Default: `(origin, opts) => new Pool(origin, opts)` * **requestTls** `BuildOptions` (optional) - Options object passed when creating the underlying socket via the connector builder for the request. It extends from [`Client#ConnectOptions`](/docs/docs/api/Client.md#parameter-connectoptions). * **proxyTls** `BuildOptions` (optional) - Options object passed when creating the underlying socket via the connector builder for the proxy server. It extends from [`Client#ConnectOptions`](/docs/docs/api/Client.md#parameter-connectoptions). +* **proxyTunnel** `boolean` (optional) - By default, ProxyAgent will request that the Proxy facilitate a tunnel between the endpoint and the agent. Setting `proxyTunnel` to false avoids issuing a CONNECT extension, and includes the endpoint domain and path in each request. Examples: diff --git a/deps/undici/src/lib/cache/memory-cache-store.js b/deps/undici/src/lib/cache/memory-cache-store.js index 6fa7356b3660e8..2fb3dfabd19eb8 100644 --- a/deps/undici/src/lib/cache/memory-cache-store.js +++ b/deps/undici/src/lib/cache/memory-cache-store.js @@ -1,6 +1,7 @@ 'use strict' const { Writable } = require('node:stream') +const { EventEmitter } = require('node:events') const { assertCacheKey, assertCacheValue } = require('../util/cache.js') /** @@ -12,8 +13,9 @@ const { assertCacheKey, assertCacheValue } = require('../util/cache.js') /** * @implements {CacheStore} + * @extends {EventEmitter} */ -class MemoryCacheStore { +class MemoryCacheStore extends EventEmitter { #maxCount = Infinity #maxSize = Infinity #maxEntrySize = Infinity @@ -21,11 +23,13 @@ class MemoryCacheStore { #size = 0 #count = 0 #entries = new Map() + #hasEmittedMaxSizeEvent = false /** * @param {import('../../types/cache-interceptor.d.ts').default.MemoryCacheStoreOpts | undefined} [opts] */ constructor (opts) { + super() if (opts) { if (typeof opts !== 'object') { throw new TypeError('MemoryCacheStore options must be an object') @@ -66,6 +70,22 @@ class MemoryCacheStore { } } + /** + * Get the current size of the cache in bytes + * @returns {number} The current size of the cache in bytes + */ + get size () { + return this.#size + } + + /** + * Check if the cache is full (either max size or max count reached) + * @returns {boolean} True if the cache is full, false otherwise + */ + isFull () { + return this.#size >= this.#maxSize || this.#count >= this.#maxCount + } + /** * @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} req * @returns {import('../../types/cache-interceptor.d.ts').default.GetResult | undefined} @@ -76,17 +96,9 @@ class MemoryCacheStore { const topLevelKey = `${key.origin}:${key.path}` const now = Date.now() - const entry = this.#entries.get(topLevelKey)?.find((entry) => ( - entry.deleteAt > now && - entry.method === key.method && - (entry.vary == null || Object.keys(entry.vary).every(headerName => { - if (entry.vary[headerName] === null) { - return key.headers[headerName] === undefined - } + const entries = this.#entries.get(topLevelKey) - return entry.vary[headerName] === key.headers[headerName] - })) - )) + const entry = entries ? findEntry(key, entries, now) : null return entry == null ? undefined @@ -140,12 +152,32 @@ class MemoryCacheStore { entries = [] store.#entries.set(topLevelKey, entries) } - entries.push(entry) + const previousEntry = findEntry(key, entries, Date.now()) + if (previousEntry) { + const index = entries.indexOf(previousEntry) + entries.splice(index, 1, entry) + store.#size -= previousEntry.size + } else { + entries.push(entry) + store.#count += 1 + } store.#size += entry.size - store.#count += 1 + // Check if cache is full and emit event if needed if (store.#size > store.#maxSize || store.#count > store.#maxCount) { + // Emit maxSizeExceeded event if we haven't already + if (!store.#hasEmittedMaxSizeEvent) { + store.emit('maxSizeExceeded', { + size: store.#size, + maxSize: store.#maxSize, + count: store.#count, + maxCount: store.#maxCount + }) + store.#hasEmittedMaxSizeEvent = true + } + + // Perform eviction for (const [key, entries] of store.#entries) { for (const entry of entries.splice(0, entries.length / 2)) { store.#size -= entry.size @@ -155,6 +187,11 @@ class MemoryCacheStore { store.#entries.delete(key) } } + + // Reset the event flag after eviction + if (store.#size < store.#maxSize && store.#count < store.#maxCount) { + store.#hasEmittedMaxSizeEvent = false + } } callback(null) @@ -180,4 +217,18 @@ class MemoryCacheStore { } } +function findEntry (key, entries, now) { + return entries.find((entry) => ( + entry.deleteAt > now && + entry.method === key.method && + (entry.vary == null || Object.keys(entry.vary).every(headerName => { + if (entry.vary[headerName] === null) { + return key.headers[headerName] === undefined + } + + return entry.vary[headerName] === key.headers[headerName] + })) + )) +} + module.exports = MemoryCacheStore diff --git a/deps/undici/src/lib/dispatcher/agent.js b/deps/undici/src/lib/dispatcher/agent.js index 46fc15742d1498..7c413701a6d683 100644 --- a/deps/undici/src/lib/dispatcher/agent.js +++ b/deps/undici/src/lib/dispatcher/agent.js @@ -1,7 +1,7 @@ 'use strict' const { InvalidArgumentError } = require('../core/errors') -const { kClients, kRunning, kClose, kDestroy, kDispatch } = require('../core/symbols') +const { kClients, kRunning, kClose, kDestroy, kDispatch, kUrl } = require('../core/symbols') const DispatcherBase = require('./dispatcher-base') const Pool = require('./pool') const Client = require('./client') @@ -45,22 +45,35 @@ class Agent extends DispatcherBase { } this[kOnConnect] = (origin, targets) => { + const result = this[kClients].get(origin) + if (result) { + result.count += 1 + } this.emit('connect', origin, [this, ...targets]) } this[kOnDisconnect] = (origin, targets, err) => { + const result = this[kClients].get(origin) + if (result) { + result.count -= 1 + if (result.count <= 0) { + this[kClients].delete(origin) + result.dispatcher.destroy() + } + } this.emit('disconnect', origin, [this, ...targets], err) } this[kOnConnectionError] = (origin, targets, err) => { + // TODO: should this decrement result.count here? this.emit('connectionError', origin, [this, ...targets], err) } } get [kRunning] () { let ret = 0 - for (const client of this[kClients].values()) { - ret += client[kRunning] + for (const { dispatcher } of this[kClients].values()) { + ret += dispatcher[kRunning] } return ret } @@ -73,8 +86,8 @@ class Agent extends DispatcherBase { throw new InvalidArgumentError('opts.origin must be a non-empty string or URL.') } - let dispatcher = this[kClients].get(key) - + const result = this[kClients].get(key) + let dispatcher = result && result.dispatcher if (!dispatcher) { dispatcher = this[kFactory](opts.origin, this[kOptions]) .on('drain', this[kOnDrain]) @@ -82,10 +95,7 @@ class Agent extends DispatcherBase { .on('disconnect', this[kOnDisconnect]) .on('connectionError', this[kOnConnectionError]) - // This introduces a tiny memory leak, as dispatchers are never removed from the map. - // TODO(mcollina): remove te timer when the client/pool do not have any more - // active connections. - this[kClients].set(key, dispatcher) + this[kClients].set(key, { count: 0, dispatcher }) } return dispatcher.dispatch(opts, handler) @@ -93,8 +103,8 @@ class Agent extends DispatcherBase { async [kClose] () { const closePromises = [] - for (const client of this[kClients].values()) { - closePromises.push(client.close()) + for (const { dispatcher } of this[kClients].values()) { + closePromises.push(dispatcher.close()) } this[kClients].clear() @@ -103,13 +113,23 @@ class Agent extends DispatcherBase { async [kDestroy] (err) { const destroyPromises = [] - for (const client of this[kClients].values()) { - destroyPromises.push(client.destroy(err)) + for (const { dispatcher } of this[kClients].values()) { + destroyPromises.push(dispatcher.destroy(err)) } this[kClients].clear() await Promise.all(destroyPromises) } + + get stats () { + const allClientStats = {} + for (const { dispatcher } of this[kClients].values()) { + if (dispatcher.stats) { + allClientStats[dispatcher[kUrl].origin] = dispatcher.stats + } + } + return allClientStats + } } module.exports = Agent diff --git a/deps/undici/src/lib/dispatcher/client-h2.js b/deps/undici/src/lib/dispatcher/client-h2.js index 14e51db9949220..661d857bee1413 100644 --- a/deps/undici/src/lib/dispatcher/client-h2.js +++ b/deps/undici/src/lib/dispatcher/client-h2.js @@ -295,11 +295,13 @@ function writeH2 (client, request) { if (Array.isArray(val)) { for (let i = 0; i < val.length; i++) { if (headers[key]) { - headers[key] += `,${val[i]}` + headers[key] += `, ${val[i]}` } else { headers[key] = val[i] } } + } else if (headers[key]) { + headers[key] += `, ${val}` } else { headers[key] = val } diff --git a/deps/undici/src/lib/dispatcher/client.js b/deps/undici/src/lib/dispatcher/client.js index be0e8195d0b3c0..0b0990206e7158 100644 --- a/deps/undici/src/lib/dispatcher/client.js +++ b/deps/undici/src/lib/dispatcher/client.js @@ -4,6 +4,7 @@ const assert = require('node:assert') const net = require('node:net') const http = require('node:http') const util = require('../core/util.js') +const { ClientStats } = require('../util/stats.js') const { channels } = require('../core/diagnostics.js') const Request = require('../core/request.js') const DispatcherBase = require('./dispatcher-base') @@ -260,6 +261,10 @@ class Client extends DispatcherBase { this[kResume](true) } + get stats () { + return new ClientStats(this) + } + get [kPending] () { return this[kQueue].length - this[kPendingIdx] } diff --git a/deps/undici/src/lib/dispatcher/pool-base.js b/deps/undici/src/lib/dispatcher/pool-base.js index d0ba2c3c53a0b0..4b7b6a26f1d946 100644 --- a/deps/undici/src/lib/dispatcher/pool-base.js +++ b/deps/undici/src/lib/dispatcher/pool-base.js @@ -1,9 +1,9 @@ 'use strict' +const { PoolStats } = require('../util/stats.js') const DispatcherBase = require('./dispatcher-base') const FixedQueue = require('./fixed-queue') const { kConnected, kSize, kRunning, kPending, kQueued, kBusy, kFree, kUrl, kClose, kDestroy, kDispatch } = require('../core/symbols') -const PoolStats = require('./pool-stats') const kClients = Symbol('clients') const kNeedDrain = Symbol('needDrain') @@ -16,7 +16,6 @@ const kOnConnectionError = Symbol('onConnectionError') const kGetDispatcher = Symbol('get dispatcher') const kAddClient = Symbol('add client') const kRemoveClient = Symbol('remove client') -const kStats = Symbol('stats') class PoolBase extends DispatcherBase { constructor () { @@ -67,8 +66,6 @@ class PoolBase extends DispatcherBase { this[kOnConnectionError] = (origin, targets, err) => { pool.emit('connectionError', origin, [pool, ...targets], err) } - - this[kStats] = new PoolStats(this) } get [kBusy] () { @@ -108,7 +105,7 @@ class PoolBase extends DispatcherBase { } get stats () { - return this[kStats] + return new PoolStats(this) } async [kClose] () { diff --git a/deps/undici/src/lib/dispatcher/pool-stats.js b/deps/undici/src/lib/dispatcher/pool-stats.js deleted file mode 100644 index c739211f098c6c..00000000000000 --- a/deps/undici/src/lib/dispatcher/pool-stats.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict' - -const { kFree, kConnected, kPending, kQueued, kRunning, kSize } = require('../core/symbols') -const kPool = Symbol('pool') - -class PoolStats { - constructor (pool) { - this[kPool] = pool - } - - get connected () { - return this[kPool][kConnected] - } - - get free () { - return this[kPool][kFree] - } - - get pending () { - return this[kPool][kPending] - } - - get queued () { - return this[kPool][kQueued] - } - - get running () { - return this[kPool][kRunning] - } - - get size () { - return this[kPool][kSize] - } -} - -module.exports = PoolStats diff --git a/deps/undici/src/lib/dispatcher/pool.js b/deps/undici/src/lib/dispatcher/pool.js index 14175cf4a184e2..00cf50c3012b29 100644 --- a/deps/undici/src/lib/dispatcher/pool.js +++ b/deps/undici/src/lib/dispatcher/pool.js @@ -5,7 +5,8 @@ const { kClients, kNeedDrain, kAddClient, - kGetDispatcher + kGetDispatcher, + kRemoveClient } = require('./pool-base') const Client = require('./client') const { @@ -35,6 +36,7 @@ class Pool extends PoolBase { autoSelectFamily, autoSelectFamilyAttemptTimeout, allowH2, + clientTtl, ...options } = {}) { if (connections != null && (!Number.isFinite(connections) || connections < 0)) { @@ -65,12 +67,20 @@ class Pool extends PoolBase { this[kConnections] = connections || null this[kUrl] = util.parseOrigin(origin) - this[kOptions] = { ...util.deepClone(options), connect, allowH2 } + this[kOptions] = { ...util.deepClone(options), connect, allowH2, clientTtl } this[kOptions].interceptors = options.interceptors ? { ...options.interceptors } : undefined this[kFactory] = factory + this.on('connect', (origin, targets) => { + if (clientTtl != null && clientTtl > 0) { + for (const target of targets) { + Object.assign(target, { ttl: Date.now() }) + } + } + }) + this.on('connectionError', (origin, targets, error) => { // If a connection error occurs, we remove the client from the pool, // and emit a connectionError event. They will not be re-used. @@ -87,8 +97,12 @@ class Pool extends PoolBase { } [kGetDispatcher] () { + const clientTtlOption = this[kOptions].clientTtl for (const client of this[kClients]) { - if (!client[kNeedDrain]) { + // check ttl of client and if it's stale, remove it from the pool + if (clientTtlOption != null && clientTtlOption > 0 && client.ttl && ((Date.now() - client.ttl) > clientTtlOption)) { + this[kRemoveClient](client) + } else if (!client[kNeedDrain]) { return client } } diff --git a/deps/undici/src/lib/dispatcher/proxy-agent.js b/deps/undici/src/lib/dispatcher/proxy-agent.js index c5b4d51babb449..3f656f7eb564fb 100644 --- a/deps/undici/src/lib/dispatcher/proxy-agent.js +++ b/deps/undici/src/lib/dispatcher/proxy-agent.js @@ -1,12 +1,13 @@ 'use strict' -const { kProxy, kClose, kDestroy } = require('../core/symbols') +const { kProxy, kClose, kDestroy, kDispatch, kConnector } = require('../core/symbols') const { URL } = require('node:url') const Agent = require('./agent') const Pool = require('./pool') const DispatcherBase = require('./dispatcher-base') const { InvalidArgumentError, RequestAbortedError, SecureProxyConnectionError } = require('../core/errors') const buildConnector = require('../core/connect') +const Client = require('./client') const kAgent = Symbol('proxy agent') const kClient = Symbol('proxy client') @@ -14,6 +15,7 @@ const kProxyHeaders = Symbol('proxy headers') const kRequestTls = Symbol('request tls settings') const kProxyTls = Symbol('proxy tls settings') const kConnectEndpoint = Symbol('connect endpoint function') +const kTunnelProxy = Symbol('tunnel proxy') function defaultProtocolPort (protocol) { return protocol === 'https:' ? 443 : 80 @@ -25,6 +27,61 @@ function defaultFactory (origin, opts) { const noop = () => {} +class ProxyClient extends DispatcherBase { + #client = null + constructor (origin, opts) { + if (typeof origin === 'string') { + origin = new URL(origin) + } + + if (origin.protocol !== 'http:' && origin.protocol !== 'https:') { + throw new InvalidArgumentError('ProxyClient only supports http and https protocols') + } + + super() + + this.#client = new Client(origin, opts) + } + + async [kClose] () { + await this.#client.close() + } + + async [kDestroy] () { + await this.#client.destroy() + } + + async [kDispatch] (opts, handler) { + const { method, origin } = opts + if (method === 'CONNECT') { + this.#client[kConnector]({ + origin, + port: opts.port || defaultProtocolPort(opts.protocol), + path: opts.host, + signal: opts.signal, + headers: { + ...this[kProxyHeaders], + host: opts.host + }, + servername: this[kProxyTls]?.servername || opts.servername + }, + (err, socket) => { + if (err) { + handler.callback(err) + } else { + handler.callback(null, { socket, statusCode: 200 }) + } + } + ) + return + } + if (typeof origin === 'string') { + opts.origin = new URL(origin) + } + + return this.#client.dispatch(opts, handler) + } +} class ProxyAgent extends DispatcherBase { constructor (opts) { if (!opts || (typeof opts === 'object' && !(opts instanceof URL) && !opts.uri)) { @@ -36,6 +93,8 @@ class ProxyAgent extends DispatcherBase { throw new InvalidArgumentError('Proxy opts.clientFactory must be a function.') } + const { proxyTunnel = true } = opts + super() const url = this.#getUrl(opts) @@ -57,9 +116,19 @@ class ProxyAgent extends DispatcherBase { this[kProxyHeaders]['proxy-authorization'] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:${decodeURIComponent(password)}`).toString('base64')}` } + const factory = (!proxyTunnel && protocol === 'http:') + ? (origin, options) => { + if (origin.protocol === 'http:') { + return new ProxyClient(origin, options) + } + return new Client(origin, options) + } + : undefined + const connect = buildConnector({ ...opts.proxyTls }) this[kConnectEndpoint] = buildConnector({ ...opts.requestTls }) - this[kClient] = clientFactory(url, { connect }) + this[kClient] = clientFactory(url, { connect, factory }) + this[kTunnelProxy] = proxyTunnel this[kAgent] = new Agent({ ...opts, connect: async (opts, callback) => { @@ -115,6 +184,10 @@ class ProxyAgent extends DispatcherBase { headers.host = host } + if (!this.#shouldConnect(new URL(opts.origin))) { + opts.path = opts.origin + opts.path + } + return this[kAgent].dispatch( { ...opts, @@ -147,6 +220,19 @@ class ProxyAgent extends DispatcherBase { await this[kAgent].destroy() await this[kClient].destroy() } + + #shouldConnect (uri) { + if (typeof uri === 'string') { + uri = new URL(uri) + } + if (this[kTunnelProxy]) { + return true + } + if (uri.protocol !== 'http:' || this[kProxy].protocol !== 'http:') { + return true + } + return false + } } /** diff --git a/deps/undici/src/lib/interceptor/cache.js b/deps/undici/src/lib/interceptor/cache.js index 295c566f255fd6..b981ebf9e01ef5 100644 --- a/deps/undici/src/lib/interceptor/cache.js +++ b/deps/undici/src/lib/interceptor/cache.js @@ -20,7 +20,12 @@ const { AbortError } = require('../core/errors.js') */ function needsRevalidation (result, cacheControlDirectives) { if (cacheControlDirectives?.['no-cache']) { - // Always revalidate requests with the no-cache directive + // Always revalidate requests with the no-cache request directive + return true + } + + if (result.cacheControlDirectives?.['no-cache'] && !Array.isArray(result.cacheControlDirectives['no-cache'])) { + // Always revalidate requests with unqualified no-cache response directive return true } @@ -233,7 +238,7 @@ function handleResult ( } let headers = { - ...normaliseHeaders(opts), + ...opts.headers, 'if-modified-since': new Date(result.cachedAt).toUTCString() } @@ -319,6 +324,11 @@ module.exports = (opts = {}) => { return dispatch(opts, handler) } + opts = { + ...opts, + headers: normaliseHeaders(opts) + } + const reqCacheControl = opts.headers?.['cache-control'] ? parseCacheControlHeader(opts.headers['cache-control']) : undefined diff --git a/deps/undici/src/lib/llhttp/wasm_build_env.txt b/deps/undici/src/lib/llhttp/wasm_build_env.txt index 9ab0e76c58829a..1b4a3a6f8bd0fa 100644 --- a/deps/undici/src/lib/llhttp/wasm_build_env.txt +++ b/deps/undici/src/lib/llhttp/wasm_build_env.txt @@ -1,5 +1,5 @@ -> undici@7.8.0 build:wasm +> undici@7.10.0 build:wasm > node build/wasm.js --docker > docker run --rm --platform=linux/x86_64 --user 1001:118 --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/lib/llhttp,target=/home/node/build/lib/llhttp --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/build,target=/home/node/build/build --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/deps,target=/home/node/build/deps -t ghcr.io/nodejs/wasm-builder@sha256:975f391d907e42a75b8c72eb77c782181e941608687d4d8694c3e9df415a0970 node build/wasm.js diff --git a/deps/undici/src/lib/mock/mock-agent.js b/deps/undici/src/lib/mock/mock-agent.js index 3bff4092db1e4e..19bb01c266188f 100644 --- a/deps/undici/src/lib/mock/mock-agent.js +++ b/deps/undici/src/lib/mock/mock-agent.js @@ -16,11 +16,12 @@ const { kMockAgentIsCallHistoryEnabled, kMockAgentAddCallHistoryLog, kMockAgentMockCallHistoryInstance, + kMockAgentAcceptsNonStandardSearchParameters, kMockCallHistoryAddLog } = require('./mock-symbols') const MockClient = require('./mock-client') const MockPool = require('./mock-pool') -const { matchValue, buildAndValidateMockOptions } = require('./mock-utils') +const { matchValue, normalizeSearchParams, buildAndValidateMockOptions } = require('./mock-utils') const { InvalidArgumentError, UndiciError } = require('../core/errors') const Dispatcher = require('../dispatcher/dispatcher') const PendingInterceptorsFormatter = require('./pending-interceptors-formatter') @@ -35,6 +36,7 @@ class MockAgent extends Dispatcher { this[kNetConnect] = true this[kIsMockActive] = true this[kMockAgentIsCallHistoryEnabled] = mockOptions?.enableCallHistory ?? false + this[kMockAgentAcceptsNonStandardSearchParameters] = mockOptions?.acceptNonStandardSearchParameters ?? false // Instantiate Agent and encapsulate if (opts?.agent && typeof opts.agent.dispatch !== 'function') { @@ -67,7 +69,17 @@ class MockAgent extends Dispatcher { this[kMockAgentAddCallHistoryLog](opts) - return this[kAgent].dispatch(opts, handler) + const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters] + + const dispatchOpts = { ...opts } + + if (acceptNonStandardSearchParameters && dispatchOpts.path) { + const [path, searchParams] = dispatchOpts.path.split('?') + const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters) + dispatchOpts.path = `${path}?${normalizedSearchParams}` + } + + return this[kAgent].dispatch(dispatchOpts, handler) } async close () { @@ -147,7 +159,7 @@ class MockAgent extends Dispatcher { } [kMockAgentSet] (origin, dispatcher) { - this[kClients].set(origin, dispatcher) + this[kClients].set(origin, { count: 0, dispatcher }) } [kFactory] (origin) { @@ -159,9 +171,9 @@ class MockAgent extends Dispatcher { [kMockAgentGet] (origin) { // First check if we can immediately find it - const client = this[kClients].get(origin) - if (client) { - return client + const result = this[kClients].get(origin) + if (result?.dispatcher) { + return result.dispatcher } // If the origin is not a string create a dummy parent pool and return to user @@ -172,11 +184,11 @@ class MockAgent extends Dispatcher { } // If we match, create a pool and assign the same dispatches - for (const [keyMatcher, nonExplicitDispatcher] of Array.from(this[kClients])) { - if (nonExplicitDispatcher && typeof keyMatcher !== 'string' && matchValue(keyMatcher, origin)) { + for (const [keyMatcher, result] of Array.from(this[kClients])) { + if (result && typeof keyMatcher !== 'string' && matchValue(keyMatcher, origin)) { const dispatcher = this[kFactory](origin) this[kMockAgentSet](origin, dispatcher) - dispatcher[kDispatches] = nonExplicitDispatcher[kDispatches] + dispatcher[kDispatches] = result.dispatcher[kDispatches] return dispatcher } } @@ -190,7 +202,7 @@ class MockAgent extends Dispatcher { const mockAgentClients = this[kClients] return Array.from(mockAgentClients.entries()) - .flatMap(([origin, scope]) => scope[kDispatches].map(dispatch => ({ ...dispatch, origin }))) + .flatMap(([origin, result]) => result.dispatcher[kDispatches].map(dispatch => ({ ...dispatch, origin }))) .filter(({ pending }) => pending) } diff --git a/deps/undici/src/lib/mock/mock-symbols.js b/deps/undici/src/lib/mock/mock-symbols.js index 811002cccf2350..940dbe6e3f8596 100644 --- a/deps/undici/src/lib/mock/mock-symbols.js +++ b/deps/undici/src/lib/mock/mock-symbols.js @@ -26,5 +26,6 @@ module.exports = { kMockAgentRegisterCallHistory: Symbol('mock agent register mock call history'), kMockAgentAddCallHistoryLog: Symbol('mock agent add call history log'), kMockAgentIsCallHistoryEnabled: Symbol('mock agent is call history enabled'), + kMockAgentAcceptsNonStandardSearchParameters: Symbol('mock agent accepts non standard search parameters'), kMockCallHistoryAddLog: Symbol('mock call history add log') } diff --git a/deps/undici/src/lib/mock/mock-utils.js b/deps/undici/src/lib/mock/mock-utils.js index a41825459a4623..822d45d153ff29 100644 --- a/deps/undici/src/lib/mock/mock-utils.js +++ b/deps/undici/src/lib/mock/mock-utils.js @@ -92,13 +92,42 @@ function matchHeaders (mockDispatch, headers) { return true } +function normalizeSearchParams (query) { + if (typeof query !== 'string') { + return query + } + + const originalQp = new URLSearchParams(query) + const normalizedQp = new URLSearchParams() + + for (let [key, value] of originalQp.entries()) { + key = key.replace('[]', '') + + const valueRepresentsString = /^(['"]).*\1$/.test(value) + if (valueRepresentsString) { + normalizedQp.append(key, value) + continue + } + + if (value.includes(',')) { + const values = value.split(',') + for (const v of values) { + normalizedQp.append(key, v) + } + continue + } + + normalizedQp.append(key, value) + } + + return normalizedQp +} + function safeUrl (path) { if (typeof path !== 'string') { return path } - const pathSegments = path.split('?', 3) - if (pathSegments.length !== 2) { return path } @@ -376,6 +405,10 @@ function buildAndValidateMockOptions (opts) { throw new InvalidArgumentError('options.enableCallHistory must to be a boolean') } + if ('acceptNonStandardSearchParameters' in mockOptions && typeof mockOptions.acceptNonStandardSearchParameters !== 'boolean') { + throw new InvalidArgumentError('options.acceptNonStandardSearchParameters must to be a boolean') + } + return mockOptions } } @@ -395,5 +428,6 @@ module.exports = { checkNetConnect, buildAndValidateMockOptions, getHeaderByName, - buildHeadersFromArray + buildHeadersFromArray, + normalizeSearchParams } diff --git a/deps/undici/src/lib/util/cache.js b/deps/undici/src/lib/util/cache.js index 17039709bb9168..6f34793694159f 100644 --- a/deps/undici/src/lib/util/cache.js +++ b/deps/undici/src/lib/util/cache.js @@ -12,13 +12,11 @@ function makeCacheKey (opts) { throw new Error('opts.origin is undefined') } - const headers = normaliseHeaders(opts) - return { origin: opts.origin.toString(), method: opts.method, path: opts.path, - headers + headers: opts.headers } } diff --git a/deps/undici/src/lib/util/stats.js b/deps/undici/src/lib/util/stats.js new file mode 100644 index 00000000000000..a13132e4ec8d28 --- /dev/null +++ b/deps/undici/src/lib/util/stats.js @@ -0,0 +1,32 @@ +'use strict' + +const { + kConnected, + kPending, + kRunning, + kSize, + kFree, + kQueued +} = require('../core/symbols') + +class ClientStats { + constructor (client) { + this.connected = client[kConnected] + this.pending = client[kPending] + this.running = client[kRunning] + this.size = client[kSize] + } +} + +class PoolStats { + constructor (pool) { + this.connected = pool[kConnected] + this.free = pool[kFree] + this.pending = pool[kPending] + this.queued = pool[kQueued] + this.running = pool[kRunning] + this.size = pool[kSize] + } +} + +module.exports = { ClientStats, PoolStats } diff --git a/deps/undici/src/package-lock.json b/deps/undici/src/package-lock.json index 419ca7aec71073..5b2f2ef8a1cee7 100644 --- a/deps/undici/src/package-lock.json +++ b/deps/undici/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "undici", - "version": "7.8.0", + "version": "7.10.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "undici", - "version": "7.8.0", + "version": "7.10.0", "license": "MIT", "devDependencies": { "@fastify/busboy": "3.1.1", @@ -89,24 +89,24 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.2.tgz", + "integrity": "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==", "dev": true, "license": "MIT", "engines": { @@ -114,22 +114,22 @@ } }, "node_modules/@babel/core": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", - "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", + "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/traverse": "^7.26.10", - "@babel/types": "^7.26.10", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helpers": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -145,14 +145,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", - "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", + "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0", + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -162,14 +162,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz", - "integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.26.8", - "@babel/helper-validator-option": "^7.25.9", + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -179,29 +179,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", + "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -211,9 +211,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, "license": "MIT", "engines": { @@ -221,9 +221,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -231,9 +231,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, "license": "MIT", "engines": { @@ -241,9 +241,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -251,27 +251,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", - "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", + "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz", + "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.0" + "@babel/types": "^7.27.1" }, "bin": { "parser": "bin/babel-parser.js" @@ -336,13 +336,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -378,13 +378,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -504,13 +504,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", - "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -520,32 +520,32 @@ } }, "node_modules/@babel/template": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", - "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", - "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", + "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.27.0", - "@babel/parser": "^7.27.0", - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -564,14 +564,14 @@ } }, "node_modules/@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", + "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -588,21 +588,21 @@ } }, "node_modules/@emnapi/core": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.1.tgz", - "integrity": "sha512-4JFstCTaToCFrPqrGzgkF8N2NHjtsaY4uRh6brZQ5L9e4wbMieX8oDT8N7qfVFTQecHFEtkj4ve49VIZ3mKVqw==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", + "integrity": "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.0.1", + "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.1.tgz", - "integrity": "sha512-LMshMVP0ZhACNjQNYXiU1iZJ6QCcv0lUdPDPugqGvCGXt5xtRVBPdtA0qU12pEXZzpWAhWlZYptfdAFq10DOVQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", + "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", "dev": true, "license": "MIT", "optional": true, @@ -611,9 +611,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.1.tgz", - "integrity": "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz", + "integrity": "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==", "dev": true, "license": "MIT", "optional": true, @@ -622,9 +622,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", + "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", "cpu": [ "ppc64" ], @@ -639,9 +639,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", + "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", "cpu": [ "arm" ], @@ -656,9 +656,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", + "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", "cpu": [ "arm64" ], @@ -673,9 +673,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", + "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", "cpu": [ "x64" ], @@ -690,9 +690,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", + "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", "cpu": [ "arm64" ], @@ -707,9 +707,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", + "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", "cpu": [ "x64" ], @@ -724,9 +724,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", + "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", "cpu": [ "arm64" ], @@ -741,9 +741,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", + "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", "cpu": [ "x64" ], @@ -758,9 +758,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", + "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", "cpu": [ "arm" ], @@ -775,9 +775,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", + "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", "cpu": [ "arm64" ], @@ -792,9 +792,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", + "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", "cpu": [ "ia32" ], @@ -809,9 +809,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", + "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", "cpu": [ "loong64" ], @@ -826,9 +826,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", + "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", "cpu": [ "mips64el" ], @@ -843,9 +843,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", + "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", "cpu": [ "ppc64" ], @@ -860,9 +860,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", + "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", "cpu": [ "riscv64" ], @@ -877,9 +877,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", + "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", "cpu": [ "s390x" ], @@ -894,9 +894,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", - "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", + "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", "cpu": [ "x64" ], @@ -911,9 +911,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", + "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", "cpu": [ "arm64" ], @@ -928,9 +928,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", + "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", "cpu": [ "x64" ], @@ -945,9 +945,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", + "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", "cpu": [ "arm64" ], @@ -962,9 +962,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", + "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", "cpu": [ "x64" ], @@ -979,9 +979,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", + "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", "cpu": [ "x64" ], @@ -996,9 +996,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", + "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", "cpu": [ "arm64" ], @@ -1013,9 +1013,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", + "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", "cpu": [ "ia32" ], @@ -1030,9 +1030,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", + "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", "cpu": [ "x64" ], @@ -1047,9 +1047,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.0.tgz", - "integrity": "sha512-WhCn7Z7TauhBtmzhvKpoQs0Wwb/kBcy4CwpuI0/eEIr2Lx2auxmulAzLr91wVZJaz47iUZdkXOK7WlAfxGKCnA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, "license": "MIT", "dependencies": { @@ -1104,9 +1104,9 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", - "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz", + "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1114,9 +1114,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", - "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1151,13 +1151,16 @@ } }, "node_modules/@eslint/js": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.24.0.tgz", - "integrity": "sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==", + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz", + "integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==", "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { @@ -1171,32 +1174,19 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", + "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.13.0", + "@eslint/core": "^0.14.0", "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/@fastify/busboy": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.1.1.tgz", @@ -1268,9 +1258,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1871,15 +1861,15 @@ "license": "MIT" }, "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.8.tgz", - "integrity": "sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==", + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.10.tgz", + "integrity": "sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.4.0", - "@emnapi/runtime": "^1.4.0", + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.9.0" } }, @@ -1942,19 +1932,6 @@ "node": ">=14" } }, - "node_modules/@pkgr/core": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.2.tgz", - "integrity": "sha512-25L86MyPvnlQoX2MTIV2OiUcb6vJ6aRbFa9pbwByn95INKD5mFH2smgjDhq+fwJoqAgvgbdJLj6Tz7V9X5CFAQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, "node_modules/@reporters/github": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/@reporters/github/-/github-1.7.2.tgz", @@ -2112,13 +2089,6 @@ "@babel/types": "^7.20.7" } }, - "node_modules/@types/doctrine": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", - "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/eslint": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", @@ -2189,9 +2159,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "18.19.86", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.86.tgz", - "integrity": "sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==", + "version": "18.19.103", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.103.tgz", + "integrity": "sha512-hHTHp+sEz6SxFsp+SA+Tqrua3AbmlAw+Y//aEwdHrdZkYVRWdvWD3y5uPZ0flYOkgskaFWqZ/YGFm3FaFQ0pRw==", "dev": true, "license": "MIT", "dependencies": { @@ -2240,21 +2210,21 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.1.tgz", - "integrity": "sha512-ba0rr4Wfvg23vERs3eB+P3lfj2E+2g3lhWcCVukUuhtcdUx5lSIFZlGFEBHKr+3zizDa/TvZTptdNHVZWAkSBg==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz", + "integrity": "sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.29.1", - "@typescript-eslint/type-utils": "8.29.1", - "@typescript-eslint/utils": "8.29.1", - "@typescript-eslint/visitor-keys": "8.29.1", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/type-utils": "8.32.1", + "@typescript-eslint/utils": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", "graphemer": "^1.4.0", - "ignore": "^5.3.1", + "ignore": "^7.0.0", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2269,17 +2239,27 @@ "typescript": ">=4.8.4 <5.9.0" } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz", + "integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/@typescript-eslint/parser": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.29.1.tgz", - "integrity": "sha512-zczrHVEqEaTwh12gWBIJWj8nx+ayDcCJs06yoNMY0kwjMWDM6+kppljY+BxWI06d2Ja+h4+WdufDcwMnnMEWmg==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz", + "integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.29.1", - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/typescript-estree": "8.29.1", - "@typescript-eslint/visitor-keys": "8.29.1", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/typescript-estree": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", "debug": "^4.3.4" }, "engines": { @@ -2295,14 +2275,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.29.1.tgz", - "integrity": "sha512-2nggXGX5F3YrsGN08pw4XpMLO1Rgtnn4AzTegC2MDesv6q3QaTU5yU7IbS1tf1IwCR0Hv/1EFygLn9ms6LIpDA==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.1.tgz", + "integrity": "sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/visitor-keys": "8.29.1" + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2313,16 +2293,16 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.29.1.tgz", - "integrity": "sha512-DkDUSDwZVCYN71xA4wzySqqcZsHKic53A4BLqmrWFFpOpNSoxX233lwGu/2135ymTCR04PoKiEEEvN1gFYg4Tw==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.1.tgz", + "integrity": "sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.29.1", - "@typescript-eslint/utils": "8.29.1", + "@typescript-eslint/typescript-estree": "8.32.1", + "@typescript-eslint/utils": "8.32.1", "debug": "^4.3.4", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2337,9 +2317,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.29.1.tgz", - "integrity": "sha512-VT7T1PuJF1hpYC3AGm2rCgJBjHL3nc+A/bhOp9sGMKfi5v0WufsX/sHCFBfNTx2F+zA6qBc/PD0/kLRLjdt8mQ==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.1.tgz", + "integrity": "sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==", "dev": true, "license": "MIT", "engines": { @@ -2351,20 +2331,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.29.1.tgz", - "integrity": "sha512-l1enRoSaUkQxOQnbi0KPUtqeZkSiFlqrx9/3ns2rEDhGKfTa+88RmXqedC1zmVTOWrLc2e6DEJrTA51C9iLH5g==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.1.tgz", + "integrity": "sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/visitor-keys": "8.29.1", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2404,9 +2384,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -2417,16 +2397,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.29.1.tgz", - "integrity": "sha512-QAkFEbytSaB8wnmB+DflhUPz6CLbFWE2SnSCrRMEa+KnXIzDYbpsn++1HGvnfAsUY44doDXmvRkO5shlM/3UfA==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.1.tgz", + "integrity": "sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.29.1", - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/typescript-estree": "8.29.1" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/typescript-estree": "8.32.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2441,13 +2421,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.29.1.tgz", - "integrity": "sha512-RGLh5CRaUEf02viP5c1Vh1cMGffQscyHe7HPAzGpfmfflFg1wUz2rYxd+OZqwpeypYvZ8UxSxuIpF++fmOzEcg==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.1.tgz", + "integrity": "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.29.1", + "@typescript-eslint/types": "8.32.1", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -2459,9 +2439,9 @@ } }, "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.5.0.tgz", - "integrity": "sha512-YmocNlEcX/AgJv8gI41bhjMOTcKcea4D2nRIbZj+MhRtSH5+vEU8r/pFuTuoF+JjVplLsBueU+CILfBPVISyGQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.7.2.tgz", + "integrity": "sha512-vxtBno4xvowwNmO/ASL0Y45TpHqmNkAaDtz4Jqb+clmcVSSl8XCG/PNFFkGsXXXS6AMjP+ja/TtNCFFa1QwLRg==", "cpu": [ "arm64" ], @@ -2473,9 +2453,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.5.0.tgz", - "integrity": "sha512-qpUrXgH4e/0xu1LOhPEdfgSY3vIXOxDQv370NEL8npN8h40HcQDA+Pl2r4HBW6tTXezWIjxUFcP7tj529RZtDw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.7.2.tgz", + "integrity": "sha512-qhVa8ozu92C23Hsmv0BF4+5Dyyd5STT1FolV4whNgbY6mj3kA0qsrGPe35zNR3wAN7eFict3s4Rc2dDTPBTuFQ==", "cpu": [ "x64" ], @@ -2487,9 +2467,9 @@ ] }, "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.5.0.tgz", - "integrity": "sha512-3tX8r8vgjvZzaJZB4jvxUaaFCDCb3aWDCpZN3EjhGnnwhztslI05KSG5NY/jNjlcZ5QWZ7dEZZ/rNBFsmTaSPw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.7.2.tgz", + "integrity": "sha512-zKKdm2uMXqLFX6Ac7K5ElnnG5VIXbDlFWzg4WJ8CGUedJryM5A3cTgHuGMw1+P5ziV8CRhnSEgOnurTI4vpHpg==", "cpu": [ "x64" ], @@ -2501,9 +2481,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.5.0.tgz", - "integrity": "sha512-FH+ixzBKaUU9fWOj3TYO+Yn/eO6kYvMLV9eNJlJlkU7OgrxkCmiMS6wUbyT0KA3FOZGxnEQ2z3/BHgYm2jqeLA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.7.2.tgz", + "integrity": "sha512-8N1z1TbPnHH+iDS/42GJ0bMPLiGK+cUqOhNbMKtWJ4oFGzqSJk/zoXFzcQkgtI63qMcUI7wW1tq2usZQSb2jxw==", "cpu": [ "arm" ], @@ -2515,9 +2495,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.5.0.tgz", - "integrity": "sha512-pxCgXMgwB/4PfqFQg73lMhmWwcC0j5L+dNXhZoz/0ek0iS/oAWl65fxZeT/OnU7fVs52MgdP2q02EipqJJXHSg==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.7.2.tgz", + "integrity": "sha512-tjYzI9LcAXR9MYd9rO45m1s0B/6bJNuZ6jeOxo1pq1K6OBuRMMmfyvJYval3s9FPPGmrldYA3mi4gWDlWuTFGA==", "cpu": [ "arm" ], @@ -2529,9 +2509,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.5.0.tgz", - "integrity": "sha512-FX2FV7vpLE/+Z0NZX9/1pwWud5Wocm/2PgpUXbT5aSV3QEB10kBPJAzssOQylvdj8mOHoKl5pVkXpbCwww/T2g==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.7.2.tgz", + "integrity": "sha512-jon9M7DKRLGZ9VYSkFMflvNqu9hDtOCEnO2QAryFWgT6o6AXU8du56V7YqnaLKr6rAbZBWYsYpikF226v423QA==", "cpu": [ "arm64" ], @@ -2543,9 +2523,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.5.0.tgz", - "integrity": "sha512-+gF97xst1BZb28T3nwwzEtq2ewCoMDGKsenYsZuvpmNrW0019G1iUAunZN+FG55L21y+uP7zsGX06OXDQ/viKw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.7.2.tgz", + "integrity": "sha512-c8Cg4/h+kQ63pL43wBNaVMmOjXI/X62wQmru51qjfTvI7kmCy5uHTJvK/9LrF0G8Jdx8r34d019P1DVJmhXQpA==", "cpu": [ "arm64" ], @@ -2557,9 +2537,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.5.0.tgz", - "integrity": "sha512-5bEmVcQw9js8JYM2LkUBw5SeELSIxX+qKf9bFrfFINKAp4noZ//hUxLpbF7u/3gTBN1GsER6xOzIZlw/VTdXtA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.7.2.tgz", + "integrity": "sha512-A+lcwRFyrjeJmv3JJvhz5NbcCkLQL6Mk16kHTNm6/aGNc4FwPHPE4DR9DwuCvCnVHvF5IAd9U4VIs/VvVir5lg==", "cpu": [ "ppc64" ], @@ -2571,9 +2551,23 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.5.0.tgz", - "integrity": "sha512-GGk/8TPUsf1Q99F+lzMdjE6sGL26uJCwQ9TlvBs8zR3cLQNw/MIumPN7zrs3GFGySjnwXc8gA6J3HKbejywmqA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.7.2.tgz", + "integrity": "sha512-hQQ4TJQrSQW8JlPm7tRpXN8OCNP9ez7PajJNjRD1ZTHQAy685OYqPrKjfaMw/8LiHCt8AZ74rfUVHP9vn0N69Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.7.2.tgz", + "integrity": "sha512-NoAGbiqrxtY8kVooZ24i70CjLDlUFI7nDj3I9y54U94p+3kPxwd2L692YsdLa+cqQ0VoqMWoehDFp21PKRUoIQ==", "cpu": [ "riscv64" ], @@ -2585,9 +2579,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.5.0.tgz", - "integrity": "sha512-5uRkFYYVNAeVaA4W/CwugjFN3iDOHCPqsBLCCOoJiMfFMMz4evBRsg+498OFa9w6VcTn2bD5aI+RRayaIgk2Sw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.7.2.tgz", + "integrity": "sha512-KaZByo8xuQZbUhhreBTW+yUnOIHUsv04P8lKjQ5otiGoSJ17ISGYArc+4vKdLEpGaLbemGzr4ZeUbYQQsLWFjA==", "cpu": [ "s390x" ], @@ -2599,9 +2593,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.5.0.tgz", - "integrity": "sha512-j905CZH3nehYy6NimNqC2B14pxn4Ltd7guKMyPTzKehbFXTUgihQS/ZfHQTdojkMzbSwBOSgq1dOrY+IpgxDsA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.7.2.tgz", + "integrity": "sha512-dEidzJDubxxhUCBJ/SHSMJD/9q7JkyfBMT77Px1npl4xpg9t0POLvnWywSk66BgZS/b2Hy9Y1yFaoMTFJUe9yg==", "cpu": [ "x64" ], @@ -2613,9 +2607,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.5.0.tgz", - "integrity": "sha512-dmLevQTuzQRwu5A+mvj54R5aye5I4PVKiWqGxg8tTaYP2k2oTs/3Mo8mgnhPk28VoYCi0fdFYpgzCd4AJndQvQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.7.2.tgz", + "integrity": "sha512-RvP+Ux3wDjmnZDT4XWFfNBRVG0fMsc+yVzNFUqOflnDfZ9OYujv6nkh+GOr+watwrW4wdp6ASfG/e7bkDradsw==", "cpu": [ "x64" ], @@ -2627,9 +2621,9 @@ ] }, "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.5.0.tgz", - "integrity": "sha512-LtJMhwu7avhoi+kKfAZOKN773RtzLBVVF90YJbB0wyMpUj9yQPeA+mteVUI9P70OG/opH47FeV5AWeaNWWgqJg==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.7.2.tgz", + "integrity": "sha512-y797JBmO9IsvXVRCKDXOxjyAE4+CcZpla2GSoBQ33TVb3ILXuFnMrbR/QQZoauBYeOFuu4w3ifWLw52sdHGz6g==", "cpu": [ "wasm32" ], @@ -2637,16 +2631,16 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.8" + "@napi-rs/wasm-runtime": "^0.2.9" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.5.0.tgz", - "integrity": "sha512-FTZBxLL4SO1mgIM86KykzJmPeTPisBDHQV6xtfDXbTMrentuZ6SdQKJUV5BWaoUK3p8kIULlrCcucqdCnk8Npg==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.7.2.tgz", + "integrity": "sha512-gtYTh4/VREVSLA+gHrfbWxaMO/00y+34htY7XpioBTy56YN2eBjkPrY1ML1Zys89X3RJDKVaogzwxlM1qU7egg==", "cpu": [ "arm64" ], @@ -2658,9 +2652,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.5.0.tgz", - "integrity": "sha512-i5bB7vJ1waUsFciU/FKLd4Zw0VnAkvhiJ4//jYQXyDUuiLKodmtQZVTcOPU7pp97RrNgCFtXfC1gnvj/DHPJTw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.7.2.tgz", + "integrity": "sha512-Ywv20XHvHTDRQs12jd3MY8X5C8KLjDbg/jyaal/QLKx3fAShhJyD4blEANInsjxW3P7isHx1Blt56iUDDJO3jg==", "cpu": [ "ia32" ], @@ -2672,9 +2666,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.5.0.tgz", - "integrity": "sha512-wAvXp4k7jhioi4SebXW/yfzzYwsUCr9kIX4gCsUFKpCTUf8Mi7vScJXI3S+kupSUf0LbVHudR8qBbe2wFMSNUw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.7.2.tgz", + "integrity": "sha512-friS8NEQfHaDbkThxopGk+LuE5v3iY0StruifjQEt7SLbA46OnfgMO15sOTkbpJkol6RB+1l1TYPXh0sCddpvA==", "cpu": [ "x64" ], @@ -3309,9 +3303,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "version": "4.24.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz", + "integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==", "dev": true, "funding": [ { @@ -3329,10 +3323,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", + "caniuse-lite": "^1.0.30001716", + "electron-to-chromium": "^1.5.149", "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -3540,9 +3534,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001713", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001713.tgz", - "integrity": "sha512-wCIWIg+A4Xr7NfhTuHdX+/FKh3+Op3LBbSp2N5Pfx6T/LhdQy3GTyoTg48BReaW/MyMNZAkTadsBtai3ldWK0Q==", + "version": "1.0.30001718", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", + "integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==", "dev": true, "funding": [ { @@ -3726,6 +3720,16 @@ "dev": true, "license": "MIT" }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3851,9 +3855,9 @@ } }, "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3906,9 +3910,9 @@ } }, "node_modules/dedent": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", - "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", + "integrity": "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==", "dev": true, "license": "MIT", "peerDependencies": { @@ -4020,16 +4024,16 @@ } }, "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" } }, "node_modules/dunder-proto": { @@ -4055,9 +4059,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.136", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.136.tgz", - "integrity": "sha512-kL4+wUTD7RSA5FHx5YwWtjDnEEkIIikFgWHR4P6fqjw1PPLlqYkxeOb++wAauAssat0YClCy8Y3C5SxgSkjibQ==", + "version": "1.5.157", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.157.tgz", + "integrity": "sha512-/0ybgsQd1muo8QlnuTpKwtl0oX5YMlUGbm8xyqgDU00motRkKFFbUJySAQBWcY79rVqNLWIWa87BGVGClwAB2w==", "dev": true, "license": "ISC" }, @@ -4106,9 +4110,9 @@ } }, "node_modules/es-abstract": { - "version": "1.23.9", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", - "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "version": "1.23.10", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.10.tgz", + "integrity": "sha512-MtUbM072wlJNyeYAe0mhzrD+M6DIJa96CZAOBBrhDbgKnB4MApIKefcyAB1eOdYn8cUNZgvwBvEzdoAYsxgEIw==", "dev": true, "license": "MIT", "dependencies": { @@ -4116,18 +4120,18 @@ "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", - "call-bound": "^1.0.3", + "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.0", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", @@ -4143,13 +4147,13 @@ "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.0", + "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.3", + "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.3", + "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", @@ -4162,7 +4166,7 @@ "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.18" + "which-typed-array": "^1.1.19" }, "engines": { "node": ">= 0.4" @@ -4280,9 +4284,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", + "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4293,31 +4297,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.2", - "@esbuild/android-arm": "0.25.2", - "@esbuild/android-arm64": "0.25.2", - "@esbuild/android-x64": "0.25.2", - "@esbuild/darwin-arm64": "0.25.2", - "@esbuild/darwin-x64": "0.25.2", - "@esbuild/freebsd-arm64": "0.25.2", - "@esbuild/freebsd-x64": "0.25.2", - "@esbuild/linux-arm": "0.25.2", - "@esbuild/linux-arm64": "0.25.2", - "@esbuild/linux-ia32": "0.25.2", - "@esbuild/linux-loong64": "0.25.2", - "@esbuild/linux-mips64el": "0.25.2", - "@esbuild/linux-ppc64": "0.25.2", - "@esbuild/linux-riscv64": "0.25.2", - "@esbuild/linux-s390x": "0.25.2", - "@esbuild/linux-x64": "0.25.2", - "@esbuild/netbsd-arm64": "0.25.2", - "@esbuild/netbsd-x64": "0.25.2", - "@esbuild/openbsd-arm64": "0.25.2", - "@esbuild/openbsd-x64": "0.25.2", - "@esbuild/sunos-x64": "0.25.2", - "@esbuild/win32-arm64": "0.25.2", - "@esbuild/win32-ia32": "0.25.2", - "@esbuild/win32-x64": "0.25.2" + "@esbuild/aix-ppc64": "0.25.4", + "@esbuild/android-arm": "0.25.4", + "@esbuild/android-arm64": "0.25.4", + "@esbuild/android-x64": "0.25.4", + "@esbuild/darwin-arm64": "0.25.4", + "@esbuild/darwin-x64": "0.25.4", + "@esbuild/freebsd-arm64": "0.25.4", + "@esbuild/freebsd-x64": "0.25.4", + "@esbuild/linux-arm": "0.25.4", + "@esbuild/linux-arm64": "0.25.4", + "@esbuild/linux-ia32": "0.25.4", + "@esbuild/linux-loong64": "0.25.4", + "@esbuild/linux-mips64el": "0.25.4", + "@esbuild/linux-ppc64": "0.25.4", + "@esbuild/linux-riscv64": "0.25.4", + "@esbuild/linux-s390x": "0.25.4", + "@esbuild/linux-x64": "0.25.4", + "@esbuild/netbsd-arm64": "0.25.4", + "@esbuild/netbsd-x64": "0.25.4", + "@esbuild/openbsd-arm64": "0.25.4", + "@esbuild/openbsd-x64": "0.25.4", + "@esbuild/sunos-x64": "0.25.4", + "@esbuild/win32-arm64": "0.25.4", + "@esbuild/win32-ia32": "0.25.4", + "@esbuild/win32-x64": "0.25.4" } }, "node_modules/escalade": { @@ -4344,20 +4348,20 @@ } }, "node_modules/eslint": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.24.0.tgz", - "integrity": "sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==", + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz", + "integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.0", - "@eslint/core": "^0.12.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.14.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.24.0", - "@eslint/plugin-kit": "^0.2.7", + "@eslint/js": "9.27.0", + "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -4421,9 +4425,9 @@ } }, "node_modules/eslint-compat-utils/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -4524,9 +4528,9 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.0.tgz", - "integrity": "sha512-aV3/dVsT0/H9BtpNwbaqvl+0xGMRGzncLyhm793NFGvbwGGvzyAykqWZ8oZlZuGwuHkwJjhWJkG1cM3ynvd2pQ==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", "dev": true, "license": "ISC", "dependencies": { @@ -4535,8 +4539,8 @@ "get-tsconfig": "^4.10.0", "is-bun-module": "^2.0.0", "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.12", - "unrs-resolver": "^1.3.2" + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -4581,17 +4585,15 @@ } }, "node_modules/eslint-plugin-import-x": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.10.2.tgz", - "integrity": "sha512-jO3Y6+zBUyTX5MVbbLSzoz6fe65t+WEBaXStRLM4EBhZWbuSwAH3cLwARtM0Yp4zRtZGp9sL2zzK7G9JkHR8LA==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.12.2.tgz", + "integrity": "sha512-0jVUgJQipbs0yUfLe7LwYD6p8rIGqCysWZdyJFgkPzDyJgiKpuCaXlywKUAWgJ6u1nLpfrdt21B60OUkupyBrQ==", "dev": true, "license": "MIT", "dependencies": { - "@pkgr/core": "^0.2.1", - "@types/doctrine": "^0.0.9", - "@typescript-eslint/utils": "^8.29.0", + "@typescript-eslint/utils": "^8.31.0", + "comment-parser": "^1.4.1", "debug": "^4.4.0", - "doctrine": "^3.0.0", "eslint-import-resolver-node": "^0.3.9", "get-tsconfig": "^4.10.0", "is-glob": "^4.0.3", @@ -4599,11 +4601,14 @@ "semver": "^7.7.1", "stable-hash": "^0.0.5", "tslib": "^2.8.1", - "unrs-resolver": "^1.4.1" + "unrs-resolver": "^1.7.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-import-x" + }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" } @@ -4635,9 +4640,9 @@ } }, "node_modules/eslint-plugin-import-x/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -4648,9 +4653,9 @@ } }, "node_modules/eslint-plugin-n": { - "version": "17.17.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.17.0.tgz", - "integrity": "sha512-2VvPK7Mo73z1rDFb6pTvkH6kFibAmnTubFq5l83vePxu0WiY1s0LOtj2WHb6Sa40R3w4mnh8GFYbHBQyMlotKw==", + "version": "17.18.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.18.0.tgz", + "integrity": "sha512-hvZ/HusueqTJ7VDLoCpjN0hx4N4+jHIWTXD4TMLHy9F23XkDagR9v+xQWRWR57yY55GPF8NnD4ox9iGTxirY8A==", "dev": true, "license": "MIT", "dependencies": { @@ -4713,9 +4718,9 @@ } }, "node_modules/eslint-plugin-n/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -4777,19 +4782,6 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/eslint-plugin-react/node_modules/resolve": { "version": "2.0.0-next.5", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", @@ -4993,9 +4985,9 @@ } }, "node_modules/execa": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz", - "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", + "version": "9.5.3", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.3.tgz", + "integrity": "sha512-QFNnTvU3UjgWFy8Ef9iDHvIdcgZ344ebkwYx4/KLbR+CKQA4xBaHzv+iRpp86QfMHP8faFQLh8iOc57215y4Rg==", "dev": true, "license": "MIT", "dependencies": { @@ -5421,9 +5413,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", - "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5952,9 +5944,9 @@ } }, "node_modules/is-bun-module/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -6372,9 +6364,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -7079,9 +7071,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -7436,9 +7428,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -7647,6 +7639,22 @@ "dev": true, "license": "MIT" }, + "node_modules/napi-postinstall": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.2.4.tgz", + "integrity": "sha512-ZEzHJwBhZ8qQSbknHqYcdtQVr8zUgGyM/q6h6qAyhtyVMNrSgDhrC4disf03dYW0e+czXyLnZINnCTEkWy0eJg==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7796,9 +7804,9 @@ } }, "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -9547,9 +9555,9 @@ } }, "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", "dev": true, "license": "MIT", "engines": { @@ -9598,13 +9606,13 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", - "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", "dev": true, "license": "MIT", "dependencies": { - "fdir": "^6.4.3", + "fdir": "^6.4.4", "picomatch": "^4.0.2" }, "engines": { @@ -9615,9 +9623,9 @@ } }, "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -9863,15 +9871,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.29.1.tgz", - "integrity": "sha512-f8cDkvndhbQMPcysk6CUSGBWV+g1utqdn71P5YKwMumVMOG/5k7cHq0KyG4O52nB0oKS4aN2Tp5+wB4APJGC+w==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.32.1.tgz", + "integrity": "sha512-D7el+eaDHAmXvrZBy1zpzSNIRqnCOrkwTgZxTu3MUqRWk8k0q9m9Ho4+vPf7iHtgUfrK/o8IZaEApsxPlHTFCg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.29.1", - "@typescript-eslint/parser": "8.29.1", - "@typescript-eslint/utils": "8.29.1" + "@typescript-eslint/eslint-plugin": "8.32.1", + "@typescript-eslint/parser": "8.32.1", + "@typescript-eslint/utils": "8.32.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9948,31 +9956,36 @@ } }, "node_modules/unrs-resolver": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.5.0.tgz", - "integrity": "sha512-6aia3Oy7SEe0MuUGQm2nsyob0L2+g57w178K5SE/3pvSGAIp28BB2O921fKx424Ahc/gQ6v0DXFbhcpyhGZdOA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.7.2.tgz", + "integrity": "sha512-BBKpaylOW8KbHsu378Zky/dGh4ckT/4NW/0SHRABdqRLcQJ2dAOjDo9g97p04sWflm0kqPqpUatxReNV/dqI5A==", "dev": true, + "hasInstallScript": true, "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.2.2" + }, "funding": { "url": "https://github.com/sponsors/JounQin" }, "optionalDependencies": { - "@unrs/resolver-binding-darwin-arm64": "1.5.0", - "@unrs/resolver-binding-darwin-x64": "1.5.0", - "@unrs/resolver-binding-freebsd-x64": "1.5.0", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.5.0", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.5.0", - "@unrs/resolver-binding-linux-arm64-gnu": "1.5.0", - "@unrs/resolver-binding-linux-arm64-musl": "1.5.0", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.5.0", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.5.0", - "@unrs/resolver-binding-linux-s390x-gnu": "1.5.0", - "@unrs/resolver-binding-linux-x64-gnu": "1.5.0", - "@unrs/resolver-binding-linux-x64-musl": "1.5.0", - "@unrs/resolver-binding-wasm32-wasi": "1.5.0", - "@unrs/resolver-binding-win32-arm64-msvc": "1.5.0", - "@unrs/resolver-binding-win32-ia32-msvc": "1.5.0", - "@unrs/resolver-binding-win32-x64-msvc": "1.5.0" + "@unrs/resolver-binding-darwin-arm64": "1.7.2", + "@unrs/resolver-binding-darwin-x64": "1.7.2", + "@unrs/resolver-binding-freebsd-x64": "1.7.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.7.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.7.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.7.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.7.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.7.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.7.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.7.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.7.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.7.2", + "@unrs/resolver-binding-linux-x64-musl": "1.7.2", + "@unrs/resolver-binding-wasm32-wasi": "1.7.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.7.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.7.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.7.2" } }, "node_modules/update-browserslist-db": { @@ -10291,9 +10304,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", "dev": true, "license": "MIT", "engines": { @@ -10330,16 +10343,16 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" + "node": ">= 14.6" } }, "node_modules/yargs": { diff --git a/deps/undici/src/package.json b/deps/undici/src/package.json index 2029f132001301..ca21dfd50ccefb 100644 --- a/deps/undici/src/package.json +++ b/deps/undici/src/package.json @@ -1,6 +1,6 @@ { "name": "undici", - "version": "7.8.0", + "version": "7.10.0", "description": "An HTTP/1.1 client, written from scratch for Node.js", "homepage": "https://undici.nodejs.org", "bugs": { diff --git a/deps/undici/src/types/agent.d.ts b/deps/undici/src/types/agent.d.ts index ee313b5209b80c..2132560744ac02 100644 --- a/deps/undici/src/types/agent.d.ts +++ b/deps/undici/src/types/agent.d.ts @@ -1,6 +1,8 @@ import { URL } from 'url' import Pool from './pool' import Dispatcher from './dispatcher' +import TClientStats from './client-stats' +import TPoolStats from './pool-stats' export default Agent @@ -12,6 +14,8 @@ declare class Agent extends Dispatcher { destroyed: boolean /** Dispatches a request. */ dispatch (options: Agent.DispatchOptions, handler: Dispatcher.DispatchHandler): boolean + /** Aggregate stats for a Agent by origin. */ + readonly stats: Record } declare namespace Agent { diff --git a/deps/undici/src/types/client-stats.d.ts b/deps/undici/src/types/client-stats.d.ts new file mode 100644 index 00000000000000..ad9bd8482dffba --- /dev/null +++ b/deps/undici/src/types/client-stats.d.ts @@ -0,0 +1,15 @@ +import Client from './client' + +export default ClientStats + +declare class ClientStats { + constructor (pool: Client) + /** If socket has open connection. */ + connected: boolean + /** Number of open socket connections in this client that do not have an active request. */ + pending: number + /** Number of currently active requests of this client. */ + running: number + /** Number of active, pending, or queued requests of this client. */ + size: number +} diff --git a/deps/undici/src/types/client.d.ts b/deps/undici/src/types/client.d.ts index 55bfcef5866501..088a673eb52791 100644 --- a/deps/undici/src/types/client.d.ts +++ b/deps/undici/src/types/client.d.ts @@ -1,6 +1,7 @@ import { URL } from 'url' import Dispatcher from './dispatcher' import buildConnector from './connector' +import TClientStats from './client-stats' type ClientConnectOptions = Omit @@ -15,6 +16,8 @@ export class Client extends Dispatcher { closed: boolean /** `true` after `client.destroyed()` has been called or `client.close()` has been called and the client shutdown has completed. */ destroyed: boolean + /** Aggregate stats for a Client. */ + readonly stats: TClientStats // Override dispatcher APIs. override connect ( @@ -84,13 +87,13 @@ export declare namespace Client { /** * @description Enables support for H2 if the server has assigned bigger priority to it through ALPN negotiation. * @default false - */ + */ allowH2?: boolean; /** * @description Dictates the maximum number of concurrent streams for a single H2 session. It can be overridden by a SETTINGS remote frame. * @default 100 - */ - maxConcurrentStreams?: number + */ + maxConcurrentStreams?: number; } export interface SocketInfo { localAddress?: string diff --git a/deps/undici/src/types/mock-agent.d.ts b/deps/undici/src/types/mock-agent.d.ts index 0b8321298dad15..330926be1919b1 100644 --- a/deps/undici/src/types/mock-agent.d.ts +++ b/deps/undici/src/types/mock-agent.d.ts @@ -59,6 +59,9 @@ declare namespace MockAgent { /** Ignore trailing slashes in the path */ ignoreTrailingSlash?: boolean; + /** Accept URLs with search parameters using non standard syntaxes. default false */ + acceptNonStandardSearchParameters?: boolean; + /** Enable call history. you can either call MockAgent.enableCallHistory(). default false */ enableCallHistory?: boolean } diff --git a/deps/undici/src/types/pool.d.ts b/deps/undici/src/types/pool.d.ts index 4814606a7027c5..5198476eb9c78f 100644 --- a/deps/undici/src/types/pool.d.ts +++ b/deps/undici/src/types/pool.d.ts @@ -33,6 +33,8 @@ declare namespace Pool { factory?(origin: URL, opts: object): Dispatcher; /** The max number of clients to create. `null` if no limit. Default `null`. */ connections?: number | null; + /** The amount of time before a client is removed from the pool and closed. `null` if no time limit. Default `null` */ + clientTtl?: number | null; interceptors?: { Pool?: readonly Dispatcher.DispatchInterceptor[] } & Client.Options['interceptors'] } diff --git a/deps/undici/src/types/proxy-agent.d.ts b/deps/undici/src/types/proxy-agent.d.ts index 7d39f971c903a6..41555422178b57 100644 --- a/deps/undici/src/types/proxy-agent.d.ts +++ b/deps/undici/src/types/proxy-agent.d.ts @@ -24,5 +24,6 @@ declare namespace ProxyAgent { requestTls?: buildConnector.BuildOptions; proxyTls?: buildConnector.BuildOptions; clientFactory?(origin: URL, opts: object): Dispatcher; + proxyTunnel?: boolean; } } diff --git a/deps/undici/undici.js b/deps/undici/undici.js index 05c939ec180b7b..8905ca01ae25ad 100644 --- a/deps/undici/undici.js +++ b/deps/undici/undici.js @@ -1846,6 +1846,46 @@ var require_dispatcher_base = __commonJS({ } }); +// lib/util/stats.js +var require_stats = __commonJS({ + "lib/util/stats.js"(exports2, module2) { + "use strict"; + var { + kConnected, + kPending, + kRunning, + kSize, + kFree, + kQueued + } = require_symbols(); + var ClientStats = class { + static { + __name(this, "ClientStats"); + } + constructor(client) { + this.connected = client[kConnected]; + this.pending = client[kPending]; + this.running = client[kRunning]; + this.size = client[kSize]; + } + }; + var PoolStats = class { + static { + __name(this, "PoolStats"); + } + constructor(pool) { + this.connected = pool[kConnected]; + this.free = pool[kFree]; + this.pending = pool[kPending]; + this.queued = pool[kQueued]; + this.running = pool[kRunning]; + this.size = pool[kSize]; + } + }; + module2.exports = { ClientStats, PoolStats }; + } +}); + // lib/dispatcher/fixed-queue.js var require_fixed_queue = __commonJS({ "lib/dispatcher/fixed-queue.js"(exports2, module2) { @@ -1933,50 +1973,14 @@ var require_fixed_queue = __commonJS({ } }); -// lib/dispatcher/pool-stats.js -var require_pool_stats = __commonJS({ - "lib/dispatcher/pool-stats.js"(exports2, module2) { - "use strict"; - var { kFree, kConnected, kPending, kQueued, kRunning, kSize } = require_symbols(); - var kPool = Symbol("pool"); - var PoolStats = class { - static { - __name(this, "PoolStats"); - } - constructor(pool) { - this[kPool] = pool; - } - get connected() { - return this[kPool][kConnected]; - } - get free() { - return this[kPool][kFree]; - } - get pending() { - return this[kPool][kPending]; - } - get queued() { - return this[kPool][kQueued]; - } - get running() { - return this[kPool][kRunning]; - } - get size() { - return this[kPool][kSize]; - } - }; - module2.exports = PoolStats; - } -}); - // lib/dispatcher/pool-base.js var require_pool_base = __commonJS({ "lib/dispatcher/pool-base.js"(exports2, module2) { "use strict"; + var { PoolStats } = require_stats(); var DispatcherBase = require_dispatcher_base(); var FixedQueue = require_fixed_queue(); var { kConnected, kSize, kRunning, kPending, kQueued, kBusy, kFree, kUrl, kClose, kDestroy, kDispatch } = require_symbols(); - var PoolStats = require_pool_stats(); var kClients = Symbol("clients"); var kNeedDrain = Symbol("needDrain"); var kQueue = Symbol("queue"); @@ -1988,7 +1992,6 @@ var require_pool_base = __commonJS({ var kGetDispatcher = Symbol("get dispatcher"); var kAddClient = Symbol("add client"); var kRemoveClient = Symbol("remove client"); - var kStats = Symbol("stats"); var PoolBase = class extends DispatcherBase { static { __name(this, "PoolBase"); @@ -2028,7 +2031,6 @@ var require_pool_base = __commonJS({ this[kOnConnectionError] = (origin, targets, err) => { pool.emit("connectionError", origin, [pool, ...targets], err); }; - this[kStats] = new PoolStats(this); } get [kBusy]() { return this[kNeedDrain]; @@ -2061,7 +2063,7 @@ var require_pool_base = __commonJS({ return ret; } get stats() { - return this[kStats]; + return new PoolStats(this); } async [kClose]() { if (this[kQueue].isEmpty()) { @@ -7687,11 +7689,13 @@ var require_client_h2 = __commonJS({ if (Array.isArray(val)) { for (let i = 0; i < val.length; i++) { if (headers[key]) { - headers[key] += `,${val[i]}`; + headers[key] += `, ${val[i]}`; } else { headers[key] = val[i]; } } + } else if (headers[key]) { + headers[key] += `, ${val}`; } else { headers[key] = val; } @@ -8066,6 +8070,7 @@ var require_client = __commonJS({ var net = require("node:net"); var http = require("node:http"); var util = require_util(); + var { ClientStats } = require_stats(); var { channels } = require_diagnostics(); var Request = require_request(); var DispatcherBase = require_dispatcher_base(); @@ -8275,6 +8280,9 @@ var require_client = __commonJS({ this[kPipelining] = value; this[kResume](true); } + get stats() { + return new ClientStats(this); + } get [kPending]() { return this[kQueue].length - this[kPendingIdx]; } @@ -8562,7 +8570,8 @@ var require_pool = __commonJS({ kClients, kNeedDrain, kAddClient, - kGetDispatcher + kGetDispatcher, + kRemoveClient } = require_pool_base(); var Client = require_client(); var { @@ -8593,6 +8602,7 @@ var require_pool = __commonJS({ autoSelectFamily, autoSelectFamilyAttemptTimeout, allowH2, + clientTtl, ...options } = {}) { if (connections != null && (!Number.isFinite(connections) || connections < 0)) { @@ -8618,9 +8628,16 @@ var require_pool = __commonJS({ } this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); - this[kOptions] = { ...util.deepClone(options), connect, allowH2 }; + this[kOptions] = { ...util.deepClone(options), connect, allowH2, clientTtl }; this[kOptions].interceptors = options.interceptors ? { ...options.interceptors } : void 0; this[kFactory] = factory; + this.on("connect", (origin2, targets) => { + if (clientTtl != null && clientTtl > 0) { + for (const target of targets) { + Object.assign(target, { ttl: Date.now() }); + } + } + }); this.on("connectionError", (origin2, targets, error) => { for (const target of targets) { const idx = this[kClients].indexOf(target); @@ -8631,8 +8648,11 @@ var require_pool = __commonJS({ }); } [kGetDispatcher]() { + const clientTtlOption = this[kOptions].clientTtl; for (const client of this[kClients]) { - if (!client[kNeedDrain]) { + if (clientTtlOption != null && clientTtlOption > 0 && client.ttl && Date.now() - client.ttl > clientTtlOption) { + this[kRemoveClient](client); + } else if (!client[kNeedDrain]) { return client; } } @@ -8652,7 +8672,7 @@ var require_agent = __commonJS({ "lib/dispatcher/agent.js"(exports2, module2) { "use strict"; var { InvalidArgumentError } = require_errors(); - var { kClients, kRunning, kClose, kDestroy, kDispatch } = require_symbols(); + var { kClients, kRunning, kClose, kDestroy, kDispatch, kUrl } = require_symbols(); var DispatcherBase = require_dispatcher_base(); var Pool = require_pool(); var Client = require_client(); @@ -8689,9 +8709,21 @@ var require_agent = __commonJS({ this.emit("drain", origin, [this, ...targets]); }; this[kOnConnect] = (origin, targets) => { + const result = this[kClients].get(origin); + if (result) { + result.count += 1; + } this.emit("connect", origin, [this, ...targets]); }; this[kOnDisconnect] = (origin, targets, err) => { + const result = this[kClients].get(origin); + if (result) { + result.count -= 1; + if (result.count <= 0) { + this[kClients].delete(origin); + result.dispatcher.destroy(); + } + } this.emit("disconnect", origin, [this, ...targets], err); }; this[kOnConnectionError] = (origin, targets, err) => { @@ -8700,8 +8732,8 @@ var require_agent = __commonJS({ } get [kRunning]() { let ret = 0; - for (const client of this[kClients].values()) { - ret += client[kRunning]; + for (const { dispatcher } of this[kClients].values()) { + ret += dispatcher[kRunning]; } return ret; } @@ -8712,29 +8744,39 @@ var require_agent = __commonJS({ } else { throw new InvalidArgumentError("opts.origin must be a non-empty string or URL."); } - let dispatcher = this[kClients].get(key); + const result = this[kClients].get(key); + let dispatcher = result && result.dispatcher; if (!dispatcher) { dispatcher = this[kFactory](opts.origin, this[kOptions]).on("drain", this[kOnDrain]).on("connect", this[kOnConnect]).on("disconnect", this[kOnDisconnect]).on("connectionError", this[kOnConnectionError]); - this[kClients].set(key, dispatcher); + this[kClients].set(key, { count: 0, dispatcher }); } return dispatcher.dispatch(opts, handler); } async [kClose]() { const closePromises = []; - for (const client of this[kClients].values()) { - closePromises.push(client.close()); + for (const { dispatcher } of this[kClients].values()) { + closePromises.push(dispatcher.close()); } this[kClients].clear(); await Promise.all(closePromises); } async [kDestroy](err) { const destroyPromises = []; - for (const client of this[kClients].values()) { - destroyPromises.push(client.destroy(err)); + for (const { dispatcher } of this[kClients].values()) { + destroyPromises.push(dispatcher.destroy(err)); } this[kClients].clear(); await Promise.all(destroyPromises); } + get stats() { + const allClientStats = {}; + for (const { dispatcher } of this[kClients].values()) { + if (dispatcher.stats) { + allClientStats[dispatcher[kUrl].origin] = dispatcher.stats; + } + } + return allClientStats; + } }; module2.exports = Agent; } @@ -8777,19 +8819,21 @@ var require_global2 = __commonJS({ var require_proxy_agent = __commonJS({ "lib/dispatcher/proxy-agent.js"(exports2, module2) { "use strict"; - var { kProxy, kClose, kDestroy } = require_symbols(); + var { kProxy, kClose, kDestroy, kDispatch, kConnector } = require_symbols(); var { URL: URL2 } = require("node:url"); var Agent = require_agent(); var Pool = require_pool(); var DispatcherBase = require_dispatcher_base(); var { InvalidArgumentError, RequestAbortedError, SecureProxyConnectionError } = require_errors(); var buildConnector = require_connect(); + var Client = require_client(); var kAgent = Symbol("proxy agent"); var kClient = Symbol("proxy client"); var kProxyHeaders = Symbol("proxy headers"); var kRequestTls = Symbol("request tls settings"); var kProxyTls = Symbol("proxy tls settings"); var kConnectEndpoint = Symbol("connect endpoint function"); + var kTunnelProxy = Symbol("tunnel proxy"); function defaultProtocolPort(protocol) { return protocol === "https:" ? 443 : 80; } @@ -8800,6 +8844,58 @@ var require_proxy_agent = __commonJS({ __name(defaultFactory, "defaultFactory"); var noop = /* @__PURE__ */ __name(() => { }, "noop"); + var ProxyClient = class extends DispatcherBase { + static { + __name(this, "ProxyClient"); + } + #client = null; + constructor(origin, opts) { + if (typeof origin === "string") { + origin = new URL2(origin); + } + if (origin.protocol !== "http:" && origin.protocol !== "https:") { + throw new InvalidArgumentError("ProxyClient only supports http and https protocols"); + } + super(); + this.#client = new Client(origin, opts); + } + async [kClose]() { + await this.#client.close(); + } + async [kDestroy]() { + await this.#client.destroy(); + } + async [kDispatch](opts, handler) { + const { method, origin } = opts; + if (method === "CONNECT") { + this.#client[kConnector]( + { + origin, + port: opts.port || defaultProtocolPort(opts.protocol), + path: opts.host, + signal: opts.signal, + headers: { + ...this[kProxyHeaders], + host: opts.host + }, + servername: this[kProxyTls]?.servername || opts.servername + }, + (err, socket) => { + if (err) { + handler.callback(err); + } else { + handler.callback(null, { socket, statusCode: 200 }); + } + } + ); + return; + } + if (typeof origin === "string") { + opts.origin = new URL2(origin); + } + return this.#client.dispatch(opts, handler); + } + }; var ProxyAgent = class extends DispatcherBase { static { __name(this, "ProxyAgent"); @@ -8812,6 +8908,7 @@ var require_proxy_agent = __commonJS({ if (typeof clientFactory !== "function") { throw new InvalidArgumentError("Proxy opts.clientFactory must be a function."); } + const { proxyTunnel = true } = opts; super(); const url = this.#getUrl(opts); const { href, origin, port, protocol, username, password, hostname: proxyHostname } = url; @@ -8828,9 +8925,16 @@ var require_proxy_agent = __commonJS({ } else if (username && password) { this[kProxyHeaders]["proxy-authorization"] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:${decodeURIComponent(password)}`).toString("base64")}`; } + const factory = !proxyTunnel && protocol === "http:" ? (origin2, options) => { + if (origin2.protocol === "http:") { + return new ProxyClient(origin2, options); + } + return new Client(origin2, options); + } : void 0; const connect = buildConnector({ ...opts.proxyTls }); this[kConnectEndpoint] = buildConnector({ ...opts.requestTls }); - this[kClient] = clientFactory(url, { connect }); + this[kClient] = clientFactory(url, { connect, factory }); + this[kTunnelProxy] = proxyTunnel; this[kAgent] = new Agent({ ...opts, connect: /* @__PURE__ */ __name(async (opts2, callback) => { @@ -8882,6 +8986,9 @@ var require_proxy_agent = __commonJS({ const { host } = new URL2(opts.origin); headers.host = host; } + if (!this.#shouldConnect(new URL2(opts.origin))) { + opts.path = opts.origin + opts.path; + } return this[kAgent].dispatch( { ...opts, @@ -8911,6 +9018,18 @@ var require_proxy_agent = __commonJS({ await this[kAgent].destroy(); await this[kClient].destroy(); } + #shouldConnect(uri) { + if (typeof uri === "string") { + uri = new URL2(uri); + } + if (this[kTunnelProxy]) { + return true; + } + if (uri.protocol !== "http:" || this[kProxy].protocol !== "http:") { + return true; + } + return false; + } }; function buildHeaders(headers) { if (Array.isArray(headers)) { diff --git a/deps/uv/.readthedocs.yaml b/deps/uv/.readthedocs.yaml index b16bf0d4ab754b..5290ec33e89899 100644 --- a/deps/uv/.readthedocs.yaml +++ b/deps/uv/.readthedocs.yaml @@ -2,7 +2,7 @@ version: 2 sphinx: builder: html - configuration: null + configuration: docs/src/conf.py fail_on_warning: false build: diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 39550bbc535eb2..89a3d9db05c877 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -592,3 +592,15 @@ Thad House Julian A Avar C <28635807+julian-a-avar-c@users.noreply.github.com> amcgoogan <105525867+amcgoogan@users.noreply.github.com> Rafael Gonzaga +Morten Engelhardt Olsen +Andrey +Julio Jordán +Jinho Jang +Velikiy Kirill +rainlow <37818892+rainlow@users.noreply.github.com> +Paolo Insogna +Robert Nagy +mugitya03 +Itay Bookstein +crupest +AE1020 <68134252+AE1020@users.noreply.github.com> diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt index af89db2dfc2762..73d5aff8926ed5 100644 --- a/deps/uv/CMakeLists.txt +++ b/deps/uv/CMakeLists.txt @@ -20,7 +20,7 @@ include(CTest) set(CMAKE_C_VISIBILITY_PRESET hidden) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) -set(CMAKE_C_STANDARD 90) +set(CMAKE_C_STANDARD 11) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -434,6 +434,7 @@ endif() if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|Linux|NetBSD|OpenBSD") list(APPEND uv_test_libraries util) + list(APPEND uv_libraries m) endif() if(CYGWIN OR MSYS) @@ -583,6 +584,7 @@ if(LIBUV_BUILD_TESTS) test/test-loop-close.c test/test-loop-configure.c test/test-loop-handles.c + test/test-loop-oom.c test/test-loop-stop.c test/test-loop-time.c test/test-metrics.c diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 006a9e1b415de9..787963715772d0 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,4 +1,94 @@ -2025.01.15, Version 1.50.0 (Stable) +2025.04.25, Version 1.51.0 (Stable) + +Changes since version 1.50.0: + +* win: fix leak in uv_os_tmpdir (Saúl Ibarra Corretgé) + +* docs: fix RTD build (Saúl Ibarra Corretgé) + +* win: lazy-load [GS]etThreadDescription symbols (Ben Noordhuis) + +* linux: try preadv64/pwritev64 before preadv/pwritev (Ben Noordhuis) + +* win: check cwd length before spawning a child process (Morten Engelhardt + Olsen) + +* macos,bsd: handle missing /dev/null in chroot env (Andrey) + +* doc: fix README link text (Julio Jordán) + +* win: fix order of FILE_STAT_BASIC_INFORMATION struct fields (Hüseyin Açacak) + +* macos: increase child process stdio buffer size (Jinho Jang) + +* doc: add C3 bindings to LINKS.md (Velikiy Kirill) + +* unix: remove unnecessary errno.h include in poll.c (Juan José Arboleda) + +* win: fix the inconsistency in volume serial number (Hüseyin Açacak) + +* unix: add thread affinity support on openharmony (rainlow) + +* unix: enable getrusage for SunOS (Paolo Insogna) + +* unix,win: accept NAN/INFINITY as file timestamps (Ben Noordhuis) + +* win: add ENABLE_VIRTUAL_TERMINAL_INPUT raw tty mode (Anna Henningsen) + +* test: handle UV_ENOTSUP in platform_output (cjihrig) + +* doc: fix rendering of threading.html (Tobias Nießen) + +* unix,sunos: enable use of sendmmsg on Solaris and Illumos (Stacey Marshall) + +* unix: handle out of memory in iface name copy (Ben Noordhuis) + +* openbsd: do not error out if cpuspeed is not available (Robert Nagy) + +* test: skip thread_name_threadpool on AIX/IBMi (Abdirahim Musse) + +* aix,ibmi: fix undeclared identifiers (Richard Lau) + +* unix,sunos: prefer SO_REUSEPORT for load balancing (Stacey Marshall) + +* doc: free lib pointer before function return (mugitya03) + +* test: link with libm (Juan José Arboleda) + +* style: rename parameter to match definition (Mohammed Keyvanzadeh) + +* test: support partial output lines in test runner (cjihrig) + +* build: switch from c90 to c11 (Ben Noordhuis) + +* linux: allow nul bytes in abstract socket address (Itay Bookstein) + +* sunos: use pipe2 on solaris and illumos (Andy Pan) + +* unix: remove TOCTOU issues from uv_pipe_chmod (Ben Noordhuis) + +* unix: use pipe_fname if getsockname returns nothing (crupest) + +* haiku: use uint32 instead of uint32_t (AE1020) + +* doc: update thread pool stack size comment (Ben Noordhuis) + +* unix: improve uv_loop_init OOM handling (Ben Noordhuis) + +* test: merge uv_tcp_connect callbacks (Juan José Arboleda) + +* test: skip multievent tests on macOS with TSAN enabled (Juan José Arboleda) + +* linux: align CPU quota calculation with Rust (Juan José Arboleda) + +* kqueue: improve fs event watcher OOM handling (Juan José Arboleda) + +* sunos: improve fs event watcher OOM handling (Juan José Arboleda) + +* build: shorten instructions for cmake build (Juan José Arboleda) + + +2025.01.15, Version 1.50.0 (Stable), 8fb9cb919489a48880680a56efecff6a7dfb4504 Changes since version 1.49.2: diff --git a/deps/uv/LINKS.md b/deps/uv/LINKS.md index 743935cebb8532..9f286ea3e9201f 100644 --- a/deps/uv/LINKS.md +++ b/deps/uv/LINKS.md @@ -108,3 +108,5 @@ * [node.pas](https://github.com/vovach777/node.pas) NodeJS-like ecosystem * Haskell * [Z.Haskell](https://z.haskell.world) +* C3 + * [libuv.c3l](https://github.com/velikoss/libuv.c3l) diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 9b9e6be7178b22..f3808b696ce3db 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -206,12 +206,13 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-ipc-send-recv.c \ test/test-ipc.c \ test/test-list.h \ - test/test-loop-handles.c \ test/test-loop-alive.c \ test/test-loop-close.c \ + test/test-loop-configure.c \ + test/test-loop-handles.c \ + test/test-loop-oom.c \ test/test-loop-stop.c \ test/test-loop-time.c \ - test/test-loop-configure.c \ test/test-metrics.c \ test/test-multiple-listen.c \ test/test-mutexes.c \ diff --git a/deps/uv/README.md b/deps/uv/README.md index 12c3061a894c56..7cc9d2dd53c27c 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -189,9 +189,7 @@ $ make install To build with [CMake][]: ```bash -$ mkdir -p build - -$ (cd build && cmake .. -DBUILD_TESTING=ON) # generate project with tests +$ cmake -B build -DBUILD_TESTING=ON # generate project with tests $ cmake --build build # add `-j ` with cmake >= 3.12 # Run tests: diff --git a/deps/uv/SUPPORTED_PLATFORMS.md b/deps/uv/SUPPORTED_PLATFORMS.md index 9597801b919687..c560aa1086b981 100644 --- a/deps/uv/SUPPORTED_PLATFORMS.md +++ b/deps/uv/SUPPORTED_PLATFORMS.md @@ -4,7 +4,7 @@ |---|---|---|---| | GNU/Linux | Tier 1 | Linux >= 3.10 with glibc >= 2.17 | | | macOS | Tier 1 | macOS >= 11 | Currently supported macOS releases | -| Windows | Tier 1 | >= Windows 10 | VS 2015 and later are supported | +| Windows | Tier 1 | >= Windows 10 | VS 2017 and later are supported | | FreeBSD | Tier 2 | >= 12 | | | AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | | IBM i | Tier 2 | >= IBM i 7.2 | Maintainers: @libuv/ibmi | diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index fc8316b8e8fa75..a4b03b8f5075ee 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.50.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.51.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) @@ -33,7 +33,7 @@ CC_ATTRIBUTE_VISIBILITY([default], [ # we exclude -fno-strict-aliasing for xlc CC_CHECK_FLAG_SUPPORTED_APPEND([-fno-strict-aliasing]) CC_CHECK_CFLAGS_APPEND([-g]) -CC_CHECK_CFLAGS_APPEND([-std=gnu89]) +CC_CHECK_CFLAGS_APPEND([-std=gnu11]) CC_CHECK_CFLAGS_APPEND([-Wall]) CC_CHECK_CFLAGS_APPEND([-Wextra]) CC_CHECK_CFLAGS_APPEND([-Wno-long-long]) diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index 7bc8d0cbfd165d..01a48e8edd85d8 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -430,6 +430,12 @@ API Equivalent to :man:`utime(2)`, :man:`futimes(3)` and :man:`lutimes(3)` respectively. + Passing `UV_FS_UTIME_NOW` as the atime or mtime sets the timestamp to the + current time. + + Passing `UV_FS_UTIME_OMIT` as the atime or mtime leaves the timestamp + untouched. + .. note:: z/OS: `uv_fs_lutime()` is not implemented for z/OS. It can still be called but will return ``UV_ENOSYS``. diff --git a/deps/uv/docs/src/index.rst b/deps/uv/docs/src/index.rst index 5bdb4be84b6ea1..448de4066d66f7 100644 --- a/deps/uv/docs/src/index.rst +++ b/deps/uv/docs/src/index.rst @@ -58,5 +58,5 @@ libuv can be downloaded from `here `_. Installation ------------ -Installation instructions can be found in `the README `_. +Installation instructions can be found in the `README `_. diff --git a/deps/uv/docs/src/threading.rst b/deps/uv/docs/src/threading.rst index f40cf0a33c8121..27c1d6ee28a44d 100644 --- a/deps/uv/docs/src/threading.rst +++ b/deps/uv/docs/src/threading.rst @@ -146,6 +146,8 @@ Threads a thread name can be: Linux, IBM i (16), macOS (64), Windows (32767), and NetBSD (32), etc. `uv_thread_setname()` will truncate it in case `name` is larger than the limit of the platform. + Not supported on Windows Server 2016, returns `UV_ENOSYS`. + .. versionadded:: 1.50.0 .. c:function:: int uv_thread_getname(uv_thread_t* tid, char* name, size_t* size) @@ -155,9 +157,12 @@ Threads The buffer should be large enough to hold the name of the thread plus the trailing NUL, or it will be truncated to fit with the trailing NUL. + Not supported on Windows Server 2016, returns `UV_ENOSYS`. + .. versionadded:: 1.50.0 .. c:function:: int uv_thread_setpriority(uv_thread_t tid, int priority) + If the function succeeds, the return value is 0. If the function fails, the return value is less than zero. Sets the scheduling priority of the thread specified by tid. It requires elevated @@ -165,7 +170,9 @@ Threads The priority can be set to the following constants. UV_THREAD_PRIORITY_HIGHEST, UV_THREAD_PRIORITY_ABOVE_NORMAL, UV_THREAD_PRIORITY_NORMAL, UV_THREAD_PRIORITY_BELOW_NORMAL, UV_THREAD_PRIORITY_LOWEST. + .. c:function:: int uv_thread_getpriority(uv_thread_t tid, int* priority) + If the function succeeds, the return value is 0. If the function fails, the return value is less than zero. Retrieves the scheduling priority of the thread specified by tid. The value in the diff --git a/deps/uv/docs/src/threadpool.rst b/deps/uv/docs/src/threadpool.rst index 05f31d2ccf30b8..d4dc5b8ec56097 100644 --- a/deps/uv/docs/src/threadpool.rst +++ b/deps/uv/docs/src/threadpool.rst @@ -20,10 +20,10 @@ is 1024). .. versionchanged:: 1.50.0 threads now have a default name of libuv-worker. The threadpool is global and shared across all event loops. When a particular -function makes use of the threadpool (i.e. when using :c:func:`uv_queue_work`) +function makes use of the threadpool (e.g. when using :c:func:`uv_queue_work`) libuv preallocates and initializes the maximum number of threads allowed by -``UV_THREADPOOL_SIZE``. This causes a relatively minor memory overhead -(~1MB for 128 threads) but increases the performance of threading at runtime. +``UV_THREADPOOL_SIZE``. More threads usually means more throughput but a higher +memory footprint. Thread stacks grow lazily on most platforms though. .. note:: Note that even though a global thread pool which is shared across all events diff --git a/deps/uv/docs/src/tty.rst b/deps/uv/docs/src/tty.rst index 7a2235210bf62a..b461b24437c187 100644 --- a/deps/uv/docs/src/tty.rst +++ b/deps/uv/docs/src/tty.rst @@ -27,10 +27,15 @@ Data types typedef enum { /* Initial/normal terminal mode */ UV_TTY_MODE_NORMAL, - /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + /* + * Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled). + * May become equivalent to UV_TTY_MODE_RAW_VT in future libuv versions. + */ UV_TTY_MODE_RAW, /* Binary-safe I/O mode for IPC (Unix-only) */ - UV_TTY_MODE_IO + UV_TTY_MODE_IO, + /* Raw input mode. On Windows ENABLE_VIRTUAL_TERMINAL_INPUT is also set. */ + UV_TTY_MODE_RAW_VT } uv_tty_mode_t; .. c:enum:: uv_tty_vtermstate_t diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index f0ec376b607c05..938e998fdc54d1 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -58,6 +58,7 @@ extern "C" { #include #include #include +#include /* Internal type, do not use. */ struct uv__queue { @@ -805,10 +806,15 @@ struct uv_tty_s { typedef enum { /* Initial/normal terminal mode */ UV_TTY_MODE_NORMAL, - /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + /* + * Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled). + * May become equivalent to UV_TTY_MODE_RAW_VT in future libuv versions. + */ UV_TTY_MODE_RAW, /* Binary-safe I/O mode for IPC (Unix-only) */ - UV_TTY_MODE_IO + UV_TTY_MODE_IO, + /* Raw input mode. On Windows ENABLE_VIRTUAL_TERMINAL_INPUT is also set. */ + UV_TTY_MODE_RAW_VT } uv_tty_mode_t; typedef enum { @@ -1585,6 +1591,8 @@ UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, const char* path, int mode, uv_fs_cb cb); +#define UV_FS_UTIME_NOW (INFINITY) +#define UV_FS_UTIME_OMIT (NAN) UV_EXTERN int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, diff --git a/deps/uv/include/uv/version.h b/deps/uv/include/uv/version.h index 76eb7d125fe468..77432f259588eb 100644 --- a/deps/uv/include/uv/version.h +++ b/deps/uv/include/uv/version.h @@ -31,7 +31,7 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 50 +#define UV_VERSION_MINOR 51 #define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv/win.h b/deps/uv/include/uv/win.h index 58d10b8d07fa0b..a88bf29e9ff504 100644 --- a/deps/uv/include/uv/win.h +++ b/deps/uv/include/uv/win.h @@ -499,8 +499,11 @@ typedef struct { union { \ struct { \ /* Used for readable TTY handles */ \ - /* TODO: remove me in v2.x. */ \ - HANDLE unused_; \ + union { \ + /* TODO: remove me in v2.x. */ \ + HANDLE unused_; \ + int mode; \ + } mode; \ uv_buf_t read_line_buffer; \ HANDLE read_raw_wait; \ /* Fields used for translating win keystrokes into vt100 characters */ \ diff --git a/deps/uv/src/fs-poll.c b/deps/uv/src/fs-poll.c index 44f6263a5832ec..1fadafdea1746a 100644 --- a/deps/uv/src/fs-poll.c +++ b/deps/uv/src/fs-poll.c @@ -51,7 +51,7 @@ struct poll_ctx { static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b); static void poll_cb(uv_fs_t* req); static void timer_cb(uv_timer_t* timer); -static void timer_close_cb(uv_handle_t* handle); +static void timer_close_cb(uv_handle_t* timer); static uv_stat_t zero_statbuf; diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index 3af3009a2167d6..48da0c9c40c842 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -1120,6 +1120,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifreq *ifr, *p, flg; struct in6_ifreq if6; struct sockaddr_dl* sa_addr; + size_t namelen; + char* name; ifc.ifc_req = NULL; sock6fd = -1; @@ -1156,6 +1158,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) /* Count all up and running ipv4/ipv6 addresses */ + namelen = 0; ifr = ifc.ifc_req; while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { p = ifr; @@ -1175,6 +1178,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) continue; + namelen += strlen(p->ifr_name) + 1; (*count)++; } @@ -1182,11 +1186,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { goto cleanup; /* Alloc the return interface structs */ - *addresses = uv__calloc(*count, sizeof(**addresses)); - if (!(*addresses)) { + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); + if (*addresses == NULL) { r = UV_ENOMEM; goto cleanup; } + name = (char*) &(*addresses)[*count]; address = *addresses; ifr = ifc.ifc_req; @@ -1210,7 +1215,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* All conditions above must match count loop */ - address->name = uv__strdup(p->ifr_name); + namelen = strlen(p->ifr_name) + 1; + address->name = memcpy(name, p->ifr_name, namelen); + name += namelen; if (inet6) address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); @@ -1282,13 +1289,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - int i; - - for (i = 0; i < count; ++i) { - uv__free(addresses[i].name); - } - + int count) { uv__free(addresses); } diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c index 8265a43ab47046..538ae7876f2b24 100644 --- a/deps/uv/src/unix/async.c +++ b/deps/uv/src/unix/async.c @@ -280,7 +280,7 @@ static int uv__async_start(uv_loop_t* loop) { * thus we create one for that, but this fd will not be actually used, * it's just a placeholder and magic number which is going to be closed * during the cleanup, as other FDs. */ - err = uv__open_cloexec("/dev/null", O_RDONLY); + err = uv__open_cloexec("/", O_RDONLY); if (err < 0) return err; @@ -308,8 +308,14 @@ static int uv__async_start(uv_loop_t* loop) { return err; #endif - uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]); - uv__io_start(loop, &loop->async_io_watcher, POLLIN); + err = uv__io_init_start(loop, &loop->async_io_watcher, uv__async_io, + pipefd[0], POLLIN); + if (err < 0) { + uv__close(pipefd[0]); + if (pipefd[1] != -1) + uv__close(pipefd[1]); + return err; + } loop->async_wfd = pipefd[1]; #if UV__KQUEUE_EVFILT_USER diff --git a/deps/uv/src/unix/bsd-ifaddrs.c b/deps/uv/src/unix/bsd-ifaddrs.c index 11ca95591fc382..8d9ebd25d4306b 100644 --- a/deps/uv/src/unix/bsd-ifaddrs.c +++ b/deps/uv/src/unix/bsd-ifaddrs.c @@ -65,13 +65,13 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return 0; } +/* TODO(bnoordhuis) share with linux.c */ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + uv_interface_address_t* address; struct ifaddrs* addrs; struct ifaddrs* ent; - uv_interface_address_t* address; -#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__) - int i; -#endif + size_t namelen; + char* name; *count = 0; *addresses = NULL; @@ -80,9 +80,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV__ERR(errno); /* Count the number of interfaces */ + namelen = 0; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -92,20 +94,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } /* Make sure the memory is initiallized to zero using calloc() */ - *addresses = uv__calloc(*count, sizeof(**addresses)); - + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); if (*addresses == NULL) { freeifaddrs(addrs); return UV_ENOMEM; } + name = (char*) &(*addresses)[*count]; address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; - address->name = uv__strdup(ent->ifa_name); + namelen = strlen(ent->ifa_name) + 1; + address->name = memcpy(name, ent->ifa_name, namelen); + name += namelen; if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); @@ -129,6 +133,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__) /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + int i; + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) continue; @@ -151,13 +157,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } +/* TODO(bnoordhuis) share with linux.c */ void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(addresses[i].name); - } - uv__free(addresses); } diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 61cbc0d027f04a..bd51b69b8120e8 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -867,7 +867,7 @@ static unsigned int next_power_of_two(unsigned int val) { return val; } -static void maybe_resize(uv_loop_t* loop, unsigned int len) { +static int maybe_resize(uv_loop_t* loop, unsigned int len) { uv__io_t** watchers; void* fake_watcher_list; void* fake_watcher_count; @@ -875,7 +875,7 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { unsigned int i; if (len <= loop->nwatchers) - return; + return 0; /* Preserve fake watcher list and count at the end of the watchers */ if (loop->watchers != NULL) { @@ -891,7 +891,7 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { (nwatchers + 2) * sizeof(loop->watchers[0])); if (watchers == NULL) - abort(); + return UV_ENOMEM; for (i = loop->nwatchers; i < nwatchers; i++) watchers[i] = NULL; watchers[nwatchers] = fake_watcher_list; @@ -899,11 +899,11 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { loop->watchers = watchers; loop->nwatchers = nwatchers; + return 0; } void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { - assert(cb != NULL); assert(fd >= -1); uv__queue_init(&w->pending_queue); uv__queue_init(&w->watcher_queue); @@ -914,14 +914,18 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { } -void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { +int uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + int err; + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); w->pevents |= events; - maybe_resize(loop, w->fd + 1); + err = maybe_resize(loop, w->fd + 1); + if (err) + return err; #if !defined(__sun) /* The event ports backend needs to rearm all file descriptors on each and @@ -929,7 +933,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { * short-circuit here if the event mask is unchanged. */ if (w->events == w->pevents) - return; + return 0; #endif if (uv__queue_empty(&w->watcher_queue)) @@ -939,6 +943,25 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { loop->watchers[w->fd] = w; loop->nfds++; } + + return 0; +} + + +int uv__io_init_start(uv_loop_t* loop, + uv__io_t* w, + uv__io_cb cb, + int fd, + unsigned int events) { + int err; + + assert(cb != NULL); + assert(fd > -1); + uv__io_init(w, cb, fd); + err = uv__io_start(loop, w, events); + if (err) + uv__io_init(w, NULL, -1); + return err; } @@ -1078,6 +1101,8 @@ int uv_getrusage_thread(uv_rusage_t* rusage) { return 0; +#elif defined(RUSAGE_LWP) + return uv__getrusage(RUSAGE_LWP, rusage); #elif defined(RUSAGE_THREAD) return uv__getrusage(RUSAGE_THREAD, rusage); #endif /* defined(__APPLE__) */ @@ -2021,14 +2046,11 @@ unsigned int uv_available_parallelism(void) { #ifdef __linux__ { - double rc_with_cgroup; - uv__cpu_constraint c = {0, 0, 0.0}; + long long quota = 0; - if (uv__get_constrained_cpu(&c) == 0 && c.period_length > 0) { - rc_with_cgroup = (double)c.quota_per_period / c.period_length * c.proportions; - if (rc_with_cgroup < rc) - rc = (long)rc_with_cgroup; /* Casting is safe since rc_with_cgroup < rc < LONG_MAX */ - } + if (uv__get_constrained_cpu("a) == 0) + if (quota > 0 && quota < rc) + rc = quota; } #endif /* __linux__ */ diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 239ecda16a7eb9..717f3fab36939e 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -203,8 +203,23 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { } -UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) { +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) +static struct timespec uv__fs_to_timespec(double time) { struct timespec ts; + + if (uv__isinf(time)) + return (struct timespec){UTIME_NOW, UTIME_NOW}; + if (uv__isnan(time)) + return (struct timespec){UTIME_OMIT, UTIME_OMIT}; + ts.tv_sec = time; ts.tv_nsec = (time - ts.tv_sec) * 1e9; @@ -221,41 +236,23 @@ UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) { } return ts; } +#endif -UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) { - struct timeval tv; - tv.tv_sec = time; - tv.tv_usec = (time - tv.tv_sec) * 1e6; - if (tv.tv_usec < 0) { - tv.tv_usec += 1e6; - tv.tv_sec -= 1; - } - return tv; -} static ssize_t uv__fs_futime(uv_fs_t* req) { -#if defined(__linux__) \ +#if defined(__APPLE__) \ || defined(_AIX71) \ - || defined(__HAIKU__) \ - || defined(__GNU__) - struct timespec ts[2]; - ts[0] = uv__fs_to_timespec(req->atime); - ts[1] = uv__fs_to_timespec(req->mtime); - return futimens(req->file, ts); -#elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ || defined(__NetBSD__) \ || defined(__OpenBSD__) \ + || defined(__linux__) \ || defined(__sun) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); -# if defined(__sun) - return futimesat(req->file, NULL, tv); -# else - return futimes(req->file, tv); -# endif + struct timespec ts[2]; + ts[0] = uv__fs_to_timespec(req->atime); + ts[1] = uv__fs_to_timespec(req->mtime); + return futimens(req->file, ts); #elif defined(__MVS__) attrib_t atr; memset(&atr, 0, sizeof(atr)); @@ -461,12 +458,7 @@ static ssize_t uv__pwritev_emul(int fd, /* The function pointer cache is an uintptr_t because _Atomic void* * doesn't work on macos/ios/etc... - * Disable optimization on armv7 to work around the bug described in - * https://github.com/libuv/libuv/issues/4532 */ -#if defined(__arm__) && (__ARM_ARCH == 7) -__attribute__((optimize("O0"))) -#endif static ssize_t uv__preadv_or_pwritev(int fd, const struct iovec* bufs, size_t nbufs, @@ -479,7 +471,12 @@ static ssize_t uv__preadv_or_pwritev(int fd, p = (void*) atomic_load_explicit(cache, memory_order_relaxed); if (p == NULL) { #ifdef RTLD_DEFAULT - p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev"); + /* Try _LARGEFILE_SOURCE version of preadv/pwritev first, + * then fall back to the plain version, for libcs like musl. + */ + p = dlsym(RTLD_DEFAULT, is_pread ? "preadv64" : "pwritev64"); + if (p == NULL) + p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev"); dlerror(); /* Clear errors. */ #endif /* RTLD_DEFAULT */ if (p == NULL) @@ -487,10 +484,7 @@ static ssize_t uv__preadv_or_pwritev(int fd, atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed); } - /* Use memcpy instead of `f = p` to work around a compiler bug, - * see https://github.com/libuv/libuv/issues/4532 - */ - memcpy(&f, &p, sizeof(p)); + f = p; return f(fd, bufs, nbufs, off); } @@ -1145,25 +1139,20 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { static ssize_t uv__fs_utime(uv_fs_t* req) { -#if defined(__linux__) \ - || defined(_AIX71) \ - || defined(__sun) \ - || defined(__HAIKU__) +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); return utimensat(AT_FDCWD, req->path, ts, 0); -#elif defined(__APPLE__) \ - || defined(__DragonFly__) \ - || defined(__FreeBSD__) \ - || defined(__NetBSD__) \ - || defined(__OpenBSD__) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); - return utimes(req->path, tv); -#elif defined(_AIX) \ - && !defined(_AIX71) +#elif defined(_AIX) && !defined(_AIX71) struct utimbuf buf; buf.actime = req->atime; buf.modtime = req->mtime; @@ -1184,24 +1173,19 @@ static ssize_t uv__fs_utime(uv_fs_t* req) { static ssize_t uv__fs_lutime(uv_fs_t* req) { -#if defined(__linux__) || \ - defined(_AIX71) || \ - defined(__sun) || \ - defined(__HAIKU__) || \ - defined(__GNU__) || \ - defined(__OpenBSD__) +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW); -#elif defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__NetBSD__) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); - return lutimes(req->path, tv); #else errno = ENOSYS; return -1; diff --git a/deps/uv/src/unix/haiku.c b/deps/uv/src/unix/haiku.c index 31284b66dc3e96..0d3645f014b4eb 100644 --- a/deps/uv/src/unix/haiku.c +++ b/deps/uv/src/unix/haiku.c @@ -120,7 +120,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { int i; status_t status; system_info system; - uint32_t topology_count; + uint32 topology_count; /* Haiku expects address of uint32, not uint32_t */ uint64_t cpuspeed; uv_cpu_info_t* cpu_info; diff --git a/deps/uv/src/unix/ibmi.c b/deps/uv/src/unix/ibmi.c index 837bba6e2fef7b..9d94d2af54468a 100644 --- a/deps/uv/src/unix/ibmi.c +++ b/deps/uv/src/unix/ibmi.c @@ -394,6 +394,8 @@ static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) { int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; struct ifaddrs_pase *ifap = NULL, *cur; + size_t namelen; + char* name; int inet6, r = 0; *count = 0; @@ -403,6 +405,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV_ENOSYS; /* The first loop to get the size of the array to be allocated */ + namelen = 0; for (cur = ifap; cur; cur = cur->ifa_next) { if (!(cur->ifa_addr->sa_family == AF_INET6 || cur->ifa_addr->sa_family == AF_INET)) @@ -411,6 +414,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING)) continue; + namelen += strlen(cur->ifa_name) + 1; (*count)++; } @@ -420,11 +424,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } /* Alloc the return interface structs */ - *addresses = uv__calloc(*count, sizeof(**addresses)); + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); if (*addresses == NULL) { Qp2freeifaddrs(ifap); return UV_ENOMEM; } + + name = (char*) &(*addresses)[*count]; address = *addresses; /* The second loop to fill in the array */ @@ -436,7 +442,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING)) continue; - address->name = uv__strdup(cur->ifa_name); + namelen = strlen(cur->ifa_name) + 1; + address->name = memcpy(name, cur->ifa_name, namelen); + name += namelen; inet6 = (cur->ifa_addr->sa_family == AF_INET6); @@ -497,13 +505,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } -void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { - int i; - - for (i = 0; i < count; ++i) { - uv__free(addresses[i].name); - } - +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { uv__free(addresses); } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index b1d2b21756da36..a1d7d4366308ac 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -257,7 +257,12 @@ void uv__make_close_pending(uv_handle_t* handle); int uv__getiovmax(void); void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd); -void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events); +int uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events); +int uv__io_init_start(uv_loop_t* loop, + uv__io_t* w, + uv__io_cb cb, + int fd, + unsigned int events); void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events); void uv__io_close(uv_loop_t* loop, uv__io_t* w); void uv__io_feed(uv_loop_t* loop, uv__io_t* w); @@ -489,13 +494,7 @@ uv__fs_copy_file_range(int fd_in, #endif #ifdef __linux__ -typedef struct { - long long quota_per_period; - long long period_length; - double proportions; -} uv__cpu_constraint; - -int uv__get_constrained_cpu(uv__cpu_constraint* constraint); +int uv__get_constrained_cpu(long long* quota); #endif #if defined(__sun) && !defined(__illumos__) diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index e0166c344b05c4..39b72012c26955 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -569,6 +569,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, const char* path, unsigned int flags) { int fd; + int r; #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 struct stat statbuf; #endif @@ -604,7 +605,6 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop, memory_order_relaxed)) { - int r; /* The fallback fd is no longer needed */ uv__close_nocheckstdio(fd); handle->event_watcher.fd = -1; @@ -620,11 +620,16 @@ int uv_fs_event_start(uv_fs_event_t* handle, fallback: #endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */ - uv__handle_start(handle); - uv__io_init(&handle->event_watcher, uv__fs_event, fd); - uv__io_start(handle->loop, &handle->event_watcher, POLLIN); + r = uv__io_init_start(handle->loop, + &handle->event_watcher, + uv__fs_event, + fd, + POLLIN); - return 0; + if (!r) + uv__handle_start(handle); + + return r; } diff --git a/deps/uv/src/unix/linux.c b/deps/uv/src/unix/linux.c index 763f5dd5917b44..ea3e2de0384b2c 100644 --- a/deps/uv/src/unix/linux.c +++ b/deps/uv/src/unix/linux.c @@ -1954,11 +1954,15 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return !exclude_type; } +/* TODO(bnoordhuis) share with bsd-ifaddrs.c */ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - struct ifaddrs *addrs, *ent; uv_interface_address_t* address; + struct sockaddr_ll* sll; + struct ifaddrs* addrs; + struct ifaddrs* ent; + size_t namelen; + char* name; int i; - struct sockaddr_ll *sll; *count = 0; *addresses = NULL; @@ -1967,10 +1971,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV__ERR(errno); /* Count the number of interfaces */ + namelen = 0; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -1980,19 +1986,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } /* Make sure the memory is initiallized to zero using calloc() */ - *addresses = uv__calloc(*count, sizeof(**addresses)); - if (!(*addresses)) { + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); + if (*addresses == NULL) { freeifaddrs(addrs); return UV_ENOMEM; } + name = (char*) &(*addresses)[*count]; address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; - address->name = uv__strdup(ent->ifa_name); + namelen = strlen(ent->ifa_name) + 1; + address->name = memcpy(name, ent->ifa_name, namelen); + name += namelen; if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); @@ -2036,14 +2045,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } +/* TODO(bnoordhuis) share with bsd-ifaddrs.c */ void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(addresses[i].name); - } - + int count) { uv__free(addresses); } @@ -2301,49 +2305,83 @@ uint64_t uv_get_available_memory(void) { static int uv__get_cgroupv2_constrained_cpu(const char* cgroup, - uv__cpu_constraint* constraint) { - char path[256]; - char buf[1024]; - unsigned int weight; - int cgroup_size; + long long* quota) { + static const char cgroup_mount[] = "/sys/fs/cgroup"; const char* cgroup_trimmed; + char buf[1024]; + char full_path[256]; + char path[256]; char quota_buf[16]; + char* last_slash; + int cgroup_size; + long long limit; + long long min_quota; + long long period; if (strncmp(cgroup, "0::/", 4) != 0) return UV_EINVAL; /* Trim ending \n by replacing it with a 0 */ cgroup_trimmed = cgroup + sizeof("0::/") - 1; /* Skip the prefix "0::/" */ - cgroup_size = (int)strcspn(cgroup_trimmed, "\n"); /* Find the first slash */ + cgroup_size = (int)strcspn(cgroup_trimmed, "\n"); /* Find the first \n */ + min_quota = LLONG_MAX; - /* Construct the path to the cpu.max file */ - snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.max", cgroup_size, - cgroup_trimmed); + /* Construct the path to the cpu.max files */ + snprintf(path, sizeof(path), "%s/%.*s/cgroup.controllers", cgroup_mount, + cgroup_size, cgroup_trimmed); - /* Read cpu.max */ + /* Read controllers, if not exists, not really a cgroup */ if (uv__slurp(path, buf, sizeof(buf)) < 0) return UV_EIO; - if (sscanf(buf, "%15s %llu", quota_buf, &constraint->period_length) != 2) - return UV_EINVAL; + snprintf(path, sizeof(path), "%s/%.*s", cgroup_mount, cgroup_size, + cgroup_trimmed); - if (strncmp(quota_buf, "max", 3) == 0) - constraint->quota_per_period = LLONG_MAX; - else if (sscanf(quota_buf, "%lld", &constraint->quota_per_period) != 1) - return UV_EINVAL; // conversion failed + /* + * Traverse up the cgroup v2 hierarchy, starting from the current cgroup path. + * At each level, attempt to read the "cpu.max" file, which defines the CPU + * quota and period. + * + * This reflects how Linux applies cgroup limits hierarchically. + * + * e.g: given a path like /sys/fs/cgroup/foo/bar/baz, we check: + * - /sys/fs/cgroup/foo/bar/baz/cpu.max + * - /sys/fs/cgroup/foo/bar/cpu.max + * - /sys/fs/cgroup/foo/cpu.max + * - /sys/fs/cgroup/cpu.max + */ + while (strncmp(path, cgroup_mount, strlen(cgroup_mount)) == 0) { + snprintf(full_path, sizeof(full_path), "%s/cpu.max", path); - /* Construct the path to the cpu.weight file */ - snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.weight", cgroup_size, - cgroup_trimmed); + /* Silently ignore and continue if the file does not exist */ + if (uv__slurp(full_path, quota_buf, sizeof(quota_buf)) < 0) + goto next; - /* Read cpu.weight */ - if (uv__slurp(path, buf, sizeof(buf)) < 0) - return UV_EIO; + /* No limit, move on */ + if (strncmp(quota_buf, "max", 3) == 0) + goto next; - if (sscanf(buf, "%u", &weight) != 1) - return UV_EINVAL; + /* Read cpu.max */ + if (sscanf(quota_buf, "%lld %lld", &limit, &period) != 2) + goto next; + + /* Can't divide by 0 */ + if (period == 0) + goto next; + + *quota = limit / period; + if (*quota < min_quota) + min_quota = *quota; - constraint->proportions = (double)weight / 100.0; +next: + /* Move up one level in the cgroup hierarchy by trimming the last path. + * The loop ends once we reach the cgroup root mount point. + */ + last_slash = strrchr(path, '/'); + if (last_slash == NULL || strcmp(path, cgroup_mount) == 0) + break; + *last_slash = '\0'; + } return 0; } @@ -2364,12 +2402,13 @@ static char* uv__cgroup1_find_cpu_controller(const char* cgroup, } static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, - uv__cpu_constraint* constraint) { + long long* quota) { char path[256]; char buf[1024]; - unsigned int shares; int cgroup_size; char* cgroup_cpu; + long long period_length; + long long quota_per_period; cgroup_cpu = uv__cgroup1_find_cpu_controller(cgroup, &cgroup_size); @@ -2380,10 +2419,11 @@ static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.cfs_quota_us", cgroup_size, cgroup_cpu); + /* Read cpu.cfs_quota_us */ if (uv__slurp(path, buf, sizeof(buf)) < 0) return UV_EIO; - if (sscanf(buf, "%lld", &constraint->quota_per_period) != 1) + if (sscanf(buf, "%lld", "a_per_period) != 1) return UV_EINVAL; /* Construct the path to the cpu.cfs_period_us file */ @@ -2394,26 +2434,19 @@ static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, if (uv__slurp(path, buf, sizeof(buf)) < 0) return UV_EIO; - if (sscanf(buf, "%lld", &constraint->period_length) != 1) + if (sscanf(buf, "%lld", &period_length) != 1) return UV_EINVAL; - /* Construct the path to the cpu.shares file */ - snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.shares", cgroup_size, - cgroup_cpu); - - /* Read cpu.shares */ - if (uv__slurp(path, buf, sizeof(buf)) < 0) - return UV_EIO; - - if (sscanf(buf, "%u", &shares) != 1) + /* Can't divide by 0 */ + if (period_length == 0) return UV_EINVAL; - constraint->proportions = (double)shares / 1024.0; + *quota = quota_per_period / period_length; return 0; } -int uv__get_constrained_cpu(uv__cpu_constraint* constraint) { +int uv__get_constrained_cpu(long long* quota) { char cgroup[1024]; /* Read the cgroup from /proc/self/cgroup */ @@ -2424,9 +2457,9 @@ int uv__get_constrained_cpu(uv__cpu_constraint* constraint) { * The entry for cgroup v2 is always in the format "0::$PATH" * see https://docs.kernel.org/admin-guide/cgroup-v2.html */ if (strncmp(cgroup, "0::/", 4) == 0) - return uv__get_cgroupv2_constrained_cpu(cgroup, constraint); + return uv__get_cgroupv2_constrained_cpu(cgroup, quota); else - return uv__get_cgroupv1_constrained_cpu(cgroup, constraint); + return uv__get_cgroupv1_constrained_cpu(cgroup, quota); } @@ -2456,6 +2489,7 @@ static int compare_watchers(const struct watcher_list* a, static int init_inotify(uv_loop_t* loop) { + int err; int fd; if (loop->inotify_fd != -1) @@ -2465,10 +2499,14 @@ static int init_inotify(uv_loop_t* loop) { if (fd < 0) return UV__ERR(errno); - loop->inotify_fd = fd; - uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); - uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); + err = uv__io_init_start(loop, &loop->inotify_read_watcher, uv__inotify_read, + fd, POLLIN); + if (err) { + uv__close(fd); + return err; + } + loop->inotify_fd = fd; return 0; } diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index 179ee999d8052e..5d3f0c7a348b33 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -32,12 +32,11 @@ int uv_loop_init(uv_loop_t* loop) { void* saved_data; int err; - saved_data = loop->data; memset(loop, 0, sizeof(*loop)); loop->data = saved_data; - lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields)); + lfields = uv__calloc(1, sizeof(*lfields)); if (lfields == NULL) return UV_ENOMEM; loop->internal_fields = lfields; @@ -116,6 +115,11 @@ int uv_loop_init(uv_loop_t* loop) { fail_signal_init: uv__platform_loop_delete(loop); + if (loop->backend_fd != -1) { + uv__close(loop->backend_fd); + loop->backend_fd = -1; + } + fail_platform_init: uv_mutex_destroy(&lfields->loop_metrics.lock); diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index 9c863b6c90dad9..cf20fa6658209d 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -211,8 +211,16 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { which[1] = HW_CPUSPEED; size = sizeof(cpuspeed); - if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0)) + cpuspeed = 0; + /* + * HW_CPUSPEED can return EOPNOTSUPP if cpuspeed is 0, + * so ignore that and continue the flow, because we + * still care about the rest of the CPU info. + */ + if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0) && + (errno != EOPNOTSUPP)) { goto error; + } size = sizeof(info); for (i = 0; i < numcpus; i++) { diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index bd57b17fb0367a..68e225e2e17fbb 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -31,13 +31,15 @@ /* Does the file path contain embedded nul bytes? */ -static int includes_nul(const char *s, size_t n) { +static int includes_invalid_nul(const char *s, size_t n) { if (n == 0) return 0; #ifdef __linux__ - /* Accept abstract socket namespace path ("\0/virtual/path"). */ - s++; - n--; + /* Accept abstract socket namespace paths, throughout which nul bytes have + * no special significance ("\0foo\0bar"). + */ + if (s[0] == '\0') + return 0; #endif return NULL != memchr(s, '\0', n); } @@ -84,7 +86,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; #endif - if (includes_nul(name, namelen)) + if (includes_invalid_nul(name, namelen)) return UV_EINVAL; if (flags & UV_PIPE_NO_TRUNCATE) @@ -271,7 +273,7 @@ int uv_pipe_connect2(uv_connect_t* req, if (namelen == 0) return UV_EINVAL; - if (includes_nul(name, namelen)) + if (includes_invalid_nul(name, namelen)) return UV_EINVAL; if (flags & UV_PIPE_NO_TRUNCATE) @@ -445,13 +447,18 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { int uv_pipe_chmod(uv_pipe_t* handle, int mode) { - unsigned desired_mode; - struct stat pipe_stat; char name_buffer[1 + UV__PATH_MAX]; + int desired_mode; size_t name_len; + const char* name; + int fd; int r; - if (handle == NULL || uv__stream_fd(handle) == -1) + if (handle == NULL) + return UV_EBADF; + + fd = uv__stream_fd(handle); + if (fd == -1) return UV_EBADF; if (mode != UV_READABLE && @@ -459,31 +466,32 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { mode != (UV_WRITABLE | UV_READABLE)) return UV_EINVAL; - /* Unfortunately fchmod does not work on all platforms, we will use chmod. */ - name_len = sizeof(name_buffer); - r = uv_pipe_getsockname(handle, name_buffer, &name_len); - if (r != 0) - return r; - - /* stat must be used as fstat has a bug on Darwin */ - if (uv__stat(name_buffer, &pipe_stat) == -1) - return UV__ERR(errno); - desired_mode = 0; if (mode & UV_READABLE) desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; if (mode & UV_WRITABLE) desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; - /* Exit early if pipe already has desired mode. */ - if ((pipe_stat.st_mode & desired_mode) == desired_mode) - return 0; + /* fchmod on macOS and (Free|Net|Open)BSD does not support UNIX sockets. */ + if (fchmod(fd, desired_mode)) + if (errno != EINVAL && errno != EOPNOTSUPP) + return UV__ERR(errno); - pipe_stat.st_mode |= desired_mode; + /* Fall back to chmod. */ + name_len = sizeof(name_buffer); + r = uv_pipe_getsockname(handle, name_buffer, &name_len); + if (r != 0) + return r; + name = name_buffer; + + /* On some platforms, getsockname returns an empty string, and we try with pipe_fname. */ + if (name_len == 0 && handle->pipe_fname != NULL) + name = handle->pipe_fname; - r = chmod(name_buffer, pipe_stat.st_mode); + if (chmod(name, desired_mode)) + return UV__ERR(errno); - return r != -1 ? 0 : UV__ERR(errno); + return 0; } @@ -494,7 +502,9 @@ int uv_pipe(uv_os_fd_t fds[2], int read_flags, int write_flags) { defined(__FreeBSD__) || \ defined(__OpenBSD__) || \ defined(__DragonFly__) || \ - defined(__NetBSD__) + defined(__NetBSD__) || \ + defined(__illumos__) || \ + (defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4) int flags = O_CLOEXEC; if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE)) diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c index 7a12e2d1488a9d..535ac6baafc6e0 100644 --- a/deps/uv/src/unix/poll.c +++ b/deps/uv/src/unix/poll.c @@ -24,7 +24,6 @@ #include #include -#include static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index f2038f2c0e823e..43e6b798458fc1 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -188,8 +188,12 @@ void uv__wait_children(uv_loop_t* loop) { static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { int mask; int fd; + int ret; + int size; + int i; mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM; + size = 64 * 1024; switch (container->flags & mask) { case UV_IGNORE: @@ -199,8 +203,17 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { assert(container->data.stream != NULL); if (container->data.stream->type != UV_NAMED_PIPE) return UV_EINVAL; - else - return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0); + else { + ret = uv_socketpair(SOCK_STREAM, 0, fds, 0, 0); + + if (ret == 0) + for (i = 0; i < 2; i++) { + setsockopt(fds[i], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); + setsockopt(fds[i], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); + } + } + + return ret; case UV_INHERIT_FD: case UV_INHERIT_STREAM: diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c index f23c887d0d6788..ccaa72db457c59 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/src/unix/signal.c @@ -259,22 +259,28 @@ static void uv__signal_unregister_handler(int signum) { static int uv__signal_loop_once_init(uv_loop_t* loop) { + int* pipefd; int err; /* Return if already initialized. */ - if (loop->signal_pipefd[0] != -1) + pipefd = loop->signal_pipefd; + if (pipefd[0] != -1) return 0; - err = uv__make_pipe(loop->signal_pipefd, UV_NONBLOCK_PIPE); + err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE); if (err) return err; - uv__io_init(&loop->signal_io_watcher, - uv__signal_event, - loop->signal_pipefd[0]); - uv__io_start(loop, &loop->signal_io_watcher, POLLIN); + err = uv__io_init_start(loop, &loop->signal_io_watcher, uv__signal_event, + pipefd[0], POLLIN); + if (err) { + uv__close(pipefd[0]); + uv__close(pipefd[1]); + pipefd[0] = -1; + pipefd[1] = -1; + } - return 0; + return err; } diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index 2d6bae79604e09..6c38c31aa00efa 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -546,8 +546,15 @@ int uv_fs_event_start(uv_fs_event_t* handle, } if (first_run) { - uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd); - uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN); + err = uv__io_init_start(handle->loop, + &handle->loop->fs_event_watcher, + uv__fs_event_read, + portfd, + POLLIN); + if (err) + uv__handle_stop(handle); + + return err; } return 0; @@ -826,6 +833,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; struct ifaddrs* addrs; struct ifaddrs* ent; + size_t namelen; + char* name; *count = 0; *addresses = NULL; @@ -834,9 +843,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV__ERR(errno); /* Count the number of interfaces */ + namelen = 0; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -845,19 +856,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return 0; } - *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) { + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); + if (*addresses == NULL) { freeifaddrs(addrs); return UV_ENOMEM; } + name = (char*) &(*addresses)[*count]; address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent)) continue; - address->name = uv__strdup(ent->ifa_name); + namelen = strlen(ent->ifa_name) + 1; + address->name = memcpy(name, ent->ifa_name, namelen); + name += namelen; if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); @@ -885,13 +899,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #endif /* SUNOS_NO_IFADDRS */ void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(addresses[i].name); - } - + int count) { uv__free(addresses); } diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index e51c290466d08b..34fea364aebe6d 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -214,7 +214,7 @@ int uv_thread_setaffinity(uv_thread_t* tid, if (cpumask[i]) CPU_SET(i, &cpuset); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__OHOS__) if (sched_setaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset)) r = errno; else @@ -242,7 +242,7 @@ int uv_thread_getaffinity(uv_thread_t* tid, return UV_EINVAL; CPU_ZERO(&cpuset); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__OHOS__) if (sched_getaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset)) r = errno; else diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index 793054ba5a9bff..b8610720267962 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -284,6 +284,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { int fd; int rc; + if (uv__is_raw_tty_mode(mode)) { + /* There is only a single raw TTY mode on UNIX. */ + mode = UV_TTY_MODE_RAW; + } + if (tty->mode == (int) mode) return 0; @@ -324,6 +329,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { case UV_TTY_MODE_IO: uv__tty_make_raw(&tmp); break; + default: + UNREACHABLE(); } /* Apply changes after draining */ diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 67c01f7dce8e18..c4a3559d61e350 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -300,6 +300,9 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { * * zOS does not support getsockname with SO_REUSEPORT option when using * AF_UNIX. + * + * Solaris 11.4: SO_REUSEPORT will not load balance when SO_REUSEADDR + * is also set, but it's not valid for every socket type. */ static int uv__sock_reuseaddr(int fd) { int yes; @@ -317,8 +320,18 @@ static int uv__sock_reuseaddr(int fd) { if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); } -#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) && \ - !defined(__sun__) && !defined(__DragonFly__) && !defined(_AIX73) +#elif defined(SO_REUSEPORT) && defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4 + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) { + if (errno != ENOPROTOOPT) + return UV__ERR(errno); + /* Not all socket types accept SO_REUSEPORT. */ + errno = 0; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) + return UV__ERR(errno); + } +#elif defined(SO_REUSEPORT) && \ + !defined(__linux__) && !defined(__GNU__) && \ + !defined(__illumos__) && !defined(__DragonFly__) && !defined(_AIX73) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); #else @@ -1298,7 +1311,8 @@ static int uv__udp_sendmsgv(int fd, r = 0; nsent = 0; -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ + (defined(__sun__) && defined(MSG_WAITFORONE)) if (count > 1) { for (i = 0; i < count; /*empty*/) { struct mmsghdr m[20]; @@ -1325,7 +1339,9 @@ static int uv__udp_sendmsgv(int fd, goto exit; } -#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) */ +#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || + * (defined(__sun__) && defined(MSG_WAITFORONE)) + */ for (i = 0; i < count; i++, nsent++) if ((r = uv__udp_sendmsg1(fd, bufs[i], nbufs[i], addrs[i]))) diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index 372f0c4b3ac39e..b9a8e976eefdd6 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "uv.h" #include "uv/tree.h" @@ -125,7 +126,7 @@ enum { /* Only used by uv_tty_t handles. */ UV_HANDLE_TTY_READABLE = 0x01000000, - UV_HANDLE_TTY_RAW = 0x02000000, + UV_HANDLE_UNUSED0 = 0x02000000, UV_HANDLE_TTY_SAVED_POSITION = 0x04000000, UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000, @@ -140,6 +141,10 @@ enum { UV_HANDLE_REAP = 0x10000000 }; +static inline int uv__is_raw_tty_mode(uv_tty_mode_t m) { + return m == UV_TTY_MODE_RAW || m == UV_TTY_MODE_RAW_VT; +} + int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); void uv__loop_close(uv_loop_t* loop); @@ -448,4 +453,22 @@ struct uv__loop_internal_fields_s { # define UV_PTHREAD_MAX_NAMELEN_NP 16 #endif +/* Open-coded so downstream users don't have to link libm. */ +static inline int uv__isinf(double d) { + uint64_t v; + + STATIC_ASSERT(sizeof(v) == sizeof(d)); + memcpy(&v, &d, sizeof(v)); + return (v << 1 >> 53) == 2047 && !(v << 12); +} + +/* Open-coded so downstream users don't have to link libm. */ +static inline int uv__isnan(double d) { + uint64_t v; + + STATIC_ASSERT(sizeof(v) == sizeof(d)); + memcpy(&v, &d, sizeof(v)); + return (v << 1 >> 53) == 2047 && !!(v << 12); +} + #endif /* UV_COMMON_H_ */ diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index bc63b06673ac1a..5f41c87ad5ed13 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -114,7 +114,7 @@ static int uv__loops_add(uv_loop_t* loop) { failed_loops_realloc: uv_mutex_unlock(&uv__loops_lock); - return ERROR_OUTOFMEMORY; + return UV_ENOMEM; } diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index a4742aa2ec13fd..27248f644f381b 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -1788,7 +1788,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, SetLastError(pRtlNtStatusToDosError(nt_status)); return -1; } else { - stat_info.VolumeSerialNumber.QuadPart = volume_info.VolumeSerialNumber; + stat_info.VolumeSerialNumber.LowPart = volume_info.VolumeSerialNumber; } stat_info.DeviceType = device_info.DeviceType; @@ -1839,7 +1839,7 @@ INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf) { INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf, FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat) { - statbuf->st_dev = stat_info.VolumeSerialNumber.QuadPart; + statbuf->st_dev = stat_info.VolumeSerialNumber.LowPart; /* Todo: st_mode should probably always be 0666 for everyone. We might also * want to report 0777 if the file is a .exe or a directory. @@ -2580,14 +2580,29 @@ static void fs__fchmod(uv_fs_t* req) { INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { - FILETIME filetime_a, filetime_m; + FILETIME filetime_as, *filetime_a = &filetime_as; + FILETIME filetime_ms, *filetime_m = &filetime_ms; + FILETIME now; + + if (uv__isinf(atime) || uv__isinf(mtime)) + GetSystemTimeAsFileTime(&now); + + if (uv__isinf(atime)) + filetime_a = &now; + else if (uv__isnan(atime)) + filetime_a = NULL; + else + TIME_T_TO_FILETIME(atime, filetime_a); - TIME_T_TO_FILETIME(atime, &filetime_a); - TIME_T_TO_FILETIME(mtime, &filetime_m); + if (uv__isinf(mtime)) + filetime_m = &now; + else if (uv__isnan(mtime)) + filetime_m = NULL; + else + TIME_T_TO_FILETIME(mtime, filetime_m); - if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) { + if (!SetFileTime(handle, NULL, filetime_a, filetime_m)) return -1; - } return 0; } diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 9d48ddc6f84d6f..27605ca36f4434 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -898,7 +898,7 @@ int uv_spawn(uv_loop_t* loop, *env = NULL, *cwd = NULL; STARTUPINFOW startup; PROCESS_INFORMATION info; - DWORD process_flags; + DWORD process_flags, cwd_len; BYTE* child_stdio_buffer; uv__process_init(loop, process); @@ -947,9 +947,10 @@ int uv_spawn(uv_loop_t* loop, if (err) goto done_uv; + cwd_len = wcslen(cwd); } else { /* Inherit cwd */ - DWORD cwd_len, r; + DWORD r; cwd_len = GetCurrentDirectoryW(0, NULL); if (!cwd_len) { @@ -970,6 +971,15 @@ int uv_spawn(uv_loop_t* loop, } } + /* If cwd is too long, shorten it */ + if (cwd_len >= MAX_PATH) { + cwd_len = GetShortPathNameW(cwd, cwd, cwd_len); + if (cwd_len == 0) { + err = GetLastError(); + goto done; + } + } + /* Get PATH environment variable. */ path = find_path(env); if (path == NULL) { diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c index 436846a716807e..753cb6a34a5b9a 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -57,6 +57,9 @@ STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*)); static uv_key_t uv__current_thread_key; static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT; +static uv_once_t uv__thread_name_once = UV_ONCE_INIT; +HRESULT (WINAPI *pGetThreadDescription)(HANDLE, PWSTR*); +HRESULT (WINAPI *pSetThreadDescription)(HANDLE, PCWSTR); static void uv__init_current_thread_key(void) { @@ -278,12 +281,28 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { } +static void uv__thread_name_init_once(void) { + HMODULE m; + + m = GetModuleHandleA("api-ms-win-core-processthreads-l1-1-3.dll"); + if (m != NULL) { + pGetThreadDescription = (void*) GetProcAddress(m, "GetThreadDescription"); + pSetThreadDescription = (void*) GetProcAddress(m, "SetThreadDescription"); + } +} + + int uv_thread_setname(const char* name) { HRESULT hr; WCHAR* namew; int err; char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + uv_once(&uv__thread_name_once, uv__thread_name_init_once); + + if (pSetThreadDescription == NULL) + return UV_ENOSYS; + if (name == NULL) return UV_EINVAL; @@ -295,7 +314,7 @@ int uv_thread_setname(const char* name) { if (err) return err; - hr = SetThreadDescription(GetCurrentThread(), namew); + hr = pSetThreadDescription(GetCurrentThread(), namew); uv__free(namew); if (FAILED(hr)) return uv_translate_sys_error(HRESULT_CODE(hr)); @@ -312,6 +331,11 @@ int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) { int r; DWORD exit_code; + uv_once(&uv__thread_name_once, uv__thread_name_init_once); + + if (pGetThreadDescription == NULL) + return UV_ENOSYS; + if (name == NULL || size == 0) return UV_EINVAL; @@ -324,7 +348,7 @@ int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) { namew = NULL; thread_name = NULL; - hr = GetThreadDescription(*tid, &namew); + hr = pGetThreadDescription(*tid, &namew); if (FAILED(hr)) return uv_translate_sys_error(HRESULT_CODE(hr)); diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index c0339ded2e4b76..66ca99cda83ab1 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -58,6 +58,9 @@ #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endif +#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT +#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 +#endif #define CURSOR_SIZE_SMALL 25 #define CURSOR_SIZE_LARGE 100 @@ -119,7 +122,10 @@ static int uv_tty_virtual_width = -1; * handle signalling SIGWINCH */ -static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE; +static HANDLE uv__tty_console_handle_out = INVALID_HANDLE_VALUE; +static HANDLE uv__tty_console_handle_in = INVALID_HANDLE_VALUE; +static DWORD uv__tty_console_in_original_mode = (DWORD)-1; +static volatile LONG uv__tty_console_in_need_mode_reset = 0; static int uv__tty_console_height = -1; static int uv__tty_console_width = -1; static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE; @@ -159,19 +165,21 @@ static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED; static void uv__determine_vterm_state(HANDLE handle); void uv__console_init(void) { + DWORD dwMode; + if (uv_sem_init(&uv_tty_output_lock, 1)) abort(); - uv__tty_console_handle = CreateFileW(L"CONOUT$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - 0, - 0); - if (uv__tty_console_handle != INVALID_HANDLE_VALUE) { + uv__tty_console_handle_out = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + 0, + 0); + if (uv__tty_console_handle_out != INVALID_HANDLE_VALUE) { CONSOLE_SCREEN_BUFFER_INFO sb_info; uv_mutex_init(&uv__tty_console_resize_mutex); - if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) { + if (GetConsoleScreenBufferInfo(uv__tty_console_handle_out, &sb_info)) { uv__tty_console_width = sb_info.dwSize.X; uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; } @@ -179,6 +187,18 @@ void uv__console_init(void) { NULL, WT_EXECUTELONGFUNCTION); } + uv__tty_console_handle_in = CreateFileW(L"CONIN$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + 0, + OPEN_EXISTING, + 0, + 0); + if (uv__tty_console_handle_in != INVALID_HANDLE_VALUE) { + if (GetConsoleMode(uv__tty_console_handle_in, &dwMode)) { + uv__tty_console_in_original_mode = dwMode; + } + } } @@ -253,7 +273,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { /* Initialize TTY input specific fields. */ tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE; /* TODO: remove me in v2.x. */ - tty->tty.rd.unused_ = NULL; + tty->tty.rd.mode.unused_ = NULL; + /* Partially overwrites unused_ again. */ + tty->tty.rd.mode.mode = 0; tty->tty.rd.read_line_buffer = uv_null_buf_; tty->tty.rd.read_raw_wait = NULL; @@ -344,6 +366,7 @@ static void uv__tty_capture_initial_style( int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { DWORD flags; + DWORD try_set_flags; unsigned char was_reading; uv_alloc_cb alloc_cb; uv_read_cb read_cb; @@ -353,14 +376,19 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { return UV_EINVAL; } - if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) { + if ((int)mode == tty->tty.rd.mode.mode) { return 0; } + try_set_flags = 0; switch (mode) { case UV_TTY_MODE_NORMAL: flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; break; + case UV_TTY_MODE_RAW_VT: + try_set_flags = ENABLE_VIRTUAL_TERMINAL_INPUT; + InterlockedExchange(&uv__tty_console_in_need_mode_reset, 1); + /* fallthrough */ case UV_TTY_MODE_RAW: flags = ENABLE_WINDOW_INPUT; break; @@ -386,16 +414,16 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { } uv_sem_wait(&uv_tty_output_lock); - if (!SetConsoleMode(tty->handle, flags)) { + if (!SetConsoleMode(tty->handle, flags | try_set_flags) && + !SetConsoleMode(tty->handle, flags)) { err = uv_translate_sys_error(GetLastError()); uv_sem_post(&uv_tty_output_lock); return err; } uv_sem_post(&uv_tty_output_lock); - /* Update flag. */ - tty->flags &= ~UV_HANDLE_TTY_RAW; - tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0; + /* Update mode. */ + tty->tty.rd.mode.mode = mode; /* If we just stopped reading, restart. */ if (was_reading) { @@ -614,7 +642,7 @@ static void uv__tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { static void uv__tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) { - if (handle->flags & UV_HANDLE_TTY_RAW) { + if (uv__is_raw_tty_mode(handle->tty.rd.mode.mode)) { uv__tty_queue_read_raw(loop, handle); } else { uv__tty_queue_read_line(loop, handle); @@ -702,7 +730,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, handle->flags &= ~UV_HANDLE_READ_PENDING; if (!(handle->flags & UV_HANDLE_READING) || - !(handle->flags & UV_HANDLE_TTY_RAW)) { + !(uv__is_raw_tty_mode(handle->tty.rd.mode.mode))) { goto out; } @@ -1050,7 +1078,7 @@ int uv__tty_read_stop(uv_tty_t* handle) { if (!(handle->flags & UV_HANDLE_READ_PENDING)) return 0; - if (handle->flags & UV_HANDLE_TTY_RAW) { + if (uv__is_raw_tty_mode(handle->tty.rd.mode.mode)) { /* Cancel raw read. Write some bullshit event to force the console wait to * return. */ memset(&record, 0, sizeof record); @@ -2293,7 +2321,17 @@ void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { int uv_tty_reset_mode(void) { - /* Not necessary to do anything. */ + /** + * Shells on Windows do know to reset output flags after a program exits, + * but not necessarily input flags, so we do that for them. + */ + if ( + uv__tty_console_handle_in != INVALID_HANDLE_VALUE && + uv__tty_console_in_original_mode != (DWORD)-1 && + InterlockedExchange(&uv__tty_console_in_need_mode_reset, 0) != 0 + ) { + SetConsoleMode(uv__tty_console_handle_in, uv__tty_console_in_original_mode); + } return 0; } @@ -2390,7 +2428,7 @@ static void uv__tty_console_signal_resize(void) { CONSOLE_SCREEN_BUFFER_INFO sb_info; int width, height; - if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) + if (!GetConsoleScreenBufferInfo(uv__tty_console_handle_out, &sb_info)) return; width = sb_info.dwSize.X; diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 1d1b2837e1a190..57061bf8d703fe 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -1016,6 +1016,7 @@ int uv_os_homedir(char* buffer, size_t* size) { int uv_os_tmpdir(char* buffer, size_t* size) { + int r; wchar_t *path; size_t len; @@ -1054,7 +1055,9 @@ int uv_os_tmpdir(char* buffer, size_t* size) { path[len] = L'\0'; } - return uv__copy_utf16_to_utf8(path, len, buffer, size); + r = uv__copy_utf16_to_utf8(path, len, buffer, size); + uv__free(path); + return r; } diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 4e0ccc61baf225..b9c9f1abc8899e 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4145,8 +4145,8 @@ typedef struct _FILE_STAT_BASIC_INFORMATION { ULONG DeviceType; ULONG DeviceCharacteristics; ULONG Reserved; - FILE_ID_128 FileId128; LARGE_INTEGER VolumeSerialNumber; + FILE_ID_128 FileId128; } FILE_STAT_BASIC_INFORMATION; #endif @@ -4828,13 +4828,4 @@ typedef int (WINAPI *uv_sGetHostNameW) int); extern uv_sGetHostNameW pGetHostNameW; -/* processthreadsapi.h */ -#if defined(__MINGW32__) -WINBASEAPI -HRESULT WINAPI GetThreadDescription(HANDLE hThread, - PWSTR *ppszThreadDescription); -WINBASEAPI -HRESULT WINAPI SetThreadDescription(HANDLE hThread, PCWSTR lpThreadDescription); -#endif - #endif /* UV_WIN_WINAPI_H_ */ diff --git a/deps/uv/test/runner-unix.c b/deps/uv/test/runner-unix.c index 81560add82043e..3d14cb69b29ee1 100644 --- a/deps/uv/test/runner-unix.c +++ b/deps/uv/test/runner-unix.c @@ -367,6 +367,7 @@ long int process_output_size(process_info_t *p) { /* Copy the contents of the stdio output buffer to `fd`. */ int process_copy_output(process_info_t* p, FILE* stream) { char buf[1024]; + int partial; int r; r = fseek(p->stdout_file, 0, SEEK_SET); @@ -375,9 +376,9 @@ int process_copy_output(process_info_t* p, FILE* stream) { return -1; } - /* TODO: what if the line is longer than buf */ + partial = 0; while ((r = fread(buf, 1, sizeof(buf), p->stdout_file)) != 0) - print_lines(buf, r, stream); + partial = print_lines(buf, r, stream, partial); if (ferror(p->stdout_file)) { perror("read"); diff --git a/deps/uv/test/runner-win.c b/deps/uv/test/runner-win.c index 6c6e35f7731327..8035ca62f8ec9f 100644 --- a/deps/uv/test/runner-win.c +++ b/deps/uv/test/runner-win.c @@ -219,6 +219,7 @@ long int process_output_size(process_info_t *p) { int process_copy_output(process_info_t* p, FILE* stream) { char buf[1024]; + int partial; int fd, r; fd = _open_osfhandle((intptr_t)p->stdio_out, _O_RDONLY | _O_TEXT); @@ -229,8 +230,9 @@ int process_copy_output(process_info_t* p, FILE* stream) { if (r < 0) return -1; + partial = 0; while ((r = _read(fd, buf, sizeof(buf))) != 0) - print_lines(buf, r, stream); + partial = print_lines(buf, r, stream, partial); _close(fd); return 0; diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c index 54abb39dd22886..87e7db0b05c5ea 100644 --- a/deps/uv/test/runner.c +++ b/deps/uv/test/runner.c @@ -426,13 +426,17 @@ void print_tests(FILE* stream) { } -void print_lines(const char* buffer, size_t size, FILE* stream) { +int print_lines(const char* buffer, size_t size, FILE* stream, int partial) { const char* start; const char* end; start = buffer; while ((end = memchr(start, '\n', &buffer[size] - start))) { - fputs("# ", stream); + if (partial == 0) + fputs("# ", stream); + else + partial = 0; + fwrite(start, 1, (int)(end - start), stream); fputs("\n", stream); fflush(stream); @@ -441,9 +445,13 @@ void print_lines(const char* buffer, size_t size, FILE* stream) { end = &buffer[size]; if (start < end) { - fputs("# ", stream); + if (partial == 0) + fputs("# ", stream); + fwrite(start, 1, (int)(end - start), stream); - fputs("\n", stream); fflush(stream); + return 1; } + + return 0; } diff --git a/deps/uv/test/runner.h b/deps/uv/test/runner.h index 6801564f961c31..ff7d4eec9b6870 100644 --- a/deps/uv/test/runner.h +++ b/deps/uv/test/runner.h @@ -123,7 +123,7 @@ int run_test_part(const char* test, const char* part); void print_tests(FILE* stream); /* Print lines in |buffer| as TAP diagnostics to |stream|. */ -void print_lines(const char* buffer, size_t size, FILE* stream); +int print_lines(const char* buffer, size_t size, FILE* stream, int partial); /* * Stuff that should be implemented by test-runner-.h diff --git a/deps/uv/test/test-connect-unspecified.c b/deps/uv/test/test-connect-unspecified.c index 73e59a9972b670..ebed8c3c20b809 100644 --- a/deps/uv/test/test-connect-unspecified.c +++ b/deps/uv/test/test-connect-unspecified.c @@ -22,11 +22,7 @@ #include "uv.h" #include "task.h" -static void connect_4(uv_connect_t* req, int status) { - ASSERT_NE(status, UV_EADDRNOTAVAIL); -} - -static void connect_6(uv_connect_t* req, int status) { +static void connect_cb(uv_connect_t* req, int status) { ASSERT_NE(status, UV_EADDRNOTAVAIL); } @@ -46,7 +42,7 @@ TEST_IMPL(connect_unspecified) { ASSERT_OK(uv_tcp_connect(&connect4, &socket4, (const struct sockaddr*) &addr4, - connect_4)); + connect_cb)); if (can_ipv6()) { ASSERT_OK(uv_tcp_init(loop, &socket6)); @@ -54,7 +50,7 @@ TEST_IMPL(connect_unspecified) { ASSERT_OK(uv_tcp_connect(&connect6, &socket6, (const struct sockaddr*) &addr6, - connect_6)); + connect_cb)); } ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index b53057dc25bb22..f224181fc36855 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -32,7 +32,7 @@ static uv_fs_event_t fs_event; static const char file_prefix[] = "fsevent-"; static const int fs_event_file_count = 16; -#if defined(__APPLE__) || defined(_WIN32) +#if (defined(__APPLE__) && !defined(__TSAN__)) || defined(_WIN32) static const char file_prefix_in_subdir[] = "subdir"; static int fs_multievent_cb_called; #endif @@ -250,7 +250,7 @@ static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle, } } -#if defined(__APPLE__) || defined(_WIN32) +#if (defined(__APPLE__) && !defined(__TSAN__)) || defined(_WIN32) static const char* fs_event_get_filename_in_subdir(int i) { snprintf(fs_event_filename, sizeof(fs_event_filename), diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 423d72dd2f7b84..4761b15bad188b 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -59,6 +59,18 @@ #define TOO_LONG_NAME_LENGTH 65536 #define PATHMAX 4096 +#ifdef _WIN32 +static const int is_win32 = 1; +#else +static const int is_win32 = 0; +#endif + +#if defined(__APPLE__) || defined(__SUNPRO_C) +static const int is_apple_or_sunpro_c = 1; +#else +static const int is_apple_or_sunpro_c = 0; +#endif + typedef struct { const char* path; double atime; @@ -827,43 +839,70 @@ static void check_utime(const char* path, ASSERT_OK(req.result); s = &req.statbuf; - if (s->st_atim.tv_nsec == 0 && s->st_mtim.tv_nsec == 0) { - /* - * Test sub-second timestamps only when supported (such as Windows with + if (isfinite(atime)) { + /* Test sub-second timestamps only when supported (such as Windows with * NTFS). Some other platforms support sub-second timestamps, but that * support is filesystem-dependent. Notably OS X (HFS Plus) does NOT * support sub-second timestamps. But kernels may round or truncate in * either direction, so we may accept either possible answer. */ -#ifdef _WIN32 - ASSERT_DOUBLE_EQ(atime, (long) atime); - ASSERT_DOUBLE_EQ(mtime, (long) atime); -#endif - if (atime > 0 || (long) atime == atime) - ASSERT_EQ(s->st_atim.tv_sec, (long) atime); - if (mtime > 0 || (long) mtime == mtime) - ASSERT_EQ(s->st_mtim.tv_sec, (long) mtime); - ASSERT_GE(s->st_atim.tv_sec, (long) atime - 1); - ASSERT_GE(s->st_mtim.tv_sec, (long) mtime - 1); - ASSERT_LE(s->st_atim.tv_sec, (long) atime); - ASSERT_LE(s->st_mtim.tv_sec, (long) mtime); + if (s->st_atim.tv_nsec == 0) { + if (is_win32) + ASSERT_DOUBLE_EQ(atime, (long) atime); + if (atime > 0 || (long) atime == atime) + ASSERT_EQ(s->st_atim.tv_sec, (long) atime); + ASSERT_GE(s->st_atim.tv_sec, (long) atime - 1); + ASSERT_LE(s->st_atim.tv_sec, (long) atime); + } else { + double st_atim; + /* TODO(vtjnash): would it be better to normalize this? */ + if (!is_apple_or_sunpro_c) + ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); + st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; + /* Linux does not allow reading reliably the atime of a symlink + * since readlink() can update it + */ + if (!test_lutime) + ASSERT_DOUBLE_EQ(st_atim, atime); + } + } else if (isinf(atime)) { + /* We test with timestamps that are in the distant past + * (if you're a Gen Z-er) so check it's more recent than that. + */ + ASSERT_GT(s->st_atim.tv_sec, 1739710000); } else { - double st_atim; - double st_mtim; -#if !defined(__APPLE__) && !defined(__SUNPRO_C) - /* TODO(vtjnash): would it be better to normalize this? */ - ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); - ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); -#endif - st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; - st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; - /* - * Linux does not allow reading reliably the atime of a symlink - * since readlink() can update it + ASSERT_OK(0); + } + + if (isfinite(mtime)) { + /* Test sub-second timestamps only when supported (such as Windows with + * NTFS). Some other platforms support sub-second timestamps, but that + * support is filesystem-dependent. Notably OS X (HFS Plus) does NOT + * support sub-second timestamps. But kernels may round or truncate in + * either direction, so we may accept either possible answer. */ - if (!test_lutime) - ASSERT_DOUBLE_EQ(st_atim, atime); - ASSERT_DOUBLE_EQ(st_mtim, mtime); + if (s->st_mtim.tv_nsec == 0) { + if (is_win32) + ASSERT_DOUBLE_EQ(mtime, (long) atime); + if (mtime > 0 || (long) mtime == mtime) + ASSERT_EQ(s->st_mtim.tv_sec, (long) mtime); + ASSERT_GE(s->st_mtim.tv_sec, (long) mtime - 1); + ASSERT_LE(s->st_mtim.tv_sec, (long) mtime); + } else { + double st_mtim; + /* TODO(vtjnash): would it be better to normalize this? */ + if (!is_apple_or_sunpro_c) + ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); + st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; + ASSERT_DOUBLE_EQ(st_mtim, mtime); + } + } else if (isinf(mtime)) { + /* We test with timestamps that are in the distant past + * (if you're a Gen Z-er) so check it's more recent than that. + */ + ASSERT_GT(s->st_mtim.tv_sec, 1739710000); + } else { + ASSERT_OK(0); } uv_fs_req_cleanup(&req); @@ -1607,6 +1646,50 @@ TEST_IMPL(fs_fstat) { } +TEST_IMPL(fs_fstat_st_dev) { + uv_fs_t req; + uv_fs_t req_link; + uv_loop_t* loop = uv_default_loop(); + char* test_file = "tmp_st_dev"; + char* symlink_file = "tmp_st_dev_link"; + + unlink(test_file); + unlink(symlink_file); + + // Create file + int r = uv_fs_open(NULL, &req, test_file, UV_FS_O_RDWR | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); + uv_fs_req_cleanup(&req); + + // Create a symlink + r = uv_fs_symlink(loop, &req, test_file, symlink_file, 0, NULL); + ASSERT_EQ(r, 0); + uv_fs_req_cleanup(&req); + + // Call uv_fs_fstat for file + r = uv_fs_stat(loop, &req, test_file, NULL); + ASSERT_EQ(r, 0); + + // Call uv_fs_fstat for symlink + r = uv_fs_stat(loop, &req_link, symlink_file, NULL); + ASSERT_EQ(r, 0); + + // Compare st_dev + ASSERT_EQ(((uv_stat_t*)req.ptr)->st_dev, ((uv_stat_t*)req_link.ptr)->st_dev); + + // Cleanup + uv_fs_req_cleanup(&req); + uv_fs_req_cleanup(&req_link); + unlink(test_file); + unlink(symlink_file); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + + TEST_IMPL(fs_fstat_stdio) { int fd; int res; @@ -2684,13 +2767,46 @@ TEST_IMPL(fs_utime) { atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */ - r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL); - ASSERT_OK(r); + ASSERT_OK(uv_fs_utime(NULL, &req, path, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_utime(NULL, + &req, + path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_utime(NULL, + &req, + path, + UV_FS_UTIME_NOW, + UV_FS_UTIME_OMIT, + NULL)); ASSERT_OK(req.result); uv_fs_req_cleanup(&req); + check_utime(path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_utime(NULL, &req, path, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); check_utime(path, atime, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_utime(NULL, + &req, + path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_NOW, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 0); + atime = mtime = 1291404900.25; /* 2010-12-03 20:35:00.25 - mees <3 */ checkme.path = path; checkme.atime = atime; @@ -2824,9 +2940,43 @@ TEST_IMPL(fs_futime) { ASSERT_OK(req.result); #endif uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_futime(NULL, + &req, + file, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_futime(NULL, + &req, + file, + UV_FS_UTIME_NOW, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_futime(NULL, &req, file, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); check_utime(path, atime, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_futime(NULL, + &req, + file, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_NOW, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 0); + atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */ checkme.atime = atime; @@ -2888,20 +3038,50 @@ TEST_IMPL(fs_lutime) { /* Test the synchronous version. */ atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */ - checkme.atime = atime; - checkme.mtime = mtime; - checkme.path = symlink_path; - req.data = &checkme; - r = uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL); -#if (defined(_AIX) && !defined(_AIX71)) || \ - defined(__MVS__) +#if (defined(_AIX) && !defined(_AIX71)) || defined(__MVS__) ASSERT_EQ(r, UV_ENOSYS); RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1"); #endif ASSERT_OK(r); - lutime_cb(&req); - ASSERT_EQ(1, lutime_cb_count); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, + &req, + symlink_path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, + &req, + symlink_path, + UV_FS_UTIME_NOW, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, + &req, + symlink_path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_NOW, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 1); /* Test the asynchronous version. */ atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */ @@ -2909,11 +3089,12 @@ TEST_IMPL(fs_lutime) { checkme.atime = atime; checkme.mtime = mtime; checkme.path = symlink_path; + req.data = &checkme; r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb); ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT_EQ(2, lutime_cb_count); + ASSERT_EQ(1, lutime_cb_count); /* Cleanup. */ unlink(path); diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index c6651299c12c8d..0dea544699d75f 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -33,6 +33,7 @@ TEST_DECLARE (loop_stop_before_run) TEST_DECLARE (loop_update_time) TEST_DECLARE (loop_backend_timeout) TEST_DECLARE (loop_configure) +TEST_DECLARE (loop_init_oom) TEST_DECLARE (default_loop_close) TEST_DECLARE (barrier_1) TEST_DECLARE (barrier_2) @@ -53,7 +54,8 @@ TEST_DECLARE (tty_raw) TEST_DECLARE (tty_empty_write) TEST_DECLARE (tty_large_write) TEST_DECLARE (tty_raw_cancel) -TEST_DECLARE (tty_duplicate_vt100_fn_key) +TEST_DECLARE (tty_duplicate_vt100_fn_key_libuv) +TEST_DECLARE (tty_duplicate_vt100_fn_key_winvt) TEST_DECLARE (tty_duplicate_alt_modifier_key) TEST_DECLARE (tty_composing_character) TEST_DECLARE (tty_cursor_up) @@ -364,6 +366,7 @@ TEST_DECLARE (fs_mkdtemp) TEST_DECLARE (fs_mkstemp) TEST_DECLARE (fs_fstat) TEST_DECLARE (fs_fstat_stdio) +TEST_DECLARE (fs_fstat_st_dev) TEST_DECLARE (fs_access) TEST_DECLARE (fs_chmod) TEST_DECLARE (fs_copyfile) @@ -603,6 +606,7 @@ TASK_LIST_START TEST_ENTRY (loop_update_time) TEST_ENTRY (loop_backend_timeout) TEST_ENTRY (loop_configure) + TEST_ENTRY (loop_init_oom) TEST_ENTRY (default_loop_close) TEST_ENTRY (barrier_1) TEST_ENTRY (barrier_2) @@ -635,7 +639,8 @@ TASK_LIST_START TEST_ENTRY (tty_empty_write) TEST_ENTRY (tty_large_write) TEST_ENTRY (tty_raw_cancel) - TEST_ENTRY (tty_duplicate_vt100_fn_key) + TEST_ENTRY (tty_duplicate_vt100_fn_key_libuv) + TEST_ENTRY (tty_duplicate_vt100_fn_key_winvt) TEST_ENTRY (tty_duplicate_alt_modifier_key) TEST_ENTRY (tty_composing_character) TEST_ENTRY (tty_cursor_up) @@ -1083,6 +1088,7 @@ TASK_LIST_START TEST_ENTRY (fs_mkstemp) TEST_ENTRY (fs_fstat) TEST_ENTRY (fs_fstat_stdio) + TEST_ENTRY (fs_fstat_st_dev) TEST_ENTRY (fs_access) TEST_ENTRY (fs_chmod) TEST_ENTRY (fs_copyfile) diff --git a/deps/uv/test/test-loop-oom.c b/deps/uv/test/test-loop-oom.c new file mode 100644 index 00000000000000..5f5b58c9e561fd --- /dev/null +++ b/deps/uv/test/test-loop-oom.c @@ -0,0 +1,62 @@ +/* Copyright libuv contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + +static int limit; +static int alloc; + +static void* t_realloc(void* p, size_t n) { + alloc += n; + if (alloc > limit) + return NULL; + p = realloc(p, n); + ASSERT_NOT_NULL(p); + return p; +} + +static void* t_calloc(size_t m, size_t n) { + return t_realloc(NULL, m * n); +} + +static void* t_malloc(size_t n) { + return t_realloc(NULL, n); +} + +TEST_IMPL(loop_init_oom) { + uv_loop_t loop; + int err; + + ASSERT_OK(uv_replace_allocator(t_malloc, t_realloc, t_calloc, free)); + for (;;) { + err = uv_loop_init(&loop); + if (err == 0) + break; + ASSERT_EQ(err, UV_ENOMEM); + limit += 8; + alloc = 0; + } + ASSERT_OK(uv_loop_close(&loop)); + return 0; +} diff --git a/deps/uv/test/test-pipe-getsockname.c b/deps/uv/test/test-pipe-getsockname.c index cc345ccd86426c..3be30e674182f2 100644 --- a/deps/uv/test/test-pipe-getsockname.c +++ b/deps/uv/test/test-pipe-getsockname.c @@ -59,7 +59,7 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) { ASSERT_OK(r); if (*buf == '\0') { /* Linux abstract socket. */ - const char expected[] = "\0" TEST_PIPENAME; + const char expected[] = "\0" TEST_PIPENAME "\0"; ASSERT_EQ(len, sizeof(expected) - 1); ASSERT_MEM_EQ(buf, expected, len); } else { @@ -223,7 +223,7 @@ TEST_IMPL(pipe_getsockname) { TEST_IMPL(pipe_getsockname_abstract) { /* TODO(bnoordhuis) Use unique name, susceptible to concurrent test runs. */ - static const char name[] = "\0" TEST_PIPENAME; + static const char name[] = "\0" TEST_PIPENAME "\0"; #if defined(__linux__) char buf[256]; size_t buflen; diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c index d9b39c744ff16d..06a8e484dd78ec 100644 --- a/deps/uv/test/test-platform-output.c +++ b/deps/uv/test/test-platform-output.c @@ -236,21 +236,24 @@ TEST_IMPL(platform_output) { printf(" version: %s\n", uname.version); printf(" machine: %s\n", uname.machine); - ASSERT_OK(uv_getrusage_thread(&rusage)); - ASSERT_UINT64_GE(rusage.ru_utime.tv_sec, 0); - ASSERT_UINT64_GE(rusage.ru_utime.tv_usec, 0); - ASSERT_UINT64_GE(rusage.ru_stime.tv_sec, 0); - ASSERT_UINT64_GE(rusage.ru_stime.tv_usec, 0); - printf("uv_getrusage_thread:\n"); - printf(" user: %llu sec %llu microsec\n", - (unsigned long long) rusage.ru_utime.tv_sec, - (unsigned long long) rusage.ru_utime.tv_usec); - printf(" system: %llu sec %llu microsec\n", - (unsigned long long) rusage.ru_stime.tv_sec, - (unsigned long long) rusage.ru_stime.tv_usec); - printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt); - printf(" maximum resident set size: %llu\n", - (unsigned long long) rusage.ru_maxrss); + err = uv_getrusage_thread(&rusage); + if (err != UV_ENOTSUP) { + ASSERT_OK(err); + ASSERT_UINT64_GE(rusage.ru_utime.tv_sec, 0); + ASSERT_UINT64_GE(rusage.ru_utime.tv_usec, 0); + ASSERT_UINT64_GE(rusage.ru_stime.tv_sec, 0); + ASSERT_UINT64_GE(rusage.ru_stime.tv_usec, 0); + printf("uv_getrusage_thread:\n"); + printf(" user: %llu sec %llu microsec\n", + (unsigned long long) rusage.ru_utime.tv_sec, + (unsigned long long) rusage.ru_utime.tv_usec); + printf(" system: %llu sec %llu microsec\n", + (unsigned long long) rusage.ru_stime.tv_sec, + (unsigned long long) rusage.ru_stime.tv_usec); + printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt); + printf(" maximum resident set size: %llu\n", + (unsigned long long) rusage.ru_maxrss); + } return 0; } diff --git a/deps/uv/test/test-thread-name.c b/deps/uv/test/test-thread-name.c index 378d82cf81bc43..39340744290a0e 100644 --- a/deps/uv/test/test-thread-name.c +++ b/deps/uv/test/test-thread-name.c @@ -178,6 +178,10 @@ static void after_work_cb(uv_work_t* req, int status) { } TEST_IMPL(thread_name_threadpool) { + +#if defined(_AIX) || defined(__PASE__) + RETURN_SKIP("API not available on this platform"); +#endif uv_work_t req; loop = uv_default_loop(); // Just to make sure all workers will be executed diff --git a/deps/uv/test/test-tty-duplicate-key.c b/deps/uv/test/test-tty-duplicate-key.c index 871d580266ad8d..e3e813e69b3536 100644 --- a/deps/uv/test/test-tty-duplicate-key.c +++ b/deps/uv/test/test-tty-duplicate-key.c @@ -131,7 +131,7 @@ static void make_key_event_records(WORD virt_key, DWORD ctr_key_state, # undef KEV } -TEST_IMPL(tty_duplicate_vt100_fn_key) { +TEST_IMPL(tty_duplicate_vt100_fn_key_libuv) { int r; int ttyin_fd; uv_tty_t tty_in; @@ -163,6 +163,10 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) { r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read); ASSERT_OK(r); + /* + * libuv has chosen to emit ESC[[A, but other terminals, and even + * Windows itself use a different escape sequence, see the test below. + */ expect_str = ESC"[[A"; expect_nread = strlen(expect_str); @@ -184,6 +188,62 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) { return 0; } +TEST_IMPL(tty_duplicate_vt100_fn_key_winvt) { + int r; + int ttyin_fd; + uv_tty_t tty_in; + uv_loop_t* loop; + HANDLE handle; + INPUT_RECORD records[2]; + DWORD written; + + loop = uv_default_loop(); + + /* Make sure we have an FD that refers to a tty */ + handle = CreateFileA("conin$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); + ttyin_fd = _open_osfhandle((intptr_t) handle, 0); + ASSERT_GE(ttyin_fd, 0); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ + ASSERT_OK(r); + ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); + ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); + + r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read); + ASSERT_OK(r); + + /* + * Some keys, like F1, get are assigned a different value by Windows + * in ENABLE_VIRTUAL_TERMINAL_INPUT mode vs. libuv in the test above. + */ + expect_str = ESC"OP"; + expect_nread = strlen(expect_str); + + /* Turn on raw mode. */ + r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW_VT); + ASSERT_OK(r); + + /* + * Send F1 keystroke. + */ + make_key_event_records(VK_F1, 0, TRUE, records); + WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written); + ASSERT_EQ(written, ARRAY_SIZE(records)); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + TEST_IMPL(tty_duplicate_alt_modifier_key) { int r; int ttyin_fd; diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 8c8d7d00fd2913..540445f1f3249b 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -173,7 +173,7 @@ ], 'include_dirs': [ 'include' ], 'conditions': [ - ['OS == "linux"', { + ['OS == "linux" or OS=="openharmony"', { 'defines': [ '_POSIX_C_SOURCE=200112' ], }], ], @@ -190,7 +190,7 @@ '-Wno-unused-parameter', '-Wstrict-prototypes', ], - 'OTHER_CFLAGS': [ '-g', '--std=gnu89' ], + 'OTHER_CFLAGS': [ '-g', '--std=gnu11' ], }, 'conditions': [ [ 'OS=="win"', { @@ -255,14 +255,14 @@ }], ], }], - [ 'OS in "linux mac ios android zos"', { + [ 'OS in "linux mac ios android zos openharmony"', { 'sources': [ 'src/unix/proctitle.c' ], }], [ 'OS != "zos"', { 'cflags': [ '-fvisibility=hidden', '-g', - '--std=gnu89', + '--std=gnu11', '-Wall', '-Wextra', '-Wno-unused-parameter', @@ -279,7 +279,7 @@ '_DARWIN_UNLIMITED_SELECT=1', ] }], - [ 'OS=="linux"', { + [ 'OS=="linux" or OS=="openharmony"', { 'defines': [ '_GNU_SOURCE' ], 'sources': [ '<@(uv_sources_linux)', diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h index e9d0cc5a18a57b..2f7acd0e73fff6 100644 --- a/deps/v8/src/parsing/parser-base.h +++ b/deps/v8/src/parsing/parser-base.h @@ -1178,15 +1178,16 @@ class ParserBase { scope()->scope_type() == REPL_MODE_SCOPE) && !scope()->is_nonlinear()); } - bool IsNextUsingKeyword(Token::Value token_after_using, bool is_await_using) { + bool IsNextUsingKeyword(bool is_await_using) { // using and await using declarations in for-of statements must be followed - // by a non-pattern ForBinding. In the case of synchronous `using`, `of` is - // disallowed as well with a negative lookahead. + // by a non-pattern ForBinding. // // `of`: for ( [lookahead ≠ using of] ForDeclaration[?Yield, ?Await, +Using] // of AssignmentExpression[+In, ?Yield, ?Await] ) // // If `using` is not considered a keyword, it is parsed as an identifier. + Token::Value token_after_using = + is_await_using ? PeekAheadAhead() : PeekAhead(); if (v8_flags.js_explicit_resource_management) { switch (token_after_using) { case Token::kIdentifier: @@ -1201,7 +1202,16 @@ class ParserBase { case Token::kAsync: return true; case Token::kOf: - return is_await_using; + if (is_await_using) { + return true; + } else { + // In the case of synchronous `using`, `of` is disallowed as well + // with a negative lookahead for for-of loops. But, cursedly, + // `using of` is allowed as the initializer of C-style for loops, + // e.g. `for (using of = null;;)` parses. + Token::Value token_after_of = PeekAheadAhead(); + return token_after_of == Token::kAssign; + } case Token::kFutureStrictReservedWord: case Token::kEscapedStrictReservedWord: return is_sloppy(language_mode()); @@ -1220,12 +1230,12 @@ class ParserBase { // LineTerminator here] ForBinding[?Yield, +Await, ~Pattern] return ((peek() == Token::kUsing && !scanner()->HasLineTerminatorAfterNext() && - IsNextUsingKeyword(PeekAhead(), /* is_await_using */ false)) || + IsNextUsingKeyword(/* is_await_using */ false)) || (is_await_allowed() && peek() == Token::kAwait && !scanner()->HasLineTerminatorAfterNext() && PeekAhead() == Token::kUsing && !scanner()->HasLineTerminatorAfterNextNext() && - IsNextUsingKeyword(PeekAheadAhead(), /* is_await_using */ true))); + IsNextUsingKeyword(/* is_await_using */ true))); } const PendingCompilationErrorHandler* pending_error_handler() const { return pending_error_handler_; diff --git a/deps/v8/test/mjsunit/harmony/for-using-of-await-using-of.js b/deps/v8/test/mjsunit/harmony/for-using-of-await-using-of.js index 0877208fdbcee8..e990e517b1ac13 100644 --- a/deps/v8/test/mjsunit/harmony/for-using-of-await-using-of.js +++ b/deps/v8/test/mjsunit/harmony/for-using-of-await-using-of.js @@ -93,4 +93,6 @@ const reservedWords = for (using using of[]) {} for (using async of []) {} for (using foo of []) {} + // Cursedly, `using of` is a valid binding form in C-style for loops. + for (using of = null;;) break; })(); diff --git a/deps/zlib/zlib.gyp b/deps/zlib/zlib.gyp index 92e20b64b039ae..dcf6bdb67f6b92 100644 --- a/deps/zlib/zlib.gyp +++ b/deps/zlib/zlib.gyp @@ -75,7 +75,7 @@ ['OS=="android"', { 'defines': [ 'ARMV8_OS_ANDROID' ], }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'defines': [ 'ARMV8_OS_LINUX' ], }], ['OS=="mac"', { @@ -93,7 +93,7 @@ ['OS=="android"', { 'defines': [ 'ARMV8_OS_ANDROID' ], }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'defines': [ 'ARMV8_OS_LINUX' ], }], ['OS=="mac"', { diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 94663c8085c7a7..f340d5f912178f 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -1448,8 +1448,10 @@ instances of `ChildProcess`. added: v0.7.7 --> -* `code` {number} The exit code if the child process exited on its own. -* `signal` {string} The signal by which the child process was terminated. +* `code` {number} The exit code if the child process exited on its own, or + `null` if the child process terminated due to a signal. +* `signal` {string} The signal by which the child process was terminated, or + `null` if the child process did not terminated due to a signal. The `'close'` event is emitted after a process has ended _and_ the stdio streams of a child process have been closed. This is distinct from the @@ -1457,6 +1459,11 @@ streams of a child process have been closed. This is distinct from the streams. The `'close'` event will always emit after [`'exit'`][] was already emitted, or [`'error'`][] if the child process failed to spawn. +If the process exited, `code` is the final exit code of the process, otherwise +`null`. If the process terminated due to receipt of a signal, `signal` is the +string name of the signal, otherwise `null`. One of the two will always be +non-`null`. + ```cjs const { spawn } = require('node:child_process'); const ls = spawn('ls', ['-lh', '/usr']); @@ -1526,8 +1533,10 @@ See also [`subprocess.kill()`][] and [`subprocess.send()`][]. added: v0.1.90 --> -* `code` {number} The exit code if the child process exited on its own. -* `signal` {string} The signal by which the child process was terminated. +* `code` {number} The exit code if the child process exited on its own, or + `null` if the child process terminated due to a signal. +* `signal` {string} The signal by which the child process was terminated, or + `null` if the child process did not terminated due to a signal. The `'exit'` event is emitted after the child process ends. If the process exited, `code` is the final exit code of the process, otherwise `null`. If the @@ -1764,10 +1773,12 @@ setTimeout(() => { added: - v20.5.0 - v18.18.0 +changes: + - version: v24.2.0 + pr-url: https://github.com/nodejs/node/pull/58467 + description: No longer experimental. --> -> Stability: 1 - Experimental - Calls [`subprocess.kill()`][] with `'SIGTERM'`. ### `subprocess.killed` diff --git a/doc/api/cli.md b/doc/api/cli.md index 2b707496b5531c..660f80675d7797 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -194,6 +194,9 @@ process. -Enable [Source Map v3][Source Map] support for stack traces. +Enable [Source Map][] support for stack traces. When using a transpiler, such as TypeScript, stack traces thrown by an application reference the transpiled code, not the original source position. @@ -931,11 +931,19 @@ in the `$schema` must be replaced with the version of Node.js you are using. ], "watch-path": "src", "watch-preserve-output": true + }, + "testRunner": { + "test-isolation": "process" } } ``` -In the `nodeOptions` field, only flags that are allowed in [`NODE_OPTIONS`][] are supported. +The configuration file supports namespace-specific options: + +* The `nodeOptions` field contains CLI flags that are allowed in [`NODE_OPTIONS`][]. + +* Namespace fields like `testRunner` contain configuration specific to that subsystem. + No-op flags are not supported. Not all V8 flags are currently supported. @@ -949,7 +957,7 @@ For example, the configuration file above is equivalent to the following command-line arguments: ```bash -node --import amaro/strip --watch-path=src --watch-preserve-output +node --import amaro/strip --watch-path=src --watch-preserve-output --test-isolation=process ``` The priority in configuration is as follows: @@ -962,11 +970,10 @@ Values in the configuration file will not override the values in the environment variables and command-line options, but will override the values in the `NODE_OPTIONS` env file parsed by the `--env-file` flag. -If duplicate keys are present in the configuration file, only -the first key will be used. +Keys cannot be duplicated within the same or different namespaces. The configuration parser will throw an error if the configuration file contains -unknown keys or keys that cannot used in `NODE_OPTIONS`. +unknown keys or keys that cannot be used in a namespace. Node.js will not sanitize or perform validation on the user-provided configuration, so **NEVER** use untrusted configuration files. @@ -2574,8 +2581,9 @@ added: Test suite shard to execute in a format of `/`, where -`index` is a positive integer, index of divided parts -`total` is a positive integer, total of divided part +* `index` is a positive integer, index of divided parts. +* `total` is a positive integer, total of divided part. + This command will divide all tests files into `total` equal parts, and will run only those that happen to be in an `index` part. @@ -2621,7 +2629,7 @@ changes: - v23.4.0 - v22.13.0 pr-url: https://github.com/nodejs/node/pull/55897 - description: Snapsnot testing is no longer experimental. + description: Snapshot testing is no longer experimental. --> Regenerates the snapshot files used by the test runner for [snapshot testing][]. @@ -3076,6 +3084,10 @@ Use `--watch-path` to specify what paths to watch. This flag cannot be combined with `--check`, `--eval`, `--interactive`, or the REPL. +Note: The `--watch` flag requires a file path as an argument and is incompatible +with `--run` or inline script input, as `--run` takes precedence and ignores watch +mode. If no file is provided, Node.js will exit with status code `9`. + ```bash node --watch index.js ``` @@ -3103,6 +3115,9 @@ combination with `--watch`. This flag cannot be combined with `--check`, `--eval`, `--interactive`, `--test`, or the REPL. +Note: Using `--watch-path` implicitly enables `--watch`, which requires a file path +and is incompatible with `--run`, as `--run` takes precedence and ignores watch mode. + ```bash node --watch-path=./src --watch-path=./tests index.js ``` @@ -3872,7 +3887,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12 [REPL]: repl.md [ScriptCoverage]: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ScriptCoverage [ShadowRealm]: https://github.com/tc39/proposal-shadowrealm -[Source Map]: https://sourcemaps.info/spec.html +[Source Map]: https://tc39.es/ecma426/ [TypeScript type-stripping]: typescript.md#type-stripping [V8 Inspector integration for Node.js]: debugger.md#v8-inspector-integration-for-nodejs [V8 JavaScript code coverage]: https://v8project.blogspot.com/2017/12/javascript-code-coverage.html diff --git a/doc/api/crypto.md b/doc/api/crypto.md index eb7fa2a01602f8..c73cb1894d174f 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -2651,7 +2651,23 @@ added: v15.6.0 * `otherCert` {X509Certificate} * Returns: {boolean} -Checks whether this certificate was issued by the given `otherCert`. +Checks whether this certificate was potentially issued by the given `otherCert` +by comparing the certificate metadata. + +This is useful for pruning a list of possible issuer certificates which have been +selected using a more rudimentary filtering routine, i.e. just based on subject +and issuer names. + +Finally, to verify that this certificate's signature was produced by a private key +corresponding to `otherCert`'s public key use [`x509.verify(publicKey)`][] +with `otherCert`'s public key represented as a [`KeyObject`][] +like so + +```js +if (!x509.verify(otherCert.publicKey)) { + throw new Error('otherCert did not issue x509'); +} +``` ### `x509.checkPrivateKey(privateKey)` @@ -6205,6 +6221,7 @@ See the [list of SSL OP Flags][] for details. [`verify.update()`]: #verifyupdatedata-inputencoding [`verify.verify()`]: #verifyverifyobject-signature-signatureencoding [`x509.fingerprint256`]: #x509fingerprint256 +[`x509.verify(publicKey)`]: #x509verifypublickey [caveats when using strings as inputs to cryptographic APIs]: #using-strings-as-inputs-to-cryptographic-apis [certificate object]: tls.md#certificate-object [encoding]: buffer.md#buffers-and-character-encodings diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 59ccb616adae1d..75cd84818cdece 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -2950,12 +2950,15 @@ upon `require('node:module').builtinModules`. -Type: Runtime +Type: End-of-Life `Transform._transformState` will be removed in future versions where it is no longer required due to simplification of the implementation. @@ -3897,10 +3900,108 @@ of built-in modules. This was incomplete and matched the already deprecated `repl._builtinLibs` ([DEP0142][]) instead it's better to rely upon `require('node:module').builtinModules`. +### DEP0192: `require('node:_tls_common')` and `require('node:_tls_wrap')` + + + +Type: Documentation-only + +The `node:_tls_common` and `node:_tls_wrap` modules are deprecated as they should be considered +an internal nodejs implementation rather than a public facing API, use `node:tls` instead. + +### DEP0193: `require('node:_stream_*')` + + + +Type: Documentation-only + +The `node:_stream_duplex`, `node:_stream_passthrough`, `node:_stream_readable`, `node:_stream_transform`, +`node:_stream_wrap` and `node:_stream_writable` modules are deprecated as they should be considered +an internal nodejs implementation rather than a public facing API, use `node:stream` instead. + +### DEP0194: HTTP/2 priority signaling + + + +Type: End-of-Life + +The support for priority signaling has been removed following its deprecation in the [RFC 9113][]. + +### DEP0195: Instantiating `node:http` classes without `new` + + + +Type: Documentation-only + +Instantiating classes without the `new` qualifier exported by the `node:http` module is deprecated. +It is recommended to use the `new` qualifier instead. This applies to all http classes, such as +`OutgoingMessage`, `IncomingMessage`, `ServerResponse` and `ClientRequest`. + +### DEP0196: Calling `node:child_process` functions with `options.shell` as an empty string + + + +Type: Documentation-only + +Calling the process-spawning functions with `{ shell: '' }` is almost certainly +unintentional, and can cause aberrant behavior. + +To make [`child_process.execFile`][] or [`child_process.spawn`][] invoke the +default shell, use `{ shell: true }`. If the intention is not to invoke a shell +(default behavior), either omit the `shell` option, or set it to `false` or a +nullish value. + +To make [`child_process.exec`][] invoke the default shell, either omit the +`shell` option, or set it to a nullish value. If the intention is not to invoke +a shell, use [`child_process.execFile`][] instead. + +### DEP0197: `util.types.isNativeError()` + + + +Type: Documentation-only + +The [`util.types.isNativeError`][] API is deprecated. Please use [`Error.isError`][] instead. + [DEP0142]: #dep0142-repl_builtinlibs [NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf [RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3 [RFC 8247 Section 2.4]: https://www.rfc-editor.org/rfc/rfc8247#section-2.4 +[RFC 9113]: https://datatracker.ietf.org/doc/html/rfc9113#section-5.3.1 [WHATWG URL API]: url.md#the-whatwg-url-api [`"exports"` or `"main"` entry]: packages.md#main-entry-point-export [`'uncaughtException'`]: process.md#event-uncaughtexception @@ -3914,6 +4015,7 @@ upon `require('node:module').builtinModules`. [`Buffer.isBuffer()`]: buffer.md#static-method-bufferisbufferobj [`Cipheriv`]: crypto.md#class-cipheriv [`Decipheriv`]: crypto.md#class-decipheriv +[`Error.isError`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/isError [`REPLServer.clearBufferedCommand()`]: repl.md#replserverclearbufferedcommand [`ReadStream.open()`]: fs.md#class-fsreadstream [`Server.getConnections()`]: net.md#servergetconnectionscallback @@ -3926,6 +4028,7 @@ upon `require('node:module').builtinModules`. [`asyncResource.runInAsyncScope()`]: async_context.md#asyncresourceruninasyncscopefn-thisarg-args [`buffer.subarray`]: buffer.md#bufsubarraystart-end [`child_process.execFile`]: child_process.md#child_processexecfilefile-args-options-callback +[`child_process.exec`]: child_process.md#child_processexeccommand-options-callback [`child_process.spawn`]: child_process.md#child_processspawncommand-args-options [`child_process`]: child_process.md [`clearInterval()`]: timers.md#clearintervaltimeout @@ -4028,6 +4131,7 @@ upon `require('node:module').builtinModules`. [`util.isArray()`]: util.md#utilisarrayobject [`util.promisify`]: util.md#utilpromisifyoriginal [`util.toUSVString()`]: util.md#utiltousvstringstring +[`util.types.isNativeError`]: util.md#utiltypesisnativeerrorvalue [`util.types`]: util.md#utiltypes [`util`]: util.md [`worker.exitedAfterDisconnect`]: cluster.md#workerexitedafterdisconnect diff --git a/doc/api/dgram.md b/doc/api/dgram.md index f3f34dbb9cbb4e..8ea655f645bc4d 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -380,10 +380,12 @@ provided, it is added as a listener for the [`'close'`][] event. added: - v20.5.0 - v18.18.0 +changes: + - version: v24.2.0 + pr-url: https://github.com/nodejs/node/pull/58467 + description: No longer experimental. --> -> Stability: 1 - Experimental - Calls [`socket.close()`][] and returns a promise that fulfills when the socket has closed. diff --git a/doc/api/diagnostics_channel.md b/doc/api/diagnostics_channel.md index aef7f3e6ec88e4..5ba16796b06dae 100644 --- a/doc/api/diagnostics_channel.md +++ b/doc/api/diagnostics_channel.md @@ -1217,6 +1217,57 @@ Emitted when a stream is created on the client. Emitted when a stream is started on the client. +`http2.client.stream.error` + +* `stream` {ClientHttp2Stream} +* `error` {Error} + +Emitted when an error occurs during the processing of a stream on the client. + +`http2.client.stream.finish` + +* `stream` {ClientHttp2Stream} +* `headers` {HTTP/2 Headers Object} +* `flags` {number} + +Emitted when a stream is received on the client. + +`http2.client.stream.close` + +* `stream` {ClientHttp2Stream} + +Emitted when a stream is closed on the client. The HTTP/2 error code used when +closing the stream can be retrieved using the `stream.rstCode` property. + +`http2.server.stream.created` + +* `stream` {ServerHttp2Stream} +* `headers` {HTTP/2 Headers Object} + +Emitted when a stream is created on the server. + +`http2.server.stream.start` + +* `stream` {ServerHttp2Stream} +* `headers` {HTTP/2 Headers Object} + +Emitted when a stream is started on the server. + +`http2.server.stream.error` + +* `stream` {ServerHttp2Stream} +* `error` {Error} + +Emitted when an error occurs during the processing of a stream on the server. + +`http2.server.stream.finish` + +* `stream` {ServerHttp2Stream} +* `headers` {HTTP/2 Headers Object} +* `flags` {number} + +Emitted when a stream is sent on the server. + #### Modules > Stability: 1 - Experimental @@ -1277,9 +1328,9 @@ Emitted when a `import()` throws an error. See [`error` event][]. `net.client.socket` -* `socket` {net.Socket} +* `socket` {net.Socket|tls.TLSSocket} -Emitted when a new TCP or pipe client socket is created. +Emitted when a new TCP or pipe client socket connection is created. `net.server.socket` diff --git a/doc/api/errors.md b/doc/api/errors.md index ccf8d16655cec4..6023d21690fa02 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -1796,8 +1796,6 @@ time. ### `ERR_INPUT_TYPE_NOT_ALLOWED` -> Stability: 1 - Experimental - The `--input-type` flag was used to attempt to execute a file. This flag can only be used with input via `--eval`, `--print`, or `STDIN`. @@ -3012,6 +3010,15 @@ category. The `node:trace_events` module could not be loaded because Node.js was compiled with the `--without-v8-platform` flag. + + +### `ERR_TRAILING_JUNK_AFTER_STREAM_END` + +Trailing junk found after the end of the compressed stream. +This error is thrown when extra, unexpected data is detected +after the end of a compressed stream (for example, in zlib +or gzip decompression). + ### `ERR_TRANSFORM_ALREADY_TRANSFORMING` @@ -3084,8 +3091,6 @@ An invalid or unknown encoding option was passed to an API. ### `ERR_UNKNOWN_FILE_EXTENSION` -> Stability: 1 - Experimental - An attempt was made to load a module with an unknown or unsupported file extension. @@ -3093,8 +3098,6 @@ extension. ### `ERR_UNKNOWN_MODULE_FORMAT` -> Stability: 1 - Experimental - An attempt was made to load a module with an unknown or unsupported format. @@ -3172,8 +3175,6 @@ transformation with [type-stripping][]. ### `ERR_USE_AFTER_CLOSE` -> Stability: 1 - Experimental - An attempt was made to use something that was already closed. diff --git a/doc/api/esm.md b/doc/api/esm.md index b3b061b2bb05be..4f717acda00575 100644 --- a/doc/api/esm.md +++ b/doc/api/esm.md @@ -396,6 +396,35 @@ import { readFileSync } from 'node:fs'; const buffer = readFileSync(new URL('./data.proto', import.meta.url)); ``` +### `import.meta.main` + + + +> Stability: 1.0 - Early development + +* {boolean} `true` when the current module is the entry point of the current process; `false` otherwise. + +Equivalent to `require.main === module` in CommonJS. + +Analogous to Python's `__name__ == "__main__"`. + +```js +export function foo() { + return 'Hello, world'; +} + +function main() { + const message = foo(); + console.log(message); +} + +if (import.meta.main) main(); +// `foo` can be imported from another module without possible side-effects from `main` +``` + ### `import.meta.resolve(specifier)` +* `options` {Object} + * `autoClose` {boolean} When true, causes the {FileHandle} to be closed when the + stream is closed. **Default:** `false` * Returns: {ReadableStream} Returns a byte-oriented `ReadableStream` that may be used to read the file's @@ -859,11 +865,14 @@ the end of the file. added: - v20.4.0 - v18.18.0 +changes: + - version: v24.2.0 + pr-url: https://github.com/nodejs/node/pull/58467 + description: No longer experimental. --> -> Stability: 1 - Experimental - -An alias for `filehandle.close()`. +Calls `filehandle.close()` and returns a promise that fulfills when the +filehandle is closed. ### `fsPromises.access(path[, mode])` @@ -6749,21 +6758,26 @@ included in the iteration results. -> Stability: 1 - Experimental +Calls `dir.close()` and returns a promise that fulfills when the +dir is closed. -An alias for `dir.close()`. - -#### `dir[Symbol.Dispose]()` +#### `dir[Symbol.dispose]()` -> Stability: 1 - Experimental - -An alias for `dir.closeSync()`. +Calls `dir.closeSync()` and returns `undefined`. ### Class: `fs.Dirent` diff --git a/doc/api/http.md b/doc/api/http.md index 6c42ea08a72f5d..21d8f412af303f 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -1936,10 +1936,12 @@ affects new connections to the server, not any existing connections. -> Stability: 1 - Experimental - Calls [`server.close()`][] and returns a promise that fulfills when the server has closed. diff --git a/doc/api/http2.md b/doc/api/http2.md index dc741338781bce..82f34034fe3577 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -1071,6 +1071,15 @@ The `'origin'` event is only emitted when using a secure TLS connection. * `headers` {HTTP/2 Headers Object} | {Array} @@ -1085,9 +1094,6 @@ added: v8.4.0 **Default:** `false`. * `parent` {number} Specifies the numeric identifier of a stream the newly created stream is dependent on. - * `weight` {number} Specifies the relative dependency of a stream in relation - to other streams with the same `parent`. The value is a number between `1` - and `256` (inclusive). * `waitForTrailers` {boolean} When `true`, the `Http2Stream` will emit the `'wantTrailers'` event after the final `DATA` frame has been sent. * `signal` {AbortSignal} An AbortSignal that may be used to abort an ongoing @@ -1457,22 +1463,18 @@ numeric stream identifier. -* `options` {Object} - * `exclusive` {boolean} When `true` and `parent` identifies a parent Stream, - this stream is made the sole direct dependency of the parent, with - all other existing dependents made a dependent of this stream. **Default:** - `false`. - * `parent` {number} Specifies the numeric identifier of a stream this stream - is dependent on. - * `weight` {number} Specifies the relative dependency of a stream in relation - to other streams with the same `parent`. The value is a number between `1` - and `256` (inclusive). - * `silent` {boolean} When `true`, changes the priority locally without - sending a `PRIORITY` frame to the connected peer. - -Updates the priority for this `Http2Stream` instance. +> Stability: 0 - Deprecated: support for priority signaling has been deprecated +> in the [RFC 9113][] and is no longer supported in Node.js. + +Empty method, only there to maintain some backward compatibility. #### `http2stream.rstCode` @@ -1568,6 +1570,15 @@ req.setTimeout(5000, () => req.close(NGHTTP2_CANCEL)); Provides miscellaneous information about the current state of the @@ -1581,10 +1592,8 @@ Provides miscellaneous information about the current state of the * `localClose` {number} `1` if this `Http2Stream` has been closed locally. * `remoteClose` {number} `1` if this `Http2Stream` has been closed remotely. - * `sumDependencyWeight` {number} The sum weight of all `Http2Stream` - instances that depend on this `Http2Stream` as specified using - `PRIORITY` frames. - * `weight` {number} The priority weight of this `Http2Stream`. + * `sumDependencyWeight` {number} Legacy property, always set to `0`. + * `weight` {number} Legacy property, always set to `16`. A current state of this `Http2Stream`. @@ -2421,10 +2430,12 @@ closed, although the server has already stopped allowing new sessions. See -> Stability: 1 - Experimental - Calls [`server.close()`][] and returns a promise that fulfills when the server has closed. @@ -2899,6 +2910,10 @@ changes: a server should wait when an [`'unknownProtocol'`][] is emitted. If the socket has not been destroyed by that time the server will destroy it. **Default:** `10000`. + * `strictFieldWhitespaceValidation` {boolean} If `true`, it turns on strict leading + and trailing whitespace validation for HTTP/2 header field names and values + as per [RFC-9113](https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.1). + **Default:** `true`. * ...: Any [`net.createServer()`][] option can be provided. * `onRequestHandler` {Function} See [Compatibility API][] * Returns: {Http2Server} @@ -3070,6 +3085,10 @@ changes: a server should wait when an [`'unknownProtocol'`][] event is emitted. If the socket has not been destroyed by that time the server will destroy it. **Default:** `10000`. + * `strictFieldWhitespaceValidation` {boolean} If `true`, it turns on strict leading + and trailing whitespace validation for HTTP/2 header field names and values + as per [RFC-9113](https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.1). + **Default:** `true`. * `onRequestHandler` {Function} See [Compatibility API][] * Returns: {Http2SecureServer} @@ -3225,6 +3244,10 @@ changes: a server should wait when an [`'unknownProtocol'`][] event is emitted. If the socket has not been destroyed by that time the server will destroy it. **Default:** `10000`. + * `strictFieldWhitespaceValidation` {boolean} If `true`, it turns on strict leading + and trailing whitespace validation for HTTP/2 header field names and values + as per [RFC-9113](https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.1). + **Default:** `true`. * `listener` {Function} Will be registered as a one-time listener of the [`'connect'`][] event. * Returns: {ClientHttp2Session} @@ -4881,6 +4904,7 @@ you need to implement any fall-back behavior yourself. [RFC 7838]: https://tools.ietf.org/html/rfc7838 [RFC 8336]: https://tools.ietf.org/html/rfc8336 [RFC 8441]: https://tools.ietf.org/html/rfc8441 +[RFC 9113]: https://datatracker.ietf.org/doc/html/rfc9113#section-5.3.1 [Sensitive headers]: #sensitive-headers [`'checkContinue'`]: #event-checkcontinue [`'connect'`]: #event-connect diff --git a/doc/api/https.md b/doc/api/https.md index 18ab7ec186e5e1..f7e52ec99ab42a 100644 --- a/doc/api/https.md +++ b/doc/api/https.md @@ -137,10 +137,12 @@ See [`server.close()`][] in the `node:http` module. -> Stability: 1 - Experimental - Calls [`server.close()`][httpsServerClose] and returns a promise that fulfills when the server has closed. diff --git a/doc/api/inspector.md b/doc/api/inspector.md index abb1b81ca699d3..a4b276030b4c32 100644 --- a/doc/api/inspector.md +++ b/doc/api/inspector.md @@ -511,6 +511,19 @@ inspector.Network.requestWillBeSent({ }); ``` +### `inspector.Network.dataReceived([params])` + + + +* `params` {Object} + +This feature is only available with the `--experimental-network-inspection` flag enabled. + +Broadcasts the `Network.dataReceived` event to connected frontends, or buffers the data if +`Network.streamResourceContent` command was not invoked for the given request yet. + ### `inspector.Network.requestWillBeSent([params])` diff --git a/doc/api/net.md b/doc/api/net.md index 5b0a5dfee2e52f..217c2bc63777e4 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -402,10 +402,12 @@ was not open when it was closed. added: - v20.5.0 - v18.18.0 +changes: + - version: v24.2.0 + pr-url: https://github.com/nodejs/node/pull/58467 + description: No longer experimental. --> -> Stability: 1 - Experimental - Calls [`server.close()`][] and returns a promise that fulfills when the server has closed. diff --git a/doc/api/perf_hooks.md b/doc/api/perf_hooks.md index 01963535c47852..5af5cc3ab9c6e1 100644 --- a/doc/api/perf_hooks.md +++ b/doc/api/perf_hooks.md @@ -1973,6 +1973,23 @@ added: v11.10.0 Enables the update interval timer. Returns `true` if the timer was started, `false` if it was already started. +### `histogram[Symbol.dispose]()` + + + +Disables the update interval timer when the histogram is disposed. + +```js +const { monitorEventLoopDelay } = require('node:perf_hooks'); +{ + using hist = monitorEventLoopDelay({ resolution: 20 }); + hist.enable(); + // The histogram will be disabled when the block is exited. +} +``` + ### Cloning an `IntervalHistogram` {IntervalHistogram} instances can be cloned via {MessagePort}. On the receiving diff --git a/doc/api/permissions.md b/doc/api/permissions.md index 8c226f638a6902..132dc681351cde 100644 --- a/doc/api/permissions.md +++ b/doc/api/permissions.md @@ -104,6 +104,23 @@ $ node --permission --allow-fs-read=* --allow-fs-write=* index.js Hello world! ``` +By default the entrypoints of your application are included +in the allowed file system read list. For example: + +```console +$ node --permission index.js +``` + +* `index.js` will be included in the allowed file system read list + +```console +$ node -r /path/to/custom-require.js --permission index.js. +``` + +* `/path/to/custom-require.js` will be included in the allowed file system read + list. +* `index.js` will be included in the allowed file system read list. + The valid arguments for both flags are: * `*` - To allow all `FileSystemRead` or `FileSystemWrite` operations, diff --git a/doc/api/process.md b/doc/api/process.md index 71b8727f1a8c05..4a3ecd3e30b552 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -982,6 +982,26 @@ $ bash -c 'exec -a customArgv0 ./node' 'customArgv0' ``` +## `process.availableMemory()` + + + +* {number} + +Gets the amount of free memory that is still available to the process +(in bytes). + +See [`uv_get_available_memory`][uv_get_available_memory] for more +information. + ## `process.channel` - -* {number} - -Gets the amount of free memory that is still available to the process -(in bytes). - -See [`uv_get_available_memory`][uv_get_available_memory] for more -information. - ## `process.cpuUsage([previousValue])` + +> Stability: 1 - Experimental + +* `file` {string} The name or path of the executable file to run. +* `args` {string\[]} List of string arguments. No argument can contain a null-byte (`\u0000`). +* `env` {Object} Environment key-value pairs. + No key or value can contain a null-byte (`\u0000`). + **Default:** `process.env`. + +Replaces the current process with a new process. + +This is achieved by using the `execve` POSIX function and therefore no memory or other +resources from the current process are preserved, except for the standard input, +standard output and standard error file descriptor. + +All other resources are discarded by the system when the processes are swapped, without triggering +any exit or close events and without running any cleanup handler. + +This function will never return, unless an error occurred. + +This function is not available on Windows or IBM i. + ## `process.exit([code])` - -> Stability: 1 - Experimental - -* `file` {string} The name or path of the executable file to run. -* `args` {string\[]} List of string arguments. No argument can contain a null-byte (`\u0000`). -* `env` {Object} Environment key-value pairs. - No key or value can contain a null-byte (`\u0000`). - **Default:** `process.env`. - -Replaces the current process with a new process. - -This is achieved by using the `execve` POSIX function and therefore no memory or other -resources from the current process are preserved, except for the standard input, -standard output and standard error file descriptor. - -All other resources are discarded by the system when the processes are swapped, without triggering -any exit or close events and without running any cleanup handler. - -This function will never return, unless an error occurred. - -This function is not available on Windows or IBM i. - ## `process.report` -* `historyPath` {string} the path to the history file +* `historyConfig` {Object|string} the path to the history file + If it is a string, it is the path to the history file. + If it is an object, it can have the following properties: + * `filePath` {string} the path to the history file + * `size` {number} Maximum number of history lines retained. To disable + the history set this value to `0`. This option makes sense only if + `terminal` is set to `true` by the user or by an internal `output` check, + otherwise the history caching mechanism is not initialized at all. + **Default:** `30`. + * `removeHistoryDuplicates` {boolean} If `true`, when a new input line added + to the history list duplicates an older one, this removes the older line + from the list. **Default:** `false`. + * `onHistoryFileLoaded` {Function} called when history writes are ready or upon error + * `err` {Error} + * `repl` {repl.REPLServer} * `callback` {Function} called when history writes are ready or upon error + (Optional if provided as `onHistoryFileLoaded` in `historyConfig`) * `err` {Error} * `repl` {repl.REPLServer} diff --git a/doc/api/sqlite.md b/doc/api/sqlite.md index 00668f15d90c32..7bdd85b51bc5ef 100644 --- a/doc/api/sqlite.md +++ b/doc/api/sqlite.md @@ -416,10 +416,12 @@ targetDb.applyChangeset(changeset); added: - v23.11.0 - v22.15.0 +changes: + - version: v24.2.0 + pr-url: https://github.com/nodejs/node/pull/58467 + description: No longer experimental. --> -> Stability: 1 - Experimental - Closes the database connection. If the database connection is already closed then this is a no-op. diff --git a/doc/api/stream.md b/doc/api/stream.md index 73426e22466085..a088d4e00298f0 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -983,10 +983,12 @@ Getter for the property `objectMode` of a given `Writable` stream. added: - v22.4.0 - v20.16.0 +changes: + - version: v24.2.0 + pr-url: https://github.com/nodejs/node/pull/58467 + description: No longer experimental. --> -> Stability: 1 - Experimental - Calls [`writable.destroy()`][writable-destroy] with an `AbortError` and returns a promise that fulfills when the stream is finished. @@ -1996,10 +1998,12 @@ has less then 64 KiB of data because no `highWaterMark` option is provided to added: - v20.4.0 - v18.18.0 +changes: + - version: v24.2.0 + pr-url: https://github.com/nodejs/node/pull/58467 + description: No longer experimental. --> -> Stability: 1 - Experimental - Calls [`readable.destroy()`][readable-destroy] with an `AbortError` and returns a promise that fulfills when the stream is finished. diff --git a/doc/api/test.md b/doc/api/test.md index 154d11424f194e..76762c07c35fbd 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -986,7 +986,7 @@ added: v22.3.0 changes: - version: v23.4.0 pr-url: https://github.com/nodejs/node/pull/55897 - description: Snapsnot testing is no longer experimental. + description: Snapshot testing is no longer experimental. --> Snapshot tests allow arbitrary values to be serialized into string values and @@ -1121,6 +1121,9 @@ const customReporter = new Transform({ case 'test:watch:drained': callback(null, 'test watch queue drained'); break; + case 'test:watch:restarted': + callback(null, 'test watch restarted due to file change'); + break; case 'test:start': callback(null, `test ${event.data.name} started`); break; @@ -1166,6 +1169,9 @@ const customReporter = new Transform({ case 'test:watch:drained': callback(null, 'test watch queue drained'); break; + case 'test:watch:restarted': + callback(null, 'test watch restarted due to file change'); + break; case 'test:start': callback(null, `test ${event.data.name} started`); break; @@ -1210,6 +1216,9 @@ export default async function * customReporter(source) { case 'test:watch:drained': yield 'test watch queue drained\n'; break; + case 'test:watch:restarted': + yield 'test watch restarted due to file change\n'; + break; case 'test:start': yield `test ${event.data.name} started\n`; break; @@ -1250,6 +1259,9 @@ module.exports = async function * customReporter(source) { case 'test:watch:drained': yield 'test watch queue drained\n'; break; + case 'test:watch:restarted': + yield 'test watch restarted due to file change\n'; + break; case 'test:start': yield `test ${event.data.name} started\n`; break; @@ -3016,6 +3028,11 @@ defined. The corresponding declaration ordered event is `'test:start'`. `undefined` if the test was run through the REPL. * `message` {string} The diagnostic message. * `nesting` {number} The nesting level of the test. + * `level` {string} The severity level of the diagnostic message. + Possible values are: + * `'info'`: Informational messages. + * `'warn'`: Warnings. + * `'error'`: Errors. Emitted when [`context.diagnostic`][] is called. This event is guaranteed to be emitted in the same order as the tests are @@ -3170,6 +3187,10 @@ generated for each test file in addition to a final cumulative summary. Emitted when no more tests are queued for execution in watch mode. +### Event: `'test:watch:restarted'` + +Emitted when one or more tests are restarted due to a file change in watch mode. + ## Class: `TestContext` -> Stability: 1 - Experimental - Cancels the immediate. This is similar to calling `clearImmediate()`. ## Class: `Timeout` @@ -175,10 +177,12 @@ thread. This allows enhanced compatibility with browser added: - v20.5.0 - v18.18.0 +changes: + - version: v24.2.0 + pr-url: https://github.com/nodejs/node/pull/58467 + description: No longer experimental. --> -> Stability: 1 - Experimental - Cancels the timeout. ## Scheduling timers diff --git a/doc/api/url.md b/doc/api/url.md index 6f7e373653c5e8..9e4b46db3871a0 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -1040,7 +1040,7 @@ Returns an ES6 `Iterator` over each of the name-value pairs in the query. Each item of the iterator is a JavaScript `Array`. The first item of the `Array` is the `name`, the second item of the `Array` is the `value`. -Alias for [`urlSearchParams[@@iterator]()`][`urlSearchParams@@iterator()`]. +Alias for [`urlSearchParams[Symbol.iterator]()`][`urlSearchParamsSymbol.iterator()`]. #### `urlSearchParams.forEach(fn[, thisArg])` @@ -1965,7 +1965,7 @@ console.log(myURL.origin); [`url.toJSON()`]: #urltojson [`url.toString()`]: #urltostring [`urlSearchParams.entries()`]: #urlsearchparamsentries -[`urlSearchParams@@iterator()`]: #urlsearchparamssymboliterator +[`urlSearchParamsSymbol.iterator()`]: #urlsearchparamssymboliterator [converted to a string]: https://tc39.es/ecma262/#sec-tostring [examples of parsed URLs]: https://url.spec.whatwg.org/#example-url-parsing [host name spoofing]: https://hackerone.com/reports/678487 diff --git a/doc/api/util.md b/doc/api/util.md index 413b05cb5d9694..ea10778edb2d08 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -973,8 +973,8 @@ The `util.inspect()` method returns a string representation of `object` that is intended for debugging. The output of `util.inspect` may change at any time and should not be depended upon programmatically. Additional `options` may be passed that alter the result. -`util.inspect()` will use the constructor's name and/or `@@toStringTag` to make -an identifiable tag for an inspected value. +`util.inspect()` will use the constructor's name and/or `Symbol.toStringTag` +property to make an identifiable tag for an inspected value. ```js class Foo { @@ -1884,7 +1884,7 @@ console.log(params.toString()); Returns an iterator over the values of each name-value pair. -### `mimeParams[@@iterator]()` +### `mimeParams[Symbol.iterator]()` * Returns: {Iterator} @@ -2408,6 +2408,9 @@ added: - v21.7.0 - v20.12.0 changes: + - version: v24.2.0 + pr-url: https://github.com/nodejs/node/pull/58437 + description: Added the `'none'` format as a non-op format. - version: - v23.5.0 - v22.13.0 @@ -2483,6 +2486,8 @@ console.log( ); ``` +The special format value `none` applies no additional styling to the text. + The full list of formats can be found in [modifiers][]. ## Class: `util.TextDecoder` @@ -3319,8 +3324,14 @@ util.types.isModuleNamespaceObject(ns); // Returns true +> Stability: 0 - Deprecated: Use [`Error.isError`][] instead. + +**Note:** As of Node.js v24, `Error.isError()` is currently slower than `util.types.isNativeError()`. +If performance is critical, consider benchmarking both in your environment. + * `value` {any} * Returns: {boolean} @@ -3707,6 +3718,7 @@ util.isArray({}); [`'warning'`]: process.md#event-warning [`Array.isArray()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray [`ArrayBuffer.isView()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/isView +[`Error.isError`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/isError [`JSON.stringify()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify [`MIMEparams`]: #class-utilmimeparams [`Object.assign()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign diff --git a/doc/api/worker_threads.md b/doc/api/worker_threads.md index 40d22d337553cb..517a1546a041d3 100644 --- a/doc/api/worker_threads.md +++ b/doc/api/worker_threads.md @@ -1861,6 +1861,21 @@ Calling `unref()` on a worker allows the thread to exit if this is the only active handle in the event system. If the worker is already `unref()`ed calling `unref()` again has no effect. +### `worker[Symbol.asyncDispose]()` + + + +Calls [`worker.terminate()`][] when the dispose scope is exited. + +```js +async function example() { + await using worker = new Worker('for (;;) {}', { eval: true }); + // Worker is automatically terminate when the scope is exited. +} +``` + ## Notes ### Synchronous blocking of stdio diff --git a/doc/api/zlib.md b/doc/api/zlib.md index a3695eb8991ece..74ffafd2bfbc9a 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -615,7 +615,6 @@ Allowed flush values. * `zlib.constants.Z_FULL_FLUSH` * `zlib.constants.Z_FINISH` * `zlib.constants.Z_BLOCK` -* `zlib.constants.Z_TREES` Return codes for the compression/decompression functions. Negative values are errors, positive values are used for special but normal @@ -834,6 +833,7 @@ Each Brotli-based class takes an `options` object. All options are optional. * `params` {Object} Key-value object containing indexed [Brotli parameters][]. * `maxOutputLength` {integer} Limits output size when using [convenience methods][]. **Default:** [`buffer.kMaxLength`][] +* `info` {boolean} If `true`, returns an object with `buffer` and `engine`. **Default:** `false` For example: @@ -856,6 +856,8 @@ added: - v10.16.0 --> +* Extends: [`ZlibBase`][] + Compress data using the Brotli algorithm. ## Class: `zlib.BrotliDecompress` @@ -866,6 +868,8 @@ added: - v10.16.0 --> +* Extends: [`ZlibBase`][] + Decompress data using the Brotli algorithm. ## Class: `zlib.Deflate` @@ -874,6 +878,8 @@ Decompress data using the Brotli algorithm. added: v0.5.8 --> +* Extends: [`ZlibBase`][] + Compress data using deflate. ## Class: `zlib.DeflateRaw` @@ -882,6 +888,8 @@ Compress data using deflate. added: v0.5.8 --> +* Extends: [`ZlibBase`][] + Compress data using deflate, and do not append a `zlib` header. ## Class: `zlib.Gunzip` @@ -901,6 +909,8 @@ changes: description: A truncated input stream will now result in an `'error'` event. --> +* Extends: [`ZlibBase`][] + Decompress a gzip stream. ## Class: `zlib.Gzip` @@ -909,6 +919,8 @@ Decompress a gzip stream. added: v0.5.8 --> +* Extends: [`ZlibBase`][] + Compress data using gzip. ## Class: `zlib.Inflate` @@ -921,6 +933,8 @@ changes: description: A truncated input stream will now result in an `'error'` event. --> +* Extends: [`ZlibBase`][] + Decompress a deflate stream. ## Class: `zlib.InflateRaw` @@ -936,6 +950,8 @@ changes: description: A truncated input stream will now result in an `'error'` event. --> +* Extends: [`ZlibBase`][] + Decompress a raw deflate stream. ## Class: `zlib.Unzip` @@ -944,6 +960,8 @@ Decompress a raw deflate stream. added: v0.5.8 --> +* Extends: [`ZlibBase`][] + Decompress either a Gzip- or Deflate-compressed stream by auto-detecting the header. @@ -959,6 +977,8 @@ changes: description: This class was renamed from `Zlib` to `ZlibBase`. --> +* Extends: [`stream.Transform`][] + Not exported by the `node:zlib` module. It is documented here because it is the base class of the compressor/decompressor classes. @@ -1049,6 +1069,7 @@ Each Zstd-based class takes an `options` object. All options are optional. * `params` {Object} Key-value object containing indexed [Zstd parameters][]. * `maxOutputLength` {integer} Limits output size when using [convenience methods][]. **Default:** [`buffer.kMaxLength`][] +* `info` {boolean} If `true`, returns an object with `buffer` and `engine`. **Default:** `false` For example: @@ -1707,6 +1728,7 @@ Decompress a chunk of data with [`ZstdDecompress`][]. [`InflateRaw`]: #class-zlibinflateraw [`Inflate`]: #class-zlibinflate [`Unzip`]: #class-zlibunzip +[`ZlibBase`]: #class-zlibzlibbase [`ZstdCompress`]: #class-zlibzstdcompress [`ZstdDecompress`]: #class-zlibzstddecompress [`buffer.kMaxLength`]: buffer.md#bufferkmaxlength diff --git a/doc/changelogs/CHANGELOG_V24.md b/doc/changelogs/CHANGELOG_V24.md index 3374b887e629f3..71a4c975fafda6 100644 --- a/doc/changelogs/CHANGELOG_V24.md +++ b/doc/changelogs/CHANGELOG_V24.md @@ -8,6 +8,7 @@ +24.2.0
    24.1.0
    24.0.2
    24.0.1
    @@ -42,6 +43,220 @@ * [io.js](CHANGELOG_IOJS.md) * [Archive](CHANGELOG_ARCHIVE.md) + + +## 2025-06-09, Version 24.2.0 (Current), @aduh95 + +### Notable Changes + +#### Remove support for HTTP/2 priority signaling + +The support for priority signaling has been removed in nghttp2, following its +deprecation in the [RFC 9113](https://datatracker.ietf.org/doc/html/rfc9113#section-5.3.1). +As a consequence of this, priority signaling is deprecated on all release lines of Node.js, +and removed from Node.js 24 so we can include latest updates from nghttp2. + +Contributed by Matteo Collina and Antoine du Hamel in +[#58293](https://github.com/nodejs/node/pull/58293). + +#### `import.meta.main` is now available + +Boolean value available in ECMAScript modules, which can be used to detect +whether the current module was the entry point of the current process. + +```mjs +export function foo() { + return 'Hello, world'; +} + +function main() { + const message = foo(); + console.log(message); +} + +if (import.meta.main) main(); +// `foo` can be imported from another module without possible side-effects from `main` +``` + +Contributed by Joe and Antoine du Hamel in +[#57804](https://github.com/nodejs/node/pull/57804). + +#### Other Notable Changes + +* \[[`e13930bbe0`](https://github.com/nodejs/node/commit/e13930bbe0)] - **doc**: add Filip Skokan to TSC (Rafael Gonzaga) [#58499](https://github.com/nodejs/node/pull/58499) +* \[[`984894b38c`](https://github.com/nodejs/node/commit/984894b38c)] - **doc**: deprecate `util.isNativeError` in favor of `Error.isError` (Miguel Marcondes Filho) [#58262](https://github.com/nodejs/node/pull/58262) +* \[[`d261274b0f`](https://github.com/nodejs/node/commit/d261274b0f)] - **doc**: deprecate passing an empty string to `options.shell` (Antoine du Hamel) [#58564](https://github.com/nodejs/node/pull/58564) +* \[[`510872a522`](https://github.com/nodejs/node/commit/510872a522)] - **(SEMVER-MINOR)** **doc**: graduate `Symbol.dispose`/`asyncDispose` from experimental (James M Snell) [#58467](https://github.com/nodejs/node/pull/58467) +* \[[`6f4c9dd423`](https://github.com/nodejs/node/commit/6f4c9dd423)] - **(SEMVER-MINOR)** **fs**: add `autoClose` option to `FileHandle` readableWebStream (James M Snell) [#58548](https://github.com/nodejs/node/pull/58548) +* \[[`32efb63242`](https://github.com/nodejs/node/commit/32efb63242)] - **http**: deprecate instantiating classes without new (Yagiz Nizipli) [#58518](https://github.com/nodejs/node/pull/58518) +* \[[`0234a8ef53`](https://github.com/nodejs/node/commit/0234a8ef53)] - **(SEMVER-MINOR)** **http2**: add diagnostics channel `http2.server.stream.finish` (Darshan Sen) [#58560](https://github.com/nodejs/node/pull/58560) +* \[[`0f1e94f731`](https://github.com/nodejs/node/commit/0f1e94f731)] - **(SEMVER-MINOR)** **lib**: graduate error codes that have been around for years (James M Snell) [#58541](https://github.com/nodejs/node/pull/58541) +* \[[`13abca3c26`](https://github.com/nodejs/node/commit/13abca3c26)] - **(SEMVER-MINOR)** **perf\_hooks**: make event loop delay histogram disposable (James M Snell) [#58384](https://github.com/nodejs/node/pull/58384) +* \[[`8ea1fc5f3b`](https://github.com/nodejs/node/commit/8ea1fc5f3b)] - **(SEMVER-MINOR)** **src**: support namespace options in configuration file (Pietro Marchini) [#58073](https://github.com/nodejs/node/pull/58073) +* \[[`d6ea36ad6c`](https://github.com/nodejs/node/commit/d6ea36ad6c)] - **src,permission**: implicit allow-fs-read to app entrypoint (Rafael Gonzaga) [#58579](https://github.com/nodejs/node/pull/58579) +* \[[`5936cef60a`](https://github.com/nodejs/node/commit/5936cef60a)] - **(SEMVER-MINOR)** **test**: add disposable histogram test (James M Snell) [#58384](https://github.com/nodejs/node/pull/58384) +* \[[`7a91f4aaa1`](https://github.com/nodejs/node/commit/7a91f4aaa1)] - **(SEMVER-MINOR)** **test**: add test for async disposable worker thread (James M Snell) [#58385](https://github.com/nodejs/node/pull/58385) +* \[[`532c173cf2`](https://github.com/nodejs/node/commit/532c173cf2)] - **(SEMVER-MINOR)** **util**: add `none` style to styleText (James M Snell) [#58437](https://github.com/nodejs/node/pull/58437) +* \[[`aeb9ab4c4c`](https://github.com/nodejs/node/commit/aeb9ab4c4c)] - **(SEMVER-MINOR)** **worker**: make Worker async disposable (James M Snell) [#58385](https://github.com/nodejs/node/pull/58385) + +### Commits + +* \[[`6c92329b1b`](https://github.com/nodejs/node/commit/6c92329b1b)] - _**Revert**_ "**benchmark**: fix broken fs.cpSync benchmark" (Yuesong Jake Li) [#58476](https://github.com/nodejs/node/pull/58476) +* \[[`8bc045264e`](https://github.com/nodejs/node/commit/8bc045264e)] - **benchmark**: fix broken fs.cpSync benchmark (Dario Piotrowicz) [#58472](https://github.com/nodejs/node/pull/58472) +* \[[`46aa079cce`](https://github.com/nodejs/node/commit/46aa079cce)] - **benchmark**: add callback-based `fs.glob` to glob benchmark (Livia Medeiros) [#58417](https://github.com/nodejs/node/pull/58417) +* \[[`a57b05e105`](https://github.com/nodejs/node/commit/a57b05e105)] - **benchmark**: add more options to cp-sync (Sonny) [#58278](https://github.com/nodejs/node/pull/58278) +* \[[`8b5ada4b31`](https://github.com/nodejs/node/commit/8b5ada4b31)] - **buffer**: use Utf8LengthV2() instead of Utf8Length() (Tobias Nießen) [#58156](https://github.com/nodejs/node/pull/58156) +* \[[`22e97362f3`](https://github.com/nodejs/node/commit/22e97362f3)] - **build**: search for libnode.so in multiple places (Jan Staněk) [#58213](https://github.com/nodejs/node/pull/58213) +* \[[`0b4056c573`](https://github.com/nodejs/node/commit/0b4056c573)] - **build**: add support for OpenHarmony operating system (hqzing) [#58350](https://github.com/nodejs/node/pull/58350) +* \[[`db7f413dd3`](https://github.com/nodejs/node/commit/db7f413dd3)] - **build**: fix pointer compression builds (Joyee Cheung) [#58171](https://github.com/nodejs/node/pull/58171) +* \[[`7ff37183e5`](https://github.com/nodejs/node/commit/7ff37183e5)] - **build**: fix defaults for shared llhttp (Antoine du Hamel) [#58269](https://github.com/nodejs/node/pull/58269) +* \[[`b8c33190fe`](https://github.com/nodejs/node/commit/b8c33190fe)] - **build,win**: fix dll build (Stefan Stojanovic) [#58357](https://github.com/nodejs/node/pull/58357) +* \[[`ef9ecbe8a6`](https://github.com/nodejs/node/commit/ef9ecbe8a6)] - **child\_process**: give names to `ChildProcess` functions (Livia Medeiros) [#58370](https://github.com/nodejs/node/pull/58370) +* \[[`cec9d9d016`](https://github.com/nodejs/node/commit/cec9d9d016)] - **crypto**: forward auth tag to OpenSSL immediately (Tobias Nießen) [#58547](https://github.com/nodejs/node/pull/58547) +* \[[`9fccb0609f`](https://github.com/nodejs/node/commit/9fccb0609f)] - **crypto**: expose crypto.constants.OPENSSL\_IS\_BORINGSSL (Shelley Vohr) [#58387](https://github.com/nodejs/node/pull/58387) +* \[[`e7c69b9345`](https://github.com/nodejs/node/commit/e7c69b9345)] - **deps**: update nghttp2 to 1.65.0 (Node.js GitHub Bot) [#57269](https://github.com/nodejs/node/pull/57269) +* \[[`d0b89598a3`](https://github.com/nodejs/node/commit/d0b89598a3)] - **deps**: use proper C standard when building libuv (Yaksh Bariya) [#58587](https://github.com/nodejs/node/pull/58587) +* \[[`8a1fe7bc6a`](https://github.com/nodejs/node/commit/8a1fe7bc6a)] - **deps**: update simdjson to 3.12.3 (Node.js GitHub Bot) [#57682](https://github.com/nodejs/node/pull/57682) +* \[[`36b639b1eb`](https://github.com/nodejs/node/commit/36b639b1eb)] - **deps**: update googletest to e9092b1 (Node.js GitHub Bot) [#58565](https://github.com/nodejs/node/pull/58565) +* \[[`f8a2a1ef52`](https://github.com/nodejs/node/commit/f8a2a1ef52)] - **deps**: update corepack to 0.33.0 (Node.js GitHub Bot) [#58566](https://github.com/nodejs/node/pull/58566) +* \[[`efb28f7895`](https://github.com/nodejs/node/commit/efb28f7895)] - **deps**: V8: cherry-pick 249de887a8d3 (Michaël Zasso) [#58561](https://github.com/nodejs/node/pull/58561) +* \[[`88e621ea97`](https://github.com/nodejs/node/commit/88e621ea97)] - **deps**: update sqlite to 3.50.0 (Node.js GitHub Bot) [#58272](https://github.com/nodejs/node/pull/58272) +* \[[`8d2ba386f1`](https://github.com/nodejs/node/commit/8d2ba386f1)] - **deps**: update OpenSSL gen container to Ubuntu 22.04 (Michaël Zasso) [#58432](https://github.com/nodejs/node/pull/58432) +* \[[`7e62a77a7f`](https://github.com/nodejs/node/commit/7e62a77a7f)] - **deps**: update undici to 7.10.0 (Node.js GitHub Bot) [#58445](https://github.com/nodejs/node/pull/58445) +* \[[`87eebd7bad`](https://github.com/nodejs/node/commit/87eebd7bad)] - **deps**: keep required OpenSSL doc files (Michaël Zasso) [#58431](https://github.com/nodejs/node/pull/58431) +* \[[`10910660f6`](https://github.com/nodejs/node/commit/10910660f6)] - **deps**: update undici to 7.9.0 (Node.js GitHub Bot) [#58268](https://github.com/nodejs/node/pull/58268) +* \[[`5e27078ca2`](https://github.com/nodejs/node/commit/5e27078ca2)] - **deps**: update ada to 3.2.4 (Node.js GitHub Bot) [#58152](https://github.com/nodejs/node/pull/58152) +* \[[`3b1e4bdbbb`](https://github.com/nodejs/node/commit/3b1e4bdbbb)] - **deps**: update libuv to 1.51.0 (Node.js GitHub Bot) [#58124](https://github.com/nodejs/node/pull/58124) +* \[[`6bddf587ae`](https://github.com/nodejs/node/commit/6bddf587ae)] - **dns**: fix dns query cache implementation (Ethan Arrowood) [#58404](https://github.com/nodejs/node/pull/58404) +* \[[`984894b38c`](https://github.com/nodejs/node/commit/984894b38c)] - **doc**: deprecate utilisNativeError in favor of ErrorisError (Miguel Marcondes Filho) [#58262](https://github.com/nodejs/node/pull/58262) +* \[[`377ef3ce3a`](https://github.com/nodejs/node/commit/377ef3ce3a)] - **doc**: add support link for panva (Filip Skokan) [#58591](https://github.com/nodejs/node/pull/58591) +* \[[`33a69ff9e4`](https://github.com/nodejs/node/commit/33a69ff9e4)] - **doc**: update metadata for \_transformState deprecation (James M Snell) [#58530](https://github.com/nodejs/node/pull/58530) +* \[[`d261274b0f`](https://github.com/nodejs/node/commit/d261274b0f)] - **doc**: deprecate passing an empty string to `options.shell` (Antoine du Hamel) [#58564](https://github.com/nodejs/node/pull/58564) +* \[[`447ca11010`](https://github.com/nodejs/node/commit/447ca11010)] - **doc**: correct formatting of example definitions for `--test-shard` (Jacob Smith) [#58571](https://github.com/nodejs/node/pull/58571) +* \[[`2f555e0e19`](https://github.com/nodejs/node/commit/2f555e0e19)] - **doc**: clarify DEP0194 scope (Antoine du Hamel) [#58504](https://github.com/nodejs/node/pull/58504) +* \[[`af0446edcb`](https://github.com/nodejs/node/commit/af0446edcb)] - **doc**: deprecate HTTP/2 priority signaling (Matteo Collina) [#58313](https://github.com/nodejs/node/pull/58313) +* \[[`80cc17f1ec`](https://github.com/nodejs/node/commit/80cc17f1ec)] - **doc**: explain child\_process code and signal null values everywhere (Darshan Sen) [#58479](https://github.com/nodejs/node/pull/58479) +* \[[`e13930bbe0`](https://github.com/nodejs/node/commit/e13930bbe0)] - **doc**: add Filip Skokan to TSC (Rafael Gonzaga) [#58499](https://github.com/nodejs/node/pull/58499) +* \[[`5f3f045ecc`](https://github.com/nodejs/node/commit/5f3f045ecc)] - **doc**: update `git node release` example (Antoine du Hamel) [#58475](https://github.com/nodejs/node/pull/58475) +* \[[`4bbd026cde`](https://github.com/nodejs/node/commit/4bbd026cde)] - **doc**: add missing options.info for ZstdOptions (Jimmy Leung) [#58360](https://github.com/nodejs/node/pull/58360) +* \[[`a6d0d2a0d7`](https://github.com/nodejs/node/commit/a6d0d2a0d7)] - **doc**: add missing options.info for BrotliOptions (Jimmy Leung) [#58359](https://github.com/nodejs/node/pull/58359) +* \[[`510872a522`](https://github.com/nodejs/node/commit/510872a522)] - **(SEMVER-MINOR)** **doc**: graduate Symbol.dispose/asyncDispose from experimental (James M Snell) [#58467](https://github.com/nodejs/node/pull/58467) +* \[[`08685256cd`](https://github.com/nodejs/node/commit/08685256cd)] - **doc**: clarify x509.checkIssued only checks metadata (Filip Skokan) [#58457](https://github.com/nodejs/node/pull/58457) +* \[[`095794fc24`](https://github.com/nodejs/node/commit/095794fc24)] - **doc**: add links to parent class for `node:zlib` classes (Antoine du Hamel) [#58433](https://github.com/nodejs/node/pull/58433) +* \[[`7acac70bce`](https://github.com/nodejs/node/commit/7acac70bce)] - **doc**: remove remaining uses of `@@wellknown` syntax (René) [#58413](https://github.com/nodejs/node/pull/58413) +* \[[`62056d40c7`](https://github.com/nodejs/node/commit/62056d40c7)] - **doc**: clarify behavior of --watch-path and --watch flags (Juan Ignacio Benito) [#58136](https://github.com/nodejs/node/pull/58136) +* \[[`e6e6ae887d`](https://github.com/nodejs/node/commit/e6e6ae887d)] - **doc**: fix the order of `process.md` sections (Allon Murienik) [#58403](https://github.com/nodejs/node/pull/58403) +* \[[`d2f6c82c0f`](https://github.com/nodejs/node/commit/d2f6c82c0f)] - **doc,lib**: update source map links to ECMA426 (Chengzhong Wu) [#58597](https://github.com/nodejs/node/pull/58597) +* \[[`a994d3d51a`](https://github.com/nodejs/node/commit/a994d3d51a)] - **doc,src,test**: fix typos (Noritaka Kobayashi) [#58477](https://github.com/nodejs/node/pull/58477) +* \[[`252acc1e89`](https://github.com/nodejs/node/commit/252acc1e89)] - **errors**: show url of unsupported attributes in the error message (Aditi) [#58303](https://github.com/nodejs/node/pull/58303) +* \[[`767e88cbc3`](https://github.com/nodejs/node/commit/767e88cbc3)] - **esm**: unwrap WebAssembly.Global on Wasm Namespaces (Guy Bedford) [#57525](https://github.com/nodejs/node/pull/57525) +* \[[`adef9af3ae`](https://github.com/nodejs/node/commit/adef9af3ae)] - **(SEMVER-MINOR)** **esm**: implement import.meta.main (Joe) [#57804](https://github.com/nodejs/node/pull/57804) +* \[[`308f4cac4b`](https://github.com/nodejs/node/commit/308f4cac4b)] - **esm**: add support for dynamic source phase hook (Guy Bedford) [#58147](https://github.com/nodejs/node/pull/58147) +* \[[`fcef56cb05`](https://github.com/nodejs/node/commit/fcef56cb05)] - **fs**: improve cpSync no-filter copyDir performance (Dario Piotrowicz) [#58461](https://github.com/nodejs/node/pull/58461) +* \[[`996fdb05ab`](https://github.com/nodejs/node/commit/996fdb05ab)] - **fs**: fix cp handle existing symlinks (Yuesong Jake Li) [#58476](https://github.com/nodejs/node/pull/58476) +* \[[`d2931e50e3`](https://github.com/nodejs/node/commit/d2931e50e3)] - **fs**: fix cpSync handle existing symlinks (Yuesong Jake Li) [#58476](https://github.com/nodejs/node/pull/58476) +* \[[`6f4c9dd423`](https://github.com/nodejs/node/commit/6f4c9dd423)] - **(SEMVER-MINOR)** **fs**: add autoClose option to FileHandle readableWebStream (James M Snell) [#58548](https://github.com/nodejs/node/pull/58548) +* \[[`8870bb8677`](https://github.com/nodejs/node/commit/8870bb8677)] - **fs**: improve `cpSync` dest overriding performance (Dario Piotrowicz) [#58160](https://github.com/nodejs/node/pull/58160) +* \[[`f2e2301559`](https://github.com/nodejs/node/commit/f2e2301559)] - **fs**: unexpose internal constants (Chengzhong Wu) [#58327](https://github.com/nodejs/node/pull/58327) +* \[[`32efb63242`](https://github.com/nodejs/node/commit/32efb63242)] - **http**: deprecate instantiating classes without new (Yagiz Nizipli) [#58518](https://github.com/nodejs/node/pull/58518) +* \[[`0b987e5741`](https://github.com/nodejs/node/commit/0b987e5741)] - **(SEMVER-MAJOR)** **http2**: remove support for priority signaling (Matteo Collina) [#58293](https://github.com/nodejs/node/pull/58293) +* \[[`44ca874b2c`](https://github.com/nodejs/node/commit/44ca874b2c)] - **http2**: add lenient flag for RFC-9113 (Carlos Fuentes) [#58116](https://github.com/nodejs/node/pull/58116) +* \[[`0234a8ef53`](https://github.com/nodejs/node/commit/0234a8ef53)] - **(SEMVER-MINOR)** **http2**: add diagnostics channel 'http2.server.stream.finish' (Darshan Sen) [#58560](https://github.com/nodejs/node/pull/58560) +* \[[`2b868e8aa7`](https://github.com/nodejs/node/commit/2b868e8aa7)] - **http2**: add diagnostics channel 'http2.server.stream.error' (Darshan Sen) [#58512](https://github.com/nodejs/node/pull/58512) +* \[[`b4df8d38cd`](https://github.com/nodejs/node/commit/b4df8d38cd)] - **http2**: add diagnostics channel 'http2.server.stream.start' (Darshan Sen) [#58449](https://github.com/nodejs/node/pull/58449) +* \[[`d86ff608bb`](https://github.com/nodejs/node/commit/d86ff608bb)] - **http2**: remove no longer userful options.selectPadding (Jimmy Leung) [#58373](https://github.com/nodejs/node/pull/58373) +* \[[`13dbbdc8a8`](https://github.com/nodejs/node/commit/13dbbdc8a8)] - **http2**: add diagnostics channel 'http2.server.stream.created' (Darshan Sen) [#58390](https://github.com/nodejs/node/pull/58390) +* \[[`08855464ec`](https://github.com/nodejs/node/commit/08855464ec)] - **http2**: add diagnostics channel 'http2.client.stream.close' (Darshan Sen) [#58329](https://github.com/nodejs/node/pull/58329) +* \[[`566fc567b8`](https://github.com/nodejs/node/commit/566fc567b8)] - **http2**: add diagnostics channel 'http2.client.stream.finish' (Darshan Sen) [#58317](https://github.com/nodejs/node/pull/58317) +* \[[`f30b9117d4`](https://github.com/nodejs/node/commit/f30b9117d4)] - **http2**: add diagnostics channel 'http2.client.stream.error' (Darshan Sen) [#58306](https://github.com/nodejs/node/pull/58306) +* \[[`79b852a692`](https://github.com/nodejs/node/commit/79b852a692)] - **inspector**: add mimeType and charset support to Network.Response (Shima Ryuhei) [#58192](https://github.com/nodejs/node/pull/58192) +* \[[`402ac8b1d8`](https://github.com/nodejs/node/commit/402ac8b1d8)] - **inspector**: add protocol method Network.dataReceived (Chengzhong Wu) [#58001](https://github.com/nodejs/node/pull/58001) +* \[[`29f34a7f86`](https://github.com/nodejs/node/commit/29f34a7f86)] - **lib**: disable REPL completion on proxies and getters (Dario Piotrowicz) [#57909](https://github.com/nodejs/node/pull/57909) +* \[[`0f1e94f731`](https://github.com/nodejs/node/commit/0f1e94f731)] - **(SEMVER-MINOR)** **lib**: graduate error codes that have been around for years (James M Snell) [#58541](https://github.com/nodejs/node/pull/58541) +* \[[`cc1aacabb0`](https://github.com/nodejs/node/commit/cc1aacabb0)] - **lib**: make ERM functions into wrappers returning undefined (Livia Medeiros) [#58400](https://github.com/nodejs/node/pull/58400) +* \[[`8df4dee38c`](https://github.com/nodejs/node/commit/8df4dee38c)] - **lib**: remove no-mixed-operators eslint rule (Ruben Bridgewater) [#58375](https://github.com/nodejs/node/pull/58375) +* \[[`104d173f58`](https://github.com/nodejs/node/commit/104d173f58)] - **meta**: bump github/codeql-action from 3.28.16 to 3.28.18 (dependabot\[bot]) [#58552](https://github.com/nodejs/node/pull/58552) +* \[[`b454e8386c`](https://github.com/nodejs/node/commit/b454e8386c)] - **meta**: bump codecov/codecov-action from 5.4.2 to 5.4.3 (dependabot\[bot]) [#58551](https://github.com/nodejs/node/pull/58551) +* \[[`f31e014b81`](https://github.com/nodejs/node/commit/f31e014b81)] - **meta**: bump step-security/harden-runner from 2.11.0 to 2.12.0 (dependabot\[bot]) [#58109](https://github.com/nodejs/node/pull/58109) +* \[[`4da920cc13`](https://github.com/nodejs/node/commit/4da920cc13)] - **meta**: bump ossf/scorecard-action from 2.4.1 to 2.4.2 (dependabot\[bot]) [#58550](https://github.com/nodejs/node/pull/58550) +* \[[`eb9bb95fe2`](https://github.com/nodejs/node/commit/eb9bb95fe2)] - **meta**: bump rtCamp/action-slack-notify from 2.3.2 to 2.3.3 (dependabot\[bot]) [#58108](https://github.com/nodejs/node/pull/58108) +* \[[`27ada1f18c`](https://github.com/nodejs/node/commit/27ada1f18c)] - **meta**: move one or more collaborators to emeritus (Node.js GitHub Bot) [#58456](https://github.com/nodejs/node/pull/58456) +* \[[`4606a6792b`](https://github.com/nodejs/node/commit/4606a6792b)] - **meta**: bump github/codeql-action from 3.28.11 to 3.28.16 (dependabot\[bot]) [#58112](https://github.com/nodejs/node/pull/58112) +* \[[`7dfe448b7f`](https://github.com/nodejs/node/commit/7dfe448b7f)] - **meta**: bump codecov/codecov-action from 5.4.0 to 5.4.2 (dependabot\[bot]) [#58110](https://github.com/nodejs/node/pull/58110) +* \[[`18bb5f7e7e`](https://github.com/nodejs/node/commit/18bb5f7e7e)] - **meta**: bump actions/download-artifact from 4.2.1 to 4.3.0 (dependabot\[bot]) [#58106](https://github.com/nodejs/node/pull/58106) +* \[[`72f2a22889`](https://github.com/nodejs/node/commit/72f2a22889)] - **module**: clarify cjs global-like error on ModuleJobSync (Carlos Espa) [#56491](https://github.com/nodejs/node/pull/56491) +* \[[`b0e0b1afae`](https://github.com/nodejs/node/commit/b0e0b1afae)] - **net**: always publish to 'net.client.socket' diagnostics channel (Darshan Sen) [#58349](https://github.com/nodejs/node/pull/58349) +* \[[`f373d6a540`](https://github.com/nodejs/node/commit/f373d6a540)] - **node-api**: use WriteOneByteV2 in napi\_get\_value\_string\_latin1 (Chengzhong Wu) [#58325](https://github.com/nodejs/node/pull/58325) +* \[[`429c38db1b`](https://github.com/nodejs/node/commit/429c38db1b)] - **node-api**: use WriteV2 in napi\_get\_value\_string\_utf16 (Tobias Nießen) [#58165](https://github.com/nodejs/node/pull/58165) +* \[[`b882148999`](https://github.com/nodejs/node/commit/b882148999)] - **path**: improve path.resolve() performance when used as process.cwd() (Ruben Bridgewater) [#58362](https://github.com/nodejs/node/pull/58362) +* \[[`13abca3c26`](https://github.com/nodejs/node/commit/13abca3c26)] - **(SEMVER-MINOR)** **perf\_hooks**: make event loop delay histogram disposable (James M Snell) [#58384](https://github.com/nodejs/node/pull/58384) +* \[[`1cd417d823`](https://github.com/nodejs/node/commit/1cd417d823)] - **permission**: remove useless conditional (Juan José) [#58514](https://github.com/nodejs/node/pull/58514) +* \[[`462c4b0c24`](https://github.com/nodejs/node/commit/462c4b0c24)] - **readline**: add stricter validation for functions called after closed (Dario Piotrowicz) [#58283](https://github.com/nodejs/node/pull/58283) +* \[[`e3e36f902c`](https://github.com/nodejs/node/commit/e3e36f902c)] - **repl**: extract and standardize history from both repl and interface (Giovanni Bucci) [#58225](https://github.com/nodejs/node/pull/58225) +* \[[`cbb2a0172f`](https://github.com/nodejs/node/commit/cbb2a0172f)] - **report**: use uv\_getrusage\_thread in report (theanarkh) [#58405](https://github.com/nodejs/node/pull/58405) +* \[[`3a6bd9c4c4`](https://github.com/nodejs/node/commit/3a6bd9c4c4)] - **sqlite**: handle thrown errors in result callback (Colin Ihrig) [#58426](https://github.com/nodejs/node/pull/58426) +* \[[`0d761bbccd`](https://github.com/nodejs/node/commit/0d761bbccd)] - **src**: env\_vars caching and local variable scope optimization (Mert Can Altin) [#57624](https://github.com/nodejs/node/pull/57624) +* \[[`8ea1fc5f3b`](https://github.com/nodejs/node/commit/8ea1fc5f3b)] - **(SEMVER-MINOR)** **src**: support namespace options in configuration file (Pietro Marchini) [#58073](https://github.com/nodejs/node/pull/58073) +* \[[`f72ce2ef75`](https://github.com/nodejs/node/commit/f72ce2ef75)] - **src**: remove fast API for InternalModuleStat (Joyee Cheung) [#58489](https://github.com/nodejs/node/pull/58489) +* \[[`8a1eaea151`](https://github.com/nodejs/node/commit/8a1eaea151)] - **src**: update std::vector\> to use v8::LocalVector\ (Aditi) [#58500](https://github.com/nodejs/node/pull/58500) +* \[[`d99d657842`](https://github.com/nodejs/node/commit/d99d657842)] - **src**: fix FIPS init error handling (Tobias Nießen) [#58379](https://github.com/nodejs/node/pull/58379) +* \[[`11e4cd698b`](https://github.com/nodejs/node/commit/11e4cd698b)] - **src**: fix possible dereference of null pointer (Eusgor) [#58459](https://github.com/nodejs/node/pull/58459) +* \[[`ca0f5a0188`](https://github.com/nodejs/node/commit/ca0f5a0188)] - **src**: add env->cppgc\_allocation\_handle() convenience method (James M Snell) [#58483](https://github.com/nodejs/node/pull/58483) +* \[[`440d4f42bd`](https://github.com/nodejs/node/commit/440d4f42bd)] - **src**: fix -Wreturn-stack-address error (Shelley Vohr) [#58439](https://github.com/nodejs/node/pull/58439) +* \[[`08615b1020`](https://github.com/nodejs/node/commit/08615b1020)] - **src**: prepare for v8 sandboxing (James M Snell) [#58376](https://github.com/nodejs/node/pull/58376) +* \[[`63f643e844`](https://github.com/nodejs/node/commit/63f643e844)] - **src**: reorganize ContextifyFunction methods (Chengzhong Wu) [#58434](https://github.com/nodejs/node/pull/58434) +* \[[`3b6895a506`](https://github.com/nodejs/node/commit/3b6895a506)] - **src**: improve CompileFunctionAndCacheResult error handling (Chengzhong Wu) [#58434](https://github.com/nodejs/node/pull/58434) +* \[[`7f1c95aee8`](https://github.com/nodejs/node/commit/7f1c95aee8)] - **src**: make a number of minor improvements to buffer (James M Snell) [#58377](https://github.com/nodejs/node/pull/58377) +* \[[`ce081bcb9a`](https://github.com/nodejs/node/commit/ce081bcb9a)] - **src**: fix build when using shared simdutf (Antoine du Hamel) [#58407](https://github.com/nodejs/node/pull/58407) +* \[[`a35cc216e5`](https://github.com/nodejs/node/commit/a35cc216e5)] - **src**: track cppgc wrappers with a list in Realm (Joyee Cheung) [#56534](https://github.com/nodejs/node/pull/56534) +* \[[`947c1c2cd5`](https://github.com/nodejs/node/commit/947c1c2cd5)] - **src,lib**: obtain sourceURL in magic comments from V8 (Chengzhong Wu) [#58389](https://github.com/nodejs/node/pull/58389) +* \[[`d6ea36ad6c`](https://github.com/nodejs/node/commit/d6ea36ad6c)] - **src,permission**: implicit allow-fs-read to app entrypoint (Rafael Gonzaga) [#58579](https://github.com/nodejs/node/pull/58579) +* \[[`e8a07f2198`](https://github.com/nodejs/node/commit/e8a07f2198)] - **stream**: making DecompressionStream spec compilent for trailing junk (0hm☘️) [#58316](https://github.com/nodejs/node/pull/58316) +* \[[`3caa2f71c1`](https://github.com/nodejs/node/commit/3caa2f71c1)] - **stream**: test explicit resource management implicitly (LiviaMedeiros) [#58296](https://github.com/nodejs/node/pull/58296) +* \[[`9ccdf4fdb4`](https://github.com/nodejs/node/commit/9ccdf4fdb4)] - **test**: improve flakiness detection on stack corruption tests (Darshan Sen) [#58601](https://github.com/nodejs/node/pull/58601) +* \[[`d3fea003df`](https://github.com/nodejs/node/commit/d3fea003df)] - **test**: mark timeouts & flaky test as flaky on IBM i (Abdirahim Musse) [#58583](https://github.com/nodejs/node/pull/58583) +* \[[`8347ef6b53`](https://github.com/nodejs/node/commit/8347ef6b53)] - **test**: dispose of filehandles in filehandle.read tests (Livia Medeiros) [#58543](https://github.com/nodejs/node/pull/58543) +* \[[`34e86f91aa`](https://github.com/nodejs/node/commit/34e86f91aa)] - **test**: rewrite test-child-process-spawn-args (Michaël Zasso) [#58546](https://github.com/nodejs/node/pull/58546) +* \[[`d7a2458a58`](https://github.com/nodejs/node/commit/d7a2458a58)] - **test**: make sqlite-database-sync tests work with system sqlite (Jelle Licht) [#58507](https://github.com/nodejs/node/pull/58507) +* \[[`4d9d6830e0`](https://github.com/nodejs/node/commit/4d9d6830e0)] - **test**: force slow JSON.stringify path for overflow (Shelley Vohr) [#58181](https://github.com/nodejs/node/pull/58181) +* \[[`bef67e45e3`](https://github.com/nodejs/node/commit/bef67e45e3)] - **test**: account for truthy signal in flaky async\_hooks tests (Darshan Sen) [#58478](https://github.com/nodejs/node/pull/58478) +* \[[`007c82f206`](https://github.com/nodejs/node/commit/007c82f206)] - **test**: mark `test-http2-debug` as flaky on LinuxONE (Richard Lau) [#58494](https://github.com/nodejs/node/pull/58494) +* \[[`21f6400098`](https://github.com/nodejs/node/commit/21f6400098)] - **test**: update WPT for WebCryptoAPI to 591c95ce61 (Node.js GitHub Bot) [#58176](https://github.com/nodejs/node/pull/58176) +* \[[`1deb5f06a5`](https://github.com/nodejs/node/commit/1deb5f06a5)] - **test**: remove --no-warnings flag (Tobias Nießen) [#58424](https://github.com/nodejs/node/pull/58424) +* \[[`beba631a10`](https://github.com/nodejs/node/commit/beba631a10)] - **test**: add tests ensuring worker threads cannot access internals (Joe) [#58332](https://github.com/nodejs/node/pull/58332) +* \[[`5936cef60a`](https://github.com/nodejs/node/commit/5936cef60a)] - **(SEMVER-MINOR)** **test**: add disposable histogram test (James M Snell) [#58384](https://github.com/nodejs/node/pull/58384) +* \[[`7a91f4aaa1`](https://github.com/nodejs/node/commit/7a91f4aaa1)] - **(SEMVER-MINOR)** **test**: add test for async disposable worker thread (James M Snell) [#58385](https://github.com/nodejs/node/pull/58385) +* \[[`5fc4706280`](https://github.com/nodejs/node/commit/5fc4706280)] - **test**: leverage process.features.openssl\_is\_boringssl in test (Shelley Vohr) [#58421](https://github.com/nodejs/node/pull/58421) +* \[[`4629b18397`](https://github.com/nodejs/node/commit/4629b18397)] - **test**: fix test-buffer-tostring-range on allocation failure (Joyee Cheung) [#58416](https://github.com/nodejs/node/pull/58416) +* \[[`4c445a8c85`](https://github.com/nodejs/node/commit/4c445a8c85)] - **test**: skip in test-buffer-tostring-rangeerror on allocation failure (Joyee Cheung) [#58415](https://github.com/nodejs/node/pull/58415) +* \[[`53cb29898b`](https://github.com/nodejs/node/commit/53cb29898b)] - **test**: fix missing edge case in test-blob-slice-with-large-size (Joyee Cheung) [#58414](https://github.com/nodejs/node/pull/58414) +* \[[`89fdfdedc1`](https://github.com/nodejs/node/commit/89fdfdedc1)] - **test**: make crypto tests work with BoringSSL (Shelley Vohr) [#58117](https://github.com/nodejs/node/pull/58117) +* \[[`3b5d0e62b1`](https://github.com/nodejs/node/commit/3b5d0e62b1)] - **test**: test reordering of setAAD and setAuthTag (Tobias Nießen) [#58396](https://github.com/nodejs/node/pull/58396) +* \[[`029440bec5`](https://github.com/nodejs/node/commit/029440bec5)] - **test**: switch from deprecated `optparse` to `argparse` (Aviv Keller) [#58224](https://github.com/nodejs/node/pull/58224) +* \[[`d05263edcc`](https://github.com/nodejs/node/commit/d05263edcc)] - **test**: do not skip OCB decryption in FIPS mode (Tobias Nießen) [#58382](https://github.com/nodejs/node/pull/58382) +* \[[`23474cb257`](https://github.com/nodejs/node/commit/23474cb257)] - **test**: show more information in test-http2-debug upon failure (Joyee Cheung) [#58391](https://github.com/nodejs/node/pull/58391) +* \[[`d0302e7b3d`](https://github.com/nodejs/node/commit/d0302e7b3d)] - **test**: remove loop over single element (Tobias Nießen) [#58368](https://github.com/nodejs/node/pull/58368) +* \[[`33f615897d`](https://github.com/nodejs/node/commit/33f615897d)] - **test**: add chacha20-poly1305 to auth tag order test (Tobias Nießen) [#58367](https://github.com/nodejs/node/pull/58367) +* \[[`8f09a1f502`](https://github.com/nodejs/node/commit/8f09a1f502)] - **test**: skip wasm-allocation tests for pointer compression builds (Joyee Cheung) [#58171](https://github.com/nodejs/node/pull/58171) +* \[[`4ae6a1a5ed`](https://github.com/nodejs/node/commit/4ae6a1a5ed)] - **test**: remove references to create(De|C)ipher (Tobias Nießen) [#58363](https://github.com/nodejs/node/pull/58363) +* \[[`4d647271b2`](https://github.com/nodejs/node/commit/4d647271b2)] - **test\_runner**: emit event when file changes in watch mode (Jacopo Martinelli) [#57903](https://github.com/nodejs/node/pull/57903) +* \[[`1eda87c365`](https://github.com/nodejs/node/commit/1eda87c365)] - **test\_runner**: add level parameter to reporter.diagnostic (Jacopo Martinelli) [#57923](https://github.com/nodejs/node/pull/57923) +* \[[`13377512be`](https://github.com/nodejs/node/commit/13377512be)] - **tools**: bump the eslint group in `/tools/eslint` with 6 updates (dependabot\[bot]) [#58549](https://github.com/nodejs/node/pull/58549) +* \[[`fcc881de0d`](https://github.com/nodejs/node/commit/fcc881de0d)] - **tools**: support `DisposableStack` and `AsyncDisposableStack` in linter (LiviaMedeiros) [#58454](https://github.com/nodejs/node/pull/58454) +* \[[`208d6a5754`](https://github.com/nodejs/node/commit/208d6a5754)] - **tools**: support explicit resource management in eslint (LiviaMedeiros) [#58296](https://github.com/nodejs/node/pull/58296) +* \[[`32070f304a`](https://github.com/nodejs/node/commit/32070f304a)] - **tools**: add missing highway defines for IBM i (Abdirahim Musse) [#58335](https://github.com/nodejs/node/pull/58335) +* \[[`ddab63a323`](https://github.com/nodejs/node/commit/ddab63a323)] - **tty**: improve color terminal color detection (Ruben Bridgewater) [#58146](https://github.com/nodejs/node/pull/58146) +* \[[`c094bea8d9`](https://github.com/nodejs/node/commit/c094bea8d9)] - **tty**: use terminal VT mode on Windows (Anna Henningsen) [#58358](https://github.com/nodejs/node/pull/58358) +* \[[`dc21054a1e`](https://github.com/nodejs/node/commit/dc21054a1e)] - **typings**: add inspector internalBinding typing (Shima Ryuhei) [#58492](https://github.com/nodejs/node/pull/58492) +* \[[`3499285904`](https://github.com/nodejs/node/commit/3499285904)] - **typings**: remove no longer valid `FixedSizeBlobCopyJob` type (Dario Piotrowicz) [#58305](https://github.com/nodejs/node/pull/58305) +* \[[`1ed2deb2c8`](https://github.com/nodejs/node/commit/1ed2deb2c8)] - **typings**: remove no longer valid `revokeDataObject` type (Dario Piotrowicz) [#58305](https://github.com/nodejs/node/pull/58305) +* \[[`532c173cf2`](https://github.com/nodejs/node/commit/532c173cf2)] - **(SEMVER-MINOR)** **util**: add 'none' style to styleText (James M Snell) [#58437](https://github.com/nodejs/node/pull/58437) +* \[[`2d5a1ef528`](https://github.com/nodejs/node/commit/2d5a1ef528)] - **vm**: import call should return a promise in the current context (Chengzhong Wu) [#58309](https://github.com/nodejs/node/pull/58309) +* \[[`588c2449f2`](https://github.com/nodejs/node/commit/588c2449f2)] - **win,tools**: use Azure Trusted Signing (Stefan Stojanovic) [#58502](https://github.com/nodejs/node/pull/58502) +* \[[`aeb9ab4c4c`](https://github.com/nodejs/node/commit/aeb9ab4c4c)] - **(SEMVER-MINOR)** **worker**: make Worker async disposable (James M Snell) [#58385](https://github.com/nodejs/node/pull/58385) +* \[[`23416cce0a`](https://github.com/nodejs/node/commit/23416cce0a)] - **worker**: give names to `MessagePort` functions (Livia Medeiros) [#58307](https://github.com/nodejs/node/pull/58307) +* \[[`44df21b7fb`](https://github.com/nodejs/node/commit/44df21b7fb)] - **zlib**: remove mentions of unexposed Z\_TREES constant (Jimmy Leung) [#58371](https://github.com/nodejs/node/pull/58371) + ## 2025-05-21, Version 24.1.0 (Current), @aduh95 diff --git a/doc/contributing/primordials.md b/doc/contributing/primordials.md index bbffca00806c66..4b143c485ff9d9 100644 --- a/doc/contributing/primordials.md +++ b/doc/contributing/primordials.md @@ -161,8 +161,9 @@ This code is internally expanded into something that looks like: ```js { - // 1. Lookup @@iterator property on `array` (user-mutable if user-provided). - // 2. Lookup @@iterator property on %Array.prototype% (user-mutable). + // 1. Lookup %Symbol.iterator% property on `array` (user-mutable if + // user-provided). + // 2. Lookup %Symbol.iterator% property on %Array.prototype% (user-mutable). // 3. Call that function. const iterator = array[Symbol.iterator](); // 1. Lookup `next` property on `iterator` (doesn't exist). @@ -226,8 +227,9 @@ const [first, second] = array; This is roughly equivalent to: ```js -// 1. Lookup @@iterator property on `array` (user-mutable if user-provided). -// 2. Lookup @@iterator property on %Array.prototype% (user-mutable). +// 1. Lookup %Symbol.iterator% property on `array` (user-mutable if +// user-provided). +// 2. Lookup %Symbol.iterator% property on %Array.prototype% (user-mutable). // 3. Call that function. const iterator = array[Symbol.iterator](); // 1. Lookup `next` property on `iterator` (doesn't exist). @@ -262,8 +264,9 @@ best choice. Avoid spread operator on arrays ```js -// 1. Lookup @@iterator property on `array` (user-mutable if user-provided). -// 2. Lookup @@iterator property on %Array.prototype% (user-mutable). +// 1. Lookup %Symbol.iterator% property on `array` (user-mutable if +// user-provided). +// 2. Lookup %Symbol.iterator% property on %Array.prototype% (user-mutable). // 3. Lookup `next` property on %ArrayIteratorPrototype% (user-mutable). const arrayCopy = [...array]; func(...array); @@ -281,17 +284,17 @@ ReflectApply(func, null, array);
    %Array.prototype.concat% looks up - @@isConcatSpreadable property of the passed - arguments and the this value. + %Symbol.isConcatSpreadable% property of the passed + arguments and the this value ```js { // Unsafe code example: - // 1. Lookup @@isConcatSpreadable property on `array` (user-mutable if - // user-provided). - // 2. Lookup @@isConcatSpreadable property on `%Array.prototype% + // 1. Lookup %Symbol.isConcatSpreadable% property on `array` + // (user-mutable if user-provided). + // 2. Lookup %Symbol.isConcatSpreadable% property on `%Array.prototype% // (user-mutable). - // 2. Lookup @@isConcatSpreadable property on `%Object.prototype% + // 2. Lookup %Symbol.isConcatSpreadable% property on `%Object.prototype% // (user-mutable). const array = []; ArrayPrototypeConcat(array); @@ -340,8 +343,9 @@ Object.defineProperty(Object.prototype, Symbol.isConcatSpreadable, { ```js { // Unsafe code example: - // 1. Lookup @@iterator property on `array` (user-mutable if user-provided). - // 2. Lookup @@iterator property on %Array.prototype% (user-mutable). + // 1. Lookup %Symbol.iterator% property on `array` (user-mutable if + // user-provided). + // 2. Lookup %Symbol.iterator% property on %Array.prototype% (user-mutable). // 3. Lookup `next` property on %ArrayIteratorPrototype% (user-mutable). const obj = ObjectFromEntries(array); } @@ -371,8 +375,9 @@ Object.defineProperty(Object.prototype, Symbol.isConcatSpreadable, { %Promise.race% iterate over an array ```js -// 1. Lookup @@iterator property on `array` (user-mutable if user-provided). -// 2. Lookup @@iterator property on %Array.prototype% (user-mutable). +// 1. Lookup %Symbol.iterator% property on `array` (user-mutable if +// user-provided). +// 2. Lookup %Symbol.iterator% property on %Array.prototype% (user-mutable). // 3. Lookup `next` property on %ArrayIteratorPrototype% (user-mutable). // 4. Lookup `then` property on %Array.Prototype% (user-mutable). // 5. Lookup `then` property on %Object.Prototype% (user-mutable). @@ -437,7 +442,7 @@ Array.prototype[Symbol.iterator] = () => ({ // Core -// 1. Lookup @@iterator property on %Array.prototype% (user-mutable). +// 1. Lookup %Symbol.iterator% property on %Array.prototype% (user-mutable). // 2. Lookup `next` property on %ArrayIteratorPrototype% (user-mutable). const set = new SafeSet([1, 2, 3]); @@ -684,14 +689,14 @@ can be reset from user-land. List of RegExp methods that look up properties from mutable getters -| `RegExp` method | looks up the following flag-related properties | -| ------------------------------ | ------------------------------------------------------------------ | -| `get RegExp.prototype.flags` | `global`, `ignoreCase`, `multiline`, `dotAll`, `unicode`, `sticky` | -| `RegExp.prototype[@@match]` | `global`, `unicode` | -| `RegExp.prototype[@@matchAll]` | `flags` | -| `RegExp.prototype[@@replace]` | `global`, `unicode` | -| `RegExp.prototype[@@split]` | `flags` | -| `RegExp.prototype.toString` | `flags` | +| `RegExp` method | looks up the following flag-related properties | +| ----------------------------------- | ------------------------------------------------------------------ | +| `get RegExp.prototype.flags` | `global`, `ignoreCase`, `multiline`, `dotAll`, `unicode`, `sticky` | +| `RegExp.prototype[Symbol.match]` | `global`, `unicode` | +| `RegExp.prototype[Symbol.matchAll]` | `flags` | +| `RegExp.prototype[Symbol.replace]` | `global`, `unicode` | +| `RegExp.prototype[Symbol.split]` | `flags` | +| `RegExp.prototype.toString` | `flags` |
    @@ -786,7 +791,7 @@ console.log(proxyWithNullPrototypeObject.someProperty); // genuine value ### Checking if an object is an instance of a class -#### Using `instanceof` looks up the `@@hasInstance` property of the class +#### Using `instanceof` looks up the `%Symbol.hasInstance%` property of the class ```js // User-land diff --git a/doc/contributing/releases.md b/doc/contributing/releases.md index de56e5acd17c12..6488c1d51a983f 100644 --- a/doc/contributing/releases.md +++ b/doc/contributing/releases.md @@ -735,15 +735,34 @@ the build before moving forward. Use the following list as a baseline: ### 11. Tag and sign the release commit Once you have produced builds that you're happy with you can either run -`git node release --promote` +`git node release --promote`: ```bash -git node release -S --promote https://github.com/nodejs/node/pull/XXXX +git node release --promote https://github.com/nodejs/node/pull/XXXX -S ``` to automate the remaining steps until step 16 or you can perform it manually following the below steps. +
    +Security release + +For security releases, NCU should be configured to target the public repository, +not the private one where the proposal are hosted. Pass the upstream where to +fetch the proposal from using the `--fetch-from` flag. + +When promoting several releases, you can pass multiple URLs: + +```bash +git node release --promote \ + --fetch-from git@github.com:nodejs-private/node-private.git \ + https://github.com/nodejs-private/node-private/pull/XXXX \ + https://github.com/nodejs-private/node-private/pull/XXXX \ + -S +``` + +
    + *** Create a new tag: By waiting until this stage to create tags, you can discard diff --git a/doc/node-config-schema.json b/doc/node-config-schema.json index 1648957888096d..75902338c806cb 100644 --- a/doc/node-config-schema.json +++ b/doc/node-config-schema.json @@ -584,6 +584,135 @@ } }, "type": "object" + }, + "testRunner": { + "type": "object", + "additionalProperties": false, + "properties": { + "experimental-test-coverage": { + "type": "boolean" + }, + "experimental-test-module-mocks": { + "type": "boolean" + }, + "test-concurrency": { + "type": "number" + }, + "test-coverage-branches": { + "type": "number" + }, + "test-coverage-exclude": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "test-coverage-functions": { + "type": "number" + }, + "test-coverage-include": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "test-coverage-lines": { + "type": "number" + }, + "test-force-exit": { + "type": "boolean" + }, + "test-global-setup": { + "type": "string" + }, + "test-isolation": { + "type": "string" + }, + "test-name-pattern": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "test-only": { + "type": "boolean" + }, + "test-reporter": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "test-reporter-destination": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "test-shard": { + "type": "string" + }, + "test-skip-pattern": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "test-timeout": { + "type": "number" + }, + "test-update-snapshots": { + "type": "boolean" + } + } } }, "type": "object" diff --git a/eslint.config.mjs b/eslint.config.mjs index 777524660dddb0..003f460e1f7bc5 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -18,6 +18,8 @@ import nodeCore from './tools/eslint/eslint-plugin-node-core.js'; const { globalIgnores } = await importEslintTool('eslint/config'); const { default: js } = await importEslintTool('@eslint/js'); const { default: babelEslintParser } = await importEslintTool('@babel/eslint-parser'); +const babelPluginProposalExplicitResourceManagement = + resolveEslintTool('@babel/plugin-proposal-explicit-resource-management'); const babelPluginSyntaxImportAttributes = resolveEslintTool('@babel/plugin-syntax-import-attributes'); const babelPluginSyntaxImportSource = resolveEslintTool('@babel/plugin-syntax-import-source'); const { default: jsdoc } = await importEslintTool('eslint-plugin-jsdoc'); @@ -102,7 +104,9 @@ export default [ parser: babelEslintParser, parserOptions: { babelOptions: { + parserOpts: { createImportExpressions: true }, plugins: [ + babelPluginProposalExplicitResourceManagement, babelPluginSyntaxImportAttributes, babelPluginSyntaxImportSource, ], @@ -116,6 +120,7 @@ export default [ { languageOptions: { globals: { + AsyncDisposableStack: 'readonly', ByteLengthQueuingStrategy: 'readonly', CompressionStream: 'readonly', CountQueuingStrategy: 'readonly', @@ -124,6 +129,7 @@ export default [ Crypto: 'readonly', CryptoKey: 'readonly', DecompressionStream: 'readonly', + DisposableStack: 'readonly', EventSource: 'readable', fetch: 'readonly', Float16Array: 'readonly', diff --git a/lib/_http_server.js b/lib/_http_server.js index e6baccbe099de0..b728f73c419772 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -581,7 +581,7 @@ Server.prototype.close = function close() { }; Server.prototype[SymbolAsyncDispose] = assignFunctionName(SymbolAsyncDispose, async function() { - return promisify(this.close).call(this); + await promisify(this.close).call(this); }); Server.prototype.closeAllConnections = function closeAllConnections() { diff --git a/lib/dgram.js b/lib/dgram.js index b4c5db6439784a..163f2139e7a0c8 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -802,7 +802,7 @@ Socket.prototype[SymbolAsyncDispose] = async function() { if (!this[kStateSymbol].handle) { return; } - return FunctionPrototypeCall(promisify(this.close), this); + await FunctionPrototypeCall(promisify(this.close), this); }; diff --git a/lib/eslint.config_partial.mjs b/lib/eslint.config_partial.mjs index c4df9b191d8d05..646359807a8570 100644 --- a/lib/eslint.config_partial.mjs +++ b/lib/eslint.config_partial.mjs @@ -356,11 +356,22 @@ export default [ name: 'SubtleCrypto', message: "Use `const { SubtleCrypto } = require('internal/crypto/webcrypto');` instead of the global.", }, - // Float16Array is not available in primordials because it's only available with --js-float16array CLI flag. + // Float16Array is not available in primordials because it can be + // disabled with --no-js-float16array CLI flag. { name: 'Float16Array', message: 'Use `const { Float16Array } = globalThis;` instead of the global.', }, + // DisposableStack and AsyncDisposableStack are not available in primordials because they can be + // disabled with --no-js-explicit-resource-management CLI flag. + { + name: 'DisposableStack', + message: 'Use `const { DisposableStack } = globalThis;` instead of the global.', + }, + { + name: 'AsyncDisposableStack', + message: 'Use `const { AsyncDisposableStack } = globalThis;` instead of the global.', + }, ], 'no-restricted-modules': [ 'error', @@ -370,16 +381,6 @@ export default [ }, ], - // Stylistic rules. - '@stylistic/js/no-mixed-operators': [ - 'error', - { - groups: [ - ['&&', '||'], - ], - }, - ], - // Custom rules in tools/eslint-rules. 'node-core/alphabetize-errors': 'error', 'node-core/alphabetize-primordials': 'error', diff --git a/lib/https.js b/lib/https.js index 53f03d1a7b63df..acd3252b5cde66 100644 --- a/lib/https.js +++ b/lib/https.js @@ -117,7 +117,7 @@ Server.prototype.close = function close() { }; Server.prototype[SymbolAsyncDispose] = async function() { - return FunctionPrototypeCall(promisify(this.close), this); + await FunctionPrototypeCall(promisify(this.close), this); }; /** diff --git a/lib/inspector.js b/lib/inspector.js index 26704f0df42d28..62ca9253c5612a 100644 --- a/lib/inspector.js +++ b/lib/inspector.js @@ -214,6 +214,7 @@ const Network = { responseReceived: (params) => broadcastToFrontend('Network.responseReceived', params), loadingFinished: (params) => broadcastToFrontend('Network.loadingFinished', params), loadingFailed: (params) => broadcastToFrontend('Network.loadingFailed', params), + dataReceived: (params) => broadcastToFrontend('Network.dataReceived', params), }; module.exports = { diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index d6e9fee643e7bb..963fe2ab11927a 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -266,7 +266,7 @@ ObjectDefineProperty(process, 'allowedNodeEnvironmentFlags', { // TODO(joyeecheung): this property has not been well-maintained, should we // deprecate it in favor of a better API? -const { isDebugBuild, hasOpenSSL, hasInspector } = config; +const { isDebugBuild, hasOpenSSL, openSSLIsBoringSSL, hasInspector } = config; const features = { inspector: hasInspector, debug: isDebugBuild, @@ -276,6 +276,7 @@ const features = { tls_sni: hasOpenSSL, tls_ocsp: hasOpenSSL, tls: hasOpenSSL, + openssl_is_boringssl: openSSLIsBoringSSL, // This needs to be dynamic because --no-node-snapshot disables the // code cache even if the binary is built with embedded code cache. get cached_builtins() { diff --git a/lib/internal/child_process.js b/lib/internal/child_process.js index 748f14a283f05f..dada6b8cc5a1fd 100644 --- a/lib/internal/child_process.js +++ b/lib/internal/child_process.js @@ -352,7 +352,7 @@ function closePendingHandle(target) { } -ChildProcess.prototype.spawn = function(options) { +ChildProcess.prototype.spawn = function spawn(options) { let i = 0; validateObject(options, 'options'); @@ -490,7 +490,7 @@ function onSpawnNT(self) { } -ChildProcess.prototype.kill = function(sig) { +ChildProcess.prototype.kill = function kill(sig) { const signal = sig === 0 ? sig : convertToValidSignal(sig === undefined ? 'SIGTERM' : sig); @@ -524,12 +524,12 @@ ChildProcess.prototype[SymbolDispose] = function() { }; -ChildProcess.prototype.ref = function() { +ChildProcess.prototype.ref = function ref() { if (this._handle) this._handle.ref(); }; -ChildProcess.prototype.unref = function() { +ChildProcess.prototype.unref = function unref() { if (this._handle) this._handle.unref(); }; diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 87200b40d45bdc..6c48b1fd31b8cd 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -1338,7 +1338,12 @@ E('ERR_IMPORT_ATTRIBUTE_MISSING', E('ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE', 'Module "%s" is not of type "%s"', TypeError); E('ERR_IMPORT_ATTRIBUTE_UNSUPPORTED', - 'Import attribute "%s" with value "%s" is not supported', TypeError); + function error(attribute, value, url = undefined) { + if (url === undefined) { + return `Import attribute "${attribute}" with value "${value}" is not supported`; + } + return `Import attribute "${attribute}" with value "${value}" is not supported in ${url}`; + }, TypeError); E('ERR_INCOMPATIBLE_OPTION_PAIR', 'Option "%s" cannot be used in combination with option "%s"', TypeError, HideStackFramesError); E('ERR_INPUT_TYPE_NOT_ALLOWED', '--input-type can only be used with string ' + @@ -1803,6 +1808,8 @@ E('ERR_TRACE_EVENTS_CATEGORY_REQUIRED', 'At least one category is required', TypeError); E('ERR_TRACE_EVENTS_UNAVAILABLE', 'Trace events are unavailable', Error); +E('ERR_TRAILING_JUNK_AFTER_STREAM_END', 'Trailing junk found after the end of the compressed stream', TypeError); + // This should probably be a `RangeError`. E('ERR_TTY_INIT_FAILED', 'TTY initialization failed', SystemError); E('ERR_UNAVAILABLE_DURING_EXIT', 'Cannot call function in process exit ' + diff --git a/lib/internal/fs/cp/cp-sync.js b/lib/internal/fs/cp/cp-sync.js index 1e922b7805fc8c..03fcae9b7cdbda 100644 --- a/lib/internal/fs/cp/cp-sync.js +++ b/lib/internal/fs/cp/cp-sync.js @@ -81,15 +81,12 @@ function getStats(src, dest, opts) { function onFile(srcStat, destStat, src, dest, opts) { if (!destStat) return copyFile(srcStat, src, dest, opts); - return mayCopyFile(srcStat, src, dest, opts); -} -// TODO(@anonrig): Move this function to C++. -function mayCopyFile(srcStat, src, dest, opts) { if (opts.force) { - unlinkSync(dest); - return copyFile(srcStat, src, dest, opts); - } else if (opts.errorOnExist) { + return fsBinding.cpSyncOverrideFile(src, dest, opts.mode, opts.preserveTimestamps); + } + + if (opts.errorOnExist) { throw new ERR_FS_CP_EEXIST({ message: `${dest} already exists`, path: dest, @@ -136,18 +133,27 @@ function setDestTimestamps(src, dest) { // TODO(@anonrig): Move this function to C++. function onDir(srcStat, destStat, src, dest, opts) { - if (!destStat) return mkDirAndCopy(srcStat.mode, src, dest, opts); + if (!destStat) return copyDir(src, dest, opts, true, srcStat.mode); return copyDir(src, dest, opts); } -function mkDirAndCopy(srcMode, src, dest, opts) { - mkdirSync(dest); - copyDir(src, dest, opts); - return setDestMode(dest, srcMode); -} +function copyDir(src, dest, opts, mkDir, srcMode) { + if (!opts.filter) { + // The caller didn't provide a js filter function, in this case + // we can run the whole function faster in C++ + // TODO(dario-piotrowicz): look into making cpSyncCopyDir also accept the potential filter function + return fsBinding.cpSyncCopyDir(src, dest, + opts.force, + opts.dereference, + opts.errorOnExist, + opts.verbatimSymlinks, + opts.preserveTimestamps); + } + + if (mkDir) { + mkdirSync(dest); + } -// TODO(@anonrig): Move this function to C++. -function copyDir(src, dest, opts) { const dir = opendirSync(src); try { @@ -172,6 +178,10 @@ function copyDir(src, dest, opts) { } } finally { dir.closeSync(); + + if (srcMode !== undefined) { + setDestMode(dest, srcMode); + } } } @@ -199,7 +209,9 @@ function onLink(destStat, src, dest, verbatimSymlinks) { if (!isAbsolute(resolvedDest)) { resolvedDest = resolve(dirname(dest), resolvedDest); } - if (isSrcSubdir(resolvedSrc, resolvedDest)) { + const srcIsDir = fsBinding.internalModuleStat(src) === 1; + + if (srcIsDir && isSrcSubdir(resolvedSrc, resolvedDest)) { throw new ERR_FS_CP_EINVAL({ message: `cannot copy ${resolvedSrc} to a subdirectory of self ` + `${resolvedDest}`, diff --git a/lib/internal/fs/cp/cp.js b/lib/internal/fs/cp/cp.js index 0724eb730db058..b632c650681e77 100644 --- a/lib/internal/fs/cp/cp.js +++ b/lib/internal/fs/cp/cp.js @@ -54,6 +54,7 @@ const { resolve, sep, } = require('path'); +const fsBinding = internalBinding('fs'); async function cpFn(src, dest, opts) { // Warn about using preserveTimestamps on 32-bit node @@ -344,7 +345,10 @@ async function onLink(destStat, src, dest, opts) { if (!isAbsolute(resolvedDest)) { resolvedDest = resolve(dirname(dest), resolvedDest); } - if (isSrcSubdir(resolvedSrc, resolvedDest)) { + + const srcIsDir = fsBinding.internalModuleStat(src) === 1; + + if (srcIsDir && isSrcSubdir(resolvedSrc, resolvedDest)) { throw new ERR_FS_CP_EINVAL({ message: `cannot copy ${resolvedSrc} to a subdirectory of self ` + `${resolvedDest}`, diff --git a/lib/internal/fs/dir.js b/lib/internal/fs/dir.js index ead08110f1380f..349d0fa2dbb21e 100644 --- a/lib/internal/fs/dir.js +++ b/lib/internal/fs/dir.js @@ -23,7 +23,10 @@ const { } = require('internal/errors'); const { FSReqCallback } = binding; -const internalUtil = require('internal/util'); +const { + assignFunctionName, + promisify, +} = require('internal/util'); const { getDirent, getOptions, @@ -59,9 +62,9 @@ class Dir { validateUint32(this.#options.bufferSize, 'options.bufferSize', true); this.#readPromisified = FunctionPrototypeBind( - internalUtil.promisify(this.#readImpl), this, false); + promisify(this.#readImpl), this, false); this.#closePromisified = FunctionPrototypeBind( - internalUtil.promisify(this.close), this); + promisify(this.close), this); } get path() { @@ -304,12 +307,16 @@ ObjectDefineProperties(Dir.prototype, { [SymbolDispose]: { __proto__: null, ...nonEnumerableDescriptor, - value: Dir.prototype.closeSync, + value: assignFunctionName(SymbolDispose, function() { + this.closeSync(); + }), }, [SymbolAsyncDispose]: { __proto__: null, ...nonEnumerableDescriptor, - value: Dir.prototype.close, + value: assignFunctionName(SymbolAsyncDispose, function() { + this.close(); + }), }, [SymbolAsyncIterator]: { __proto__: null, diff --git a/lib/internal/fs/promises.js b/lib/internal/fs/promises.js index be0095660ea419..a5607810ca5bb2 100644 --- a/lib/internal/fs/promises.js +++ b/lib/internal/fs/promises.js @@ -86,7 +86,6 @@ const { validateInteger, validateObject, validateOneOf, - validateString, kValidateObjectAllowNullable, } = require('internal/validators'); const pathModule = require('path'); @@ -273,15 +272,16 @@ class FileHandle extends EventEmitter { }; async [SymbolAsyncDispose]() { - return this.close(); + await this.close(); } /** * @typedef {import('../webstreams/readablestream').ReadableStream * } ReadableStream + * @param {{ type?: 'bytes', autoClose?: boolean }} [options] * @returns {ReadableStream} */ - readableWebStream(options = { __proto__: null, type: 'bytes' }) { + readableWebStream(options = kEmptyObject) { if (this[kFd] === -1) throw new ERR_INVALID_STATE('The FileHandle is closed'); if (this[kClosePromise]) @@ -290,10 +290,15 @@ class FileHandle extends EventEmitter { throw new ERR_INVALID_STATE('The FileHandle is locked'); this[kLocked] = true; - if (options.type !== undefined) { - validateString(options.type, 'options.type'); - } - if (options.type !== 'bytes') { + validateObject(options, 'options'); + const { + type = 'bytes', + autoClose = false, + } = options; + + validateBoolean(autoClose, 'options.autoClose'); + + if (type !== 'bytes') { process.emitWarning( 'A non-"bytes" options.type has no effect. A byte-oriented steam is ' + 'always created.', @@ -301,9 +306,11 @@ class FileHandle extends EventEmitter { ); } - const readFn = FunctionPrototypeBind(this.read, this); - const ondone = FunctionPrototypeBind(this[kUnref], this); + const ondone = async () => { + this[kUnref](); + if (autoClose) await this.close(); + }; const ReadableStream = lazyReadableStream(); const readable = new ReadableStream({ @@ -315,15 +322,15 @@ class FileHandle extends EventEmitter { const { bytesRead } = await readFn(view, view.byteOffset, view.byteLength); if (bytesRead === 0) { - ondone(); controller.close(); + await ondone(); } controller.byobRequest.respond(bytesRead); }, - cancel() { - ondone(); + async cancel() { + await ondone(); }, }); diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index ce9f81bebc2494..f3f190252730b3 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -30,6 +30,8 @@ const { customInspectSymbol: kInspect, kEmptyObject, promisify, + deprecate, + deprecateProperty, } = require('internal/util'); assertCrypto(); @@ -187,6 +189,13 @@ const { _connectionListener: httpConnectionListener } = http; const dc = require('diagnostics_channel'); const onClientStreamCreatedChannel = dc.channel('http2.client.stream.created'); const onClientStreamStartChannel = dc.channel('http2.client.stream.start'); +const onClientStreamErrorChannel = dc.channel('http2.client.stream.error'); +const onClientStreamFinishChannel = dc.channel('http2.client.stream.finish'); +const onClientStreamCloseChannel = dc.channel('http2.client.stream.close'); +const onServerStreamCreatedChannel = dc.channel('http2.server.stream.created'); +const onServerStreamStartChannel = dc.channel('http2.server.stream.start'); +const onServerStreamErrorChannel = dc.channel('http2.server.stream.error'); +const onServerStreamFinishChannel = dc.channel('http2.server.stream.finish'); let debug = require('internal/util/debuglog').debuglog('http2', (fn) => { debug = fn; @@ -243,7 +252,6 @@ const kPendingRequestCalls = Symbol('kPendingRequestCalls'); const kProceed = Symbol('proceed'); const kRemoteSettings = Symbol('remote-settings'); const kRequestAsyncResource = Symbol('requestAsyncResource'); -const kSelectPadding = Symbol('select-padding'); const kSentHeaders = Symbol('sent-headers'); const kSentTrailers = Symbol('sent-trailers'); const kServer = Symbol('server'); @@ -364,6 +372,18 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) { if (type === NGHTTP2_SESSION_SERVER) { // eslint-disable-next-line no-use-before-define stream = new ServerHttp2Stream(session, handle, id, {}, obj); + if (onServerStreamCreatedChannel.hasSubscribers) { + onServerStreamCreatedChannel.publish({ + stream, + headers: obj, + }); + } + if (onServerStreamStartChannel.hasSubscribers) { + onServerStreamStartChannel.publish({ + stream, + headers: obj, + }); + } if (endOfStream) { stream.push(null); } @@ -426,6 +446,15 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) { reqAsync.runInAsyncScope(process.nextTick, null, emit, stream, event, obj, flags, headers); else process.nextTick(emit, stream, event, obj, flags, headers); + if ((event === 'response' || + event === 'push') && + onClientStreamFinishChannel.hasSubscribers) { + onClientStreamFinishChannel.publish({ + stream, + headers: obj, + flags: flags, + }); + } } if (endOfStream) { stream.push(null); @@ -721,6 +750,11 @@ function onGoawayData(code, lastStreamID, buf) { } } +// TODO(aduh95): remove this in future semver-major +const deprecateWeight = deprecateProperty('weight', + 'Priority signaling has been deprecated as of RFC 1993.', + 'DEP0194'); + // When a ClientHttp2Session is first created, the socket may not yet be // connected. If request() is called during this time, the actual request // will be deferred until the socket is ready to go. @@ -749,12 +783,14 @@ function requestOnConnect(headersList, headersParam, options) { if (options.waitForTrailers) streamOptions |= STREAM_OPTION_GET_TRAILERS; + deprecateWeight(options); + // `ret` will be either the reserved stream ID (if positive) // or an error code (if negative) const ret = session[kHandle].request(headersList, streamOptions, options.parent | 0, - options.weight | 0, + NGHTTP2_DEFAULT_WEIGHT, !!options.exclusive); // In an error condition, one of three possible response codes will be @@ -799,11 +835,7 @@ function requestOnConnect(headersList, headersParam, options) { // // Also sets the default priority options if they are not set. const setAndValidatePriorityOptions = hideStackFrames((options) => { - if (options.weight === undefined) { - options.weight = NGHTTP2_DEFAULT_WEIGHT; - } else { - validateNumber.withoutStackTrace(options.weight, 'options.weight'); - } + deprecateWeight(options); if (options.parent === undefined) { options.parent = 0; @@ -859,25 +891,6 @@ function submitSettings(settings, callback) { } } -// Submits a PRIORITY frame to be sent to the remote peer -// Note: If the silent option is true, the change will be made -// locally with no PRIORITY frame sent. -function submitPriority(options) { - if (this.destroyed) - return; - this[kUpdateTimer](); - - // If the parent is the id, do nothing because a - // stream cannot be made to depend on itself. - if (options.parent === this[kID]) - return; - - this[kHandle].priority(options.parent | 0, - options.weight | 0, - !!options.exclusive, - !!options.silent); -} - // Submit a GOAWAY frame to be sent to the remote peer. // If the lastStreamID is set to <= 0, then the lastProcStreamID will // be used. The opaqueData must either be a typed array or undefined @@ -1081,8 +1094,6 @@ function setupHandle(socket, type, options) { const handle = new binding.Http2Session(type); handle[kOwner] = this; - if (typeof options.selectPadding === 'function') - this[kSelectPadding] = options.selectPadding; handle.consume(socket._handle); handle.ongracefulclosecomplete = this[kMaybeDestroy].bind(this, null); @@ -1968,6 +1979,7 @@ const kSubmitRstStream = 1; const kForceRstStream = 2; function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) { + const type = stream[kSession][kType]; const state = stream[kState]; state.flags |= STREAM_FLAGS_CLOSED; state.rstCode = code; @@ -1998,6 +2010,11 @@ function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) { else stream.once('finish', finishFn); } + + if (type === NGHTTP2_SESSION_CLIENT && + onClientStreamCloseChannel.hasSubscribers) { + onClientStreamCloseChannel.publish({ stream }); + } } function finishCloseStream(code) { @@ -2283,25 +2300,6 @@ class Http2Stream extends Duplex { } } - priority(options) { - if (this.destroyed) - throw new ERR_HTTP2_INVALID_STREAM(); - - assertIsObject(options, 'options'); - options = { ...options }; - setAndValidatePriorityOptions(options); - - const priorityFn = submitPriority.bind(this, options); - - // If the handle has not yet been assigned, queue up the priority - // frame to be sent as soon as the ready event is emitted. - if (this.pending) { - this.once('ready', priorityFn); - return; - } - priorityFn(); - } - sendTrailers(headers) { if (this.destroyed || this.closed) throw new ERR_HTTP2_INVALID_STREAM(); @@ -2424,6 +2422,21 @@ class Http2Stream extends Duplex { setImmediate(() => { session[kMaybeDestroy](); }); + if (err) { + if (session[kType] === NGHTTP2_SESSION_CLIENT) { + if (onClientStreamErrorChannel.hasSubscribers) { + onClientStreamErrorChannel.publish({ + stream: this, + error: err, + }); + } + } else if (onServerStreamErrorChannel.hasSubscribers) { + onServerStreamErrorChannel.publish({ + stream: this, + error: err, + }); + } + } callback(err); } // The Http2Stream can be destroyed if it has closed and if the readable @@ -2459,6 +2472,12 @@ class Http2Stream extends Duplex { } } +// TODO(aduh95): remove this in future semver-major +Http2Stream.prototype.priority = deprecate(function priority(options) { + if (this.destroyed) + throw new ERR_HTTP2_INVALID_STREAM(); +}, 'http2Stream.priority is longer supported after priority signalling was deprecated in RFC 1993', 'DEP0194'); + function callTimeout(self, session) { // If the session is destroyed, this should never actually be invoked, // but just in case... @@ -2808,7 +2827,23 @@ class ServerHttp2Stream extends Http2Stream { if (headRequest) stream[kState].flags |= STREAM_FLAGS_HEAD_REQUEST; - process.nextTick(callback, null, stream, headers, 0); + process.nextTick(() => { + if (onServerStreamStartChannel.hasSubscribers) { + onServerStreamStartChannel.publish({ + stream, + headers, + }); + } + + callback(null, stream, headers, 0); + }); + + if (onServerStreamCreatedChannel.hasSubscribers) { + onServerStreamCreatedChannel.publish({ + stream, + headers, + }); + } } // Initiate a response on this Http2Stream @@ -2856,8 +2891,17 @@ class ServerHttp2Stream extends Http2Stream { } const ret = this[kHandle].respond(headersList, streamOptions); - if (ret < 0) + if (ret < 0) { this.destroy(new NghttpError(ret)); + } else if (onServerStreamFinishChannel.hasSubscribers) { + // No point in running this if the respond() call above fails because + // that would mean that it is an invalid call. + onServerStreamFinishChannel.publish({ + stream: this, + headers, + flags: state.flags, + }); + } } // Initiate a response using an open FD. Note that there are fewer @@ -3300,7 +3344,7 @@ class Http2Server extends NETServer { } async [SymbolAsyncDispose]() { - return promisify(super.close).call(this); + await promisify(super.close).call(this); } } diff --git a/lib/internal/http2/util.js b/lib/internal/http2/util.js index 75312e5aa57c5f..396623d3b9d06f 100644 --- a/lib/internal/http2/util.js +++ b/lib/internal/http2/util.js @@ -229,7 +229,8 @@ const IDX_OPTIONS_MAX_SESSION_MEMORY = 8; const IDX_OPTIONS_MAX_SETTINGS = 9; const IDX_OPTIONS_STREAM_RESET_RATE = 10; const IDX_OPTIONS_STREAM_RESET_BURST = 11; -const IDX_OPTIONS_FLAGS = 12; +const IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION = 12; +const IDX_OPTIONS_FLAGS = 13; function updateOptionsBuffer(options) { let flags = 0; @@ -293,6 +294,13 @@ function updateOptionsBuffer(options) { optionsBuffer[IDX_OPTIONS_STREAM_RESET_BURST] = MathMax(1, options.streamResetBurst); } + + if (typeof options.strictFieldWhitespaceValidation === 'boolean') { + flags |= (1 << IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION); + optionsBuffer[IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION] = + options.strictFieldWhitespaceValidation === true ? 0 : 1; + } + optionsBuffer[IDX_OPTIONS_FLAGS] = flags; } diff --git a/lib/internal/inspector/network_http.js b/lib/internal/inspector/network_http.js index 00b671cc4f8e7a..24c3598fd61763 100644 --- a/lib/internal/inspector/network_http.js +++ b/lib/internal/inspector/network_http.js @@ -16,6 +16,7 @@ const { } = require('internal/inspector/network'); const dc = require('diagnostics_channel'); const { Network } = require('inspector'); +const { MIMEType } = require('internal/mime'); const kRequestUrl = Symbol('kRequestUrl'); @@ -93,6 +94,18 @@ function onClientResponseFinish({ request, response }) { if (typeof request[kInspectorRequestId] !== 'string') { return; } + + let mimeType; + let charset; + try { + const mimeTypeObj = new MIMEType(response.headers['content-type']); + mimeType = mimeTypeObj.essence || ''; + charset = mimeTypeObj.params.get('charset') || ''; + } catch { + mimeType = ''; + charset = ''; + } + Network.responseReceived({ requestId: request[kInspectorRequestId], timestamp: getMonotonicTime(), @@ -102,6 +115,8 @@ function onClientResponseFinish({ request, response }) { status: response.statusCode, statusText: response.statusMessage ?? '', headers: convertHeaderObject(response.headers)[1], + mimeType, + charset, }, }); diff --git a/lib/internal/inspector/network_undici.js b/lib/internal/inspector/network_undici.js index 636e2b21b45b4a..faa0bc35ec0462 100644 --- a/lib/internal/inspector/network_undici.js +++ b/lib/internal/inspector/network_undici.js @@ -1,6 +1,7 @@ 'use strict'; const { + ArrayPrototypeFindIndex, DateNow, } = primordials; @@ -12,6 +13,7 @@ const { } = require('internal/inspector/network'); const dc = require('diagnostics_channel'); const { Network } = require('inspector'); +const { MIMEType } = require('internal/mime'); // Convert an undici request headers array to a plain object (Map) function requestHeadersArrayToDictionary(headers) { @@ -91,6 +93,21 @@ function onClientResponseHeaders({ request, response }) { if (typeof request[kInspectorRequestId] !== 'string') { return; } + + let mimeType; + let charset; + try { + const contentTypeKeyIndex = + ArrayPrototypeFindIndex(response.headers, (header) => header.toString().toLowerCase() === 'content-type'); + const contentType = contentTypeKeyIndex !== -1 ? response.headers[contentTypeKeyIndex + 1].toString() : ''; + const mimeTypeObj = new MIMEType(contentType); + mimeType = mimeTypeObj.essence || ''; + charset = mimeTypeObj.params.get('charset') || ''; + } catch { + mimeType = ''; + charset = ''; + } + const url = `${request.origin}${request.path}`; Network.responseReceived({ requestId: request[kInspectorRequestId], @@ -102,6 +119,8 @@ function onClientResponseHeaders({ request, response }) { status: response.statusCode, statusText: response.statusText, headers: responseHeadersArrayToDictionary(response.headers), + mimeType, + charset, }, }); } diff --git a/lib/internal/main/embedding.js b/lib/internal/main/embedding.js index 93aa8bb38a06a6..105f4a7b6da777 100644 --- a/lib/internal/main/embedding.js +++ b/lib/internal/main/embedding.js @@ -56,6 +56,7 @@ function embedderRunCjs(content) { function: compiledWrapper, cachedDataRejected, sourceMapURL, + sourceURL, } = compileFunctionForCJSLoader( content, filename, @@ -69,7 +70,7 @@ function embedderRunCjs(content) { content, customModule, false, // isGeneratedSource - undefined, // sourceURL, TODO(joyeecheung): should be extracted by V8 + sourceURL, sourceMapURL, ); } diff --git a/lib/internal/main/repl.js b/lib/internal/main/repl.js index 823040321262f6..087ecc0ae0971f 100644 --- a/lib/internal/main/repl.js +++ b/lib/internal/main/repl.js @@ -44,8 +44,7 @@ if (process.env.NODE_REPL_EXTERNAL_MODULE) { throw err; } repl.on('exit', () => { - if (repl._flushing) { - repl.pause(); + if (repl.historyManager.isFlushing) { return repl.once('flushHistory', () => { process.exit(); }); diff --git a/lib/internal/main/worker_thread.js b/lib/internal/main/worker_thread.js index caf64728b754cc..62dc44cf34b739 100644 --- a/lib/internal/main/worker_thread.js +++ b/lib/internal/main/worker_thread.js @@ -203,6 +203,20 @@ port.on('message', (message) => { break; } + case 'data-url': { + const { runEntryPointWithESMLoader } = require('internal/modules/run_main'); + + RegExpPrototypeExec(/^/, ''); // Necessary to reset RegExp statics before user code runs. + const promise = runEntryPointWithESMLoader((cascadedLoader) => { + return cascadedLoader.import(filename, undefined, { __proto__: null }, undefined, true); + }); + + PromisePrototypeThen(promise, undefined, (e) => { + workerOnGlobalUncaughtException(e, true); + }); + break; + } + default: { // script filename // runMain here might be monkey-patched by users in --require. diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 6437b3ab218a71..9eac7ab126f302 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -1640,9 +1640,9 @@ function wrapSafe(filename, content, cjsModuleInstance, format) { ); // Cache the source map for the module if present. - const { sourceMapURL } = script; + const { sourceMapURL, sourceURL } = script; if (sourceMapURL) { - maybeCacheSourceMap(filename, content, cjsModuleInstance, false, undefined, sourceMapURL); + maybeCacheSourceMap(filename, content, cjsModuleInstance, false, sourceURL, sourceMapURL); } return { @@ -1667,7 +1667,7 @@ function wrapSafe(filename, content, cjsModuleInstance, format) { // Cache the source map for the module if present. if (result.sourceMapURL) { - maybeCacheSourceMap(filename, content, cjsModuleInstance, false, undefined, result.sourceMapURL); + maybeCacheSourceMap(filename, content, cjsModuleInstance, false, result.sourceURL, result.sourceMapURL); } return result; diff --git a/lib/internal/modules/esm/assert.js b/lib/internal/modules/esm/assert.js index 1a96569cce109f..a8e564d6707285 100644 --- a/lib/internal/modules/esm/assert.js +++ b/lib/internal/modules/esm/assert.js @@ -57,7 +57,7 @@ function validateAttributes(url, format, const keys = ObjectKeys(importAttributes); for (let i = 0; i < keys.length; i++) { if (keys[i] !== 'type') { - throw new ERR_IMPORT_ATTRIBUTE_UNSUPPORTED(keys[i], importAttributes[keys[i]]); + throw new ERR_IMPORT_ATTRIBUTE_UNSUPPORTED(keys[i], importAttributes[keys[i]], url); } } const validType = formatTypeMap[format]; @@ -102,7 +102,7 @@ function handleInvalidType(url, type) { // `type` might not have been one of the types we understand. if (!ArrayPrototypeIncludes(supportedTypeAttributes, type)) { - throw new ERR_IMPORT_ATTRIBUTE_UNSUPPORTED('type', type); + throw new ERR_IMPORT_ATTRIBUTE_UNSUPPORTED('type', type, url); } // `type` was the wrong value for this format. diff --git a/lib/internal/modules/esm/create_dynamic_module.js b/lib/internal/modules/esm/create_dynamic_module.js index 26e21d8407c729..e66f032e29f3af 100644 --- a/lib/internal/modules/esm/create_dynamic_module.js +++ b/lib/internal/modules/esm/create_dynamic_module.js @@ -44,7 +44,7 @@ import.meta.exports[${nameStringLit}] = { * @param {string} [url=''] - The URL of the module. * @param {(reflect: DynamicModuleReflect) => void} evaluate - The function to evaluate the module. * @typedef {object} DynamicModuleReflect - * @property {string[]} imports - The imports of the module. + * @property {Record>} imports - The imports of the module. * @property {string[]} exports - The exports of the module. * @property {(cb: (reflect: DynamicModuleReflect) => void) => void} onReady - Callback to evaluate the module. */ diff --git a/lib/internal/modules/esm/formats.js b/lib/internal/modules/esm/formats.js index ff0bed228d4e74..fc9f21c909cba1 100644 --- a/lib/internal/modules/esm/formats.js +++ b/lib/internal/modules/esm/formats.js @@ -7,7 +7,7 @@ const { const { getOptionValue } = require('internal/options'); const { getValidatedPath } = require('internal/fs/utils'); const fsBindings = internalBinding('fs'); -const { fs: fsConstants } = internalBinding('constants'); +const { internal: internalConstants } = internalBinding('constants'); const experimentalWasmModules = getOptionValue('--experimental-wasm-modules'); const experimentalAddonModules = getOptionValue('--experimental-addon-modules'); @@ -60,7 +60,7 @@ function getFormatOfExtensionlessFile(url) { if (!experimentalWasmModules) { return 'module'; } const path = getValidatedPath(url); switch (fsBindings.getFormatOfExtensionlessFile(path)) { - case fsConstants.EXTENSIONLESS_FORMAT_WASM: + case internalConstants.EXTENSIONLESS_FORMAT_WASM: return 'wasm'; default: return 'module'; diff --git a/lib/internal/modules/esm/initialize_import_meta.js b/lib/internal/modules/esm/initialize_import_meta.js index d550656a9e6745..5c9390faa81387 100644 --- a/lib/internal/modules/esm/initialize_import_meta.js +++ b/lib/internal/modules/esm/initialize_import_meta.js @@ -51,12 +51,12 @@ function createImportMetaResolve(defaultParentURL, loader, allowParentURL) { /** * Create the `import.meta` object for a module. * @param {object} meta - * @param {{url: string}} context + * @param {{url: string, isMain?: boolean}} context * @param {typeof import('./loader.js').ModuleLoader} loader Reference to the current module loader * @returns {{dirname?: string, filename?: string, url: string, resolve?: Function}} */ function initializeImportMeta(meta, context, loader) { - const { url } = context; + const { url, isMain } = context; // Alphabetical if (StringPrototypeStartsWith(url, 'file:') === true) { @@ -65,6 +65,8 @@ function initializeImportMeta(meta, context, loader) { setLazyPathHelpers(meta, url); } + meta.main = !!isMain; + if (!loader || loader.allowImportMetaResolve) { meta.resolve = createImportMetaResolve(url, loader, experimentalImportMetaResolve); } diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index b47e51a5f0ebf8..f05d863919b751 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -248,10 +248,11 @@ class ModuleLoader { * * @param {string} source Source code of the module. * @param {string} url URL of the module. + * @param {{ isMain?: boolean }|undefined} context - context object containing module metadata. * @returns {object} The module wrap object. */ - createModuleWrap(source, url) { - return compileSourceTextModule(url, source, this); + createModuleWrap(source, url, context = kEmptyObject) { + return compileSourceTextModule(url, source, this, context); } /** @@ -289,7 +290,8 @@ class ModuleLoader { * @returns {Promise} The module object. */ eval(source, url, isEntryPoint = false) { - const wrap = this.createModuleWrap(source, url); + const context = isEntryPoint ? { isMain: true } : undefined; + const wrap = this.createModuleWrap(source, url, context); return this.executeModuleJob(url, wrap, isEntryPoint); } diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js index 56cb8da5d31b56..51aa863dd615f5 100644 --- a/lib/internal/modules/esm/module_job.js +++ b/lib/internal/modules/esm/module_job.js @@ -65,6 +65,37 @@ const isCommonJSGlobalLikeNotDefinedError = (errorMessage) => (globalLike) => errorMessage === `${globalLike} is not defined`, ); + +/** + * + * @param {Error} e + * @param {string} url + * @returns {void} + */ +const explainCommonJSGlobalLikeNotDefinedError = (e, url) => { + if (e?.name === 'ReferenceError' && + isCommonJSGlobalLikeNotDefinedError(e.message)) { + e.message += ' in ES module scope'; + + if (StringPrototypeStartsWith(e.message, 'require ')) { + e.message += ', you can use import instead'; + } + + const packageConfig = + StringPrototypeStartsWith(url, 'file://') && + RegExpPrototypeExec(/\.js(\?[^#]*)?(#.*)?$/, url) !== null && + require('internal/modules/package_json_reader') + .getPackageScopeConfig(url); + if (packageConfig.type === 'module') { + e.message += + '\nThis file is being treated as an ES module because it has a ' + + `'.js' file extension and '${packageConfig.pjsonPath}' contains ` + + '"type": "module". To treat it as a CommonJS script, rename it ' + + 'to use the \'.cjs\' file extension.'; + } + } +}; + class ModuleJobBase { constructor(url, importAttributes, phase, isMain, inspectBrk) { assert(typeof phase === 'number'); @@ -326,27 +357,7 @@ class ModuleJob extends ModuleJobBase { try { await this.module.evaluate(timeout, breakOnSigint); } catch (e) { - if (e?.name === 'ReferenceError' && - isCommonJSGlobalLikeNotDefinedError(e.message)) { - e.message += ' in ES module scope'; - - if (StringPrototypeStartsWith(e.message, 'require ')) { - e.message += ', you can use import instead'; - } - - const packageConfig = - StringPrototypeStartsWith(this.module.url, 'file://') && - RegExpPrototypeExec(/\.js(\?[^#]*)?(#.*)?$/, this.module.url) !== null && - require('internal/modules/package_json_reader') - .getPackageScopeConfig(this.module.url); - if (packageConfig.type === 'module') { - e.message += - '\nThis file is being treated as an ES module because it has a ' + - `'.js' file extension and '${packageConfig.pjsonPath}' contains ` + - '"type": "module". To treat it as a CommonJS script, rename it ' + - 'to use the \'.cjs\' file extension.'; - } - } + explainCommonJSGlobalLikeNotDefinedError(e, this.module.url); throw e; } return { __proto__: null, module: this.module }; @@ -476,8 +487,13 @@ class ModuleJobSync extends ModuleJobBase { throw new ERR_REQUIRE_ASYNC_MODULE(filename, parentFilename); } setHasStartedUserESMExecution(); - const namespace = this.module.evaluateSync(filename, parentFilename); - return { __proto__: null, module: this.module, namespace }; + try { + const namespace = this.module.evaluateSync(filename, parentFilename); + return { __proto__: null, module: this.module, namespace }; + } catch (e) { + explainCommonJSGlobalLikeNotDefinedError(e, this.module.url); + throw e; + } } } diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index 0a8e4c9e5d3af5..4d731d03ccbbe1 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -1,16 +1,16 @@ 'use strict'; const { - ArrayPrototypeMap, ArrayPrototypePush, FunctionPrototypeCall, JSONParse, - ObjectKeys, + ObjectAssign, ObjectPrototypeHasOwnProperty, ReflectApply, SafeArrayIterator, SafeMap, SafeSet, + SafeWeakMap, StringPrototypeIncludes, StringPrototypeReplaceAll, StringPrototypeSlice, @@ -103,7 +103,8 @@ translators.set('module', function moduleStrategy(url, source, isMain) { source = stringify(source); debug(`Translating StandardModule ${url}`); const { compileSourceTextModule } = require('internal/modules/esm/utils'); - const module = compileSourceTextModule(url, source, this); + const context = isMain ? { isMain } : undefined; + const module = compileSourceTextModule(url, source, this, context); return module; }); @@ -121,10 +122,10 @@ translators.set('module', function moduleStrategy(url, source, isMain) { function loadCJSModule(module, source, url, filename, isMain) { const compileResult = compileFunctionForCJSLoader(source, filename, false /* is_sea_main */, false); - const { function: compiledWrapper, sourceMapURL } = compileResult; + const { function: compiledWrapper, sourceMapURL, sourceURL } = compileResult; // Cache the source map for the cjs module if present. if (sourceMapURL) { - maybeCacheSourceMap(url, source, module, false, undefined, sourceMapURL); + maybeCacheSourceMap(url, source, module, false, sourceURL, sourceMapURL); } const cascadedLoader = require('internal/modules/esm/loader').getOrInitializeCascadedLoader(); @@ -483,6 +484,14 @@ translators.set('json', function jsonStrategy(url, source) { }); // Strategy for loading a wasm module +// This logic should collapse into WebAssembly Module Record in future. +/** + * @type {WeakMap< + * import('internal/modules/esm/utils').ModuleNamespaceObject, + * WebAssembly.Instance + * >} [[Instance]] slot proxy for WebAssembly Module Record + */ +const wasmInstances = new SafeWeakMap(); translators.set('wasm', async function(url, source) { emitExperimentalWarning('Importing WebAssembly modules'); @@ -501,19 +510,61 @@ translators.set('wasm', async function(url, source) { throw err; } - const imports = - ArrayPrototypeMap(WebAssembly.Module.imports(compiled), - ({ module }) => module); - const exports = - ArrayPrototypeMap(WebAssembly.Module.exports(compiled), - ({ name }) => name); + const importsList = new SafeSet(); + const wasmGlobalImports = []; + for (const impt of WebAssembly.Module.imports(compiled)) { + if (impt.kind === 'global') { + ArrayPrototypePush(wasmGlobalImports, impt); + } + importsList.add(impt.module); + } + + const exportsList = new SafeSet(); + const wasmGlobalExports = new SafeSet(); + for (const expt of WebAssembly.Module.exports(compiled)) { + if (expt.kind === 'global') { + wasmGlobalExports.add(expt.name); + } + exportsList.add(expt.name); + } - const createDynamicModule = require( - 'internal/modules/esm/create_dynamic_module'); - const { module } = createDynamicModule(imports, exports, url, (reflect) => { + const createDynamicModule = require('internal/modules/esm/create_dynamic_module'); + + const { module } = createDynamicModule([...importsList], [...exportsList], url, (reflect) => { + for (const impt of importsList) { + const importNs = reflect.imports[impt]; + const wasmInstance = wasmInstances.get(importNs); + if (wasmInstance) { + const wrappedModule = ObjectAssign({ __proto__: null }, reflect.imports[impt]); + for (const { module, name } of wasmGlobalImports) { + if (module !== impt) { + continue; + } + // Import of Wasm module global -> get direct WebAssembly.Global wrapped value. + // JS API validations otherwise remain the same. + wrappedModule[name] = wasmInstance[name]; + } + reflect.imports[impt] = wrappedModule; + } + } + // In cycles importing unexecuted Wasm, wasmInstance will be undefined, which will fail during + // instantiation, since all bindings will be in the Temporal Deadzone (TDZ). const { exports } = new WebAssembly.Instance(compiled, reflect.imports); - for (const expt of ObjectKeys(exports)) { - reflect.exports[expt].set(exports[expt]); + wasmInstances.set(module.getNamespace(), exports); + for (const expt of exportsList) { + let val = exports[expt]; + // Unwrap WebAssembly.Global for JS bindings + if (wasmGlobalExports.has(expt)) { + try { + // v128 will throw in GetGlobalValue, see: + // https://webassembly.github.io/esm-integration/js-api/index.html#getglobalvalue + val = val.value; + } catch { + // v128 doesn't support ToJsValue() -> use undefined (ideally should stay in TDZ) + continue; + } + } + reflect.exports[expt].set(val); } }); // WebAssembly modules support source phase imports, to import the compiled module diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js index 3c925cb0eea901..ec6f1f676ec940 100644 --- a/lib/internal/modules/esm/utils.js +++ b/lib/internal/modules/esm/utils.js @@ -42,6 +42,7 @@ const { const { emitExperimentalWarning, getCWDURL, + kEmptyObject, } = require('internal/util'); const assert = require('internal/assert'); const { @@ -188,7 +189,7 @@ function registerModule(referrer, registry) { */ function defaultInitializeImportMetaForModule(meta, wrap) { const cascadedLoader = require('internal/modules/esm/loader').getOrInitializeCascadedLoader(); - return cascadedLoader.importMetaInitialize(meta, { url: wrap.url }); + return cascadedLoader.importMetaInitialize(meta, { url: wrap.url, isMain: wrap.isMain }); } /** @@ -342,18 +343,25 @@ async function initializeHooks() { * @param {string} source Source code of the module. * @param {typeof import('./loader.js').ModuleLoader|undefined} cascadedLoader If provided, * register the module for default handling. + * @param {{ isMain?: boolean }|undefined} context - context object containing module metadata. * @returns {ModuleWrap} */ -function compileSourceTextModule(url, source, cascadedLoader) { +function compileSourceTextModule(url, source, cascadedLoader, context = kEmptyObject) { const hostDefinedOption = cascadedLoader ? source_text_module_default_hdo : undefined; const wrap = new ModuleWrap(url, undefined, source, 0, 0, hostDefinedOption); if (!cascadedLoader) { return wrap; } + + const { isMain } = context; + if (isMain) { + wrap.isMain = true; + } + // Cache the source map for the module if present. if (wrap.sourceMapURL) { - maybeCacheSourceMap(url, source, wrap, false, undefined, wrap.sourceMapURL); + maybeCacheSourceMap(url, source, wrap, false, wrap.sourceURL, wrap.sourceMapURL); } return wrap; } diff --git a/lib/internal/options.js b/lib/internal/options.js index 12548ac49a2aff..fef0d61d143335 100644 --- a/lib/internal/options.js +++ b/lib/internal/options.js @@ -13,6 +13,7 @@ const { getCLIOptionsInfo, getEmbedderOptions: getEmbedderOptionsFromBinding, getEnvOptionsInputType, + getNamespaceOptionsInputType, } = internalBinding('options'); let warnOnAllowUnauthorized = true; @@ -38,7 +39,22 @@ function getEmbedderOptions() { } function generateConfigJsonSchema() { - const map = getEnvOptionsInputType(); + const envOptionsMap = getEnvOptionsInputType(); + const namespaceOptionsMap = getNamespaceOptionsInputType(); + + function createPropertyForType(type) { + if (type === 'array') { + return { + __proto__: null, + oneOf: [ + { __proto__: null, type: 'string' }, + { __proto__: null, items: { __proto__: null, type: 'string', minItems: 1 }, type: 'array' }, + ], + }; + } + + return { __proto__: null, type }; + } const schema = { __proto__: null, @@ -60,24 +76,43 @@ function generateConfigJsonSchema() { type: 'object', }; - const nodeOptions = schema.properties.nodeOptions.properties; + // Get the root properties object for adding namespaces + const rootProperties = schema.properties; + const nodeOptions = rootProperties.nodeOptions.properties; - for (const { 0: key, 1: type } of map) { + // Add env options to nodeOptions (backward compatibility) + for (const { 0: key, 1: type } of envOptionsMap) { const keyWithoutPrefix = StringPrototypeReplace(key, '--', ''); - if (type === 'array') { - nodeOptions[keyWithoutPrefix] = { - __proto__: null, - oneOf: [ - { __proto__: null, type: 'string' }, - { __proto__: null, items: { __proto__: null, type: 'string', minItems: 1 }, type: 'array' }, - ], - }; - } else { - nodeOptions[keyWithoutPrefix] = { __proto__: null, type }; + nodeOptions[keyWithoutPrefix] = createPropertyForType(type); + } + + // Add namespace properties at the root level + for (const { 0: namespace, 1: optionsMap } of namespaceOptionsMap) { + // Create namespace object at the root level + rootProperties[namespace] = { + __proto__: null, + type: 'object', + additionalProperties: false, + properties: { __proto__: null }, + }; + + const namespaceProperties = rootProperties[namespace].properties; + + // Add all options for this namespace + for (const { 0: optionName, 1: optionType } of optionsMap) { + const keyWithoutPrefix = StringPrototypeReplace(optionName, '--', ''); + namespaceProperties[keyWithoutPrefix] = createPropertyForType(optionType); } + + // Sort the namespace properties alphabetically + const sortedNamespaceKeys = ArrayPrototypeSort(ObjectKeys(namespaceProperties)); + const sortedNamespaceProperties = ObjectFromEntries( + ArrayPrototypeMap(sortedNamespaceKeys, (key) => [key, namespaceProperties[key]]), + ); + rootProperties[namespace].properties = sortedNamespaceProperties; } - // Sort the proerties by key alphabetically. + // Sort the top-level properties by key alphabetically const sortedKeys = ArrayPrototypeSort(ObjectKeys(nodeOptions)); const sortedProperties = ObjectFromEntries( ArrayPrototypeMap(sortedKeys, (key) => [key, nodeOptions[key]]), @@ -85,6 +120,14 @@ function generateConfigJsonSchema() { schema.properties.nodeOptions.properties = sortedProperties; + // Also sort the root level properties + const sortedRootKeys = ArrayPrototypeSort(ObjectKeys(rootProperties)); + const sortedRootProperties = ObjectFromEntries( + ArrayPrototypeMap(sortedRootKeys, (key) => [key, rootProperties[key]]), + ); + + schema.properties = sortedRootProperties; + return schema; } diff --git a/lib/internal/perf/event_loop_delay.js b/lib/internal/perf/event_loop_delay.js index 8281ea105f4083..17581b1310c5c0 100644 --- a/lib/internal/perf/event_loop_delay.js +++ b/lib/internal/perf/event_loop_delay.js @@ -3,6 +3,7 @@ const { ReflectConstruct, SafeMap, Symbol, + SymbolDispose, } = primordials; const { @@ -38,7 +39,7 @@ const { const kEnabled = Symbol('kEnabled'); class ELDHistogram extends Histogram { - constructor(i) { + constructor() { throw new ERR_ILLEGAL_CONSTRUCTOR(); } @@ -65,6 +66,10 @@ class ELDHistogram extends Histogram { this[kHandle].stop(); return true; } + + [SymbolDispose]() { + this.disable(); + } } /** diff --git a/lib/internal/readline/interface.js b/lib/internal/readline/interface.js index 89f1a8d9df565e..4a9272c0950243 100644 --- a/lib/internal/readline/interface.js +++ b/lib/internal/readline/interface.js @@ -3,14 +3,12 @@ const { ArrayFrom, ArrayPrototypeFilter, - ArrayPrototypeIndexOf, ArrayPrototypeJoin, ArrayPrototypeMap, ArrayPrototypePop, ArrayPrototypePush, ArrayPrototypeReverse, ArrayPrototypeShift, - ArrayPrototypeSplice, ArrayPrototypeUnshift, DateNow, FunctionPrototypeCall, @@ -19,6 +17,7 @@ const { MathMax, MathMaxApply, NumberIsFinite, + ObjectDefineProperty, ObjectSetPrototypeOf, RegExpPrototypeExec, SafeStringIterator, @@ -30,7 +29,6 @@ const { StringPrototypeSlice, StringPrototypeSplit, StringPrototypeStartsWith, - StringPrototypeTrim, Symbol, SymbolAsyncIterator, SymbolDispose, @@ -46,12 +44,13 @@ const { const { validateAbortSignal, - validateArray, - validateNumber, validateString, validateUint32, } = require('internal/validators'); -const { kEmptyObject } = require('internal/util'); +const { + assignFunctionName, + kEmptyObject, +} = require('internal/util'); const { inspect, getStringWidth, @@ -64,7 +63,6 @@ const { charLengthLeft, commonPrefix, kSubstringSearch, - reverseString, } = require('internal/readline/utils'); let emitKeypressEvents; let kFirstEventParam; @@ -75,8 +73,8 @@ const { } = require('internal/readline/callbacks'); const { StringDecoder } = require('string_decoder'); +const { ReplHistory } = require('internal/repl/history'); -const kHistorySize = 30; const kMaxUndoRedoStackSize = 2048; const kMincrlfDelay = 100; /** @@ -150,7 +148,6 @@ const kWriteToOutput = Symbol('_writeToOutput'); const kYank = Symbol('_yank'); const kYanking = Symbol('_yanking'); const kYankPop = Symbol('_yankPop'); -const kNormalizeHistoryLineEndings = Symbol('_normalizeHistoryLineEndings'); const kSavePreviousState = Symbol('_savePreviousState'); const kRestorePreviousState = Symbol('_restorePreviousState'); const kPreviousLine = Symbol('_previousLine'); @@ -172,9 +169,6 @@ function InterfaceConstructor(input, output, completer, terminal) { FunctionPrototypeCall(EventEmitter, this); - let history; - let historySize; - let removeHistoryDuplicates = false; let crlfDelay; let prompt = '> '; let signal; @@ -184,14 +178,17 @@ function InterfaceConstructor(input, output, completer, terminal) { output = input.output; completer = input.completer; terminal = input.terminal; - history = input.history; - historySize = input.historySize; signal = input.signal; + + // It is possible to configure the history through the input object + const historySize = input.historySize; + const history = input.history; + const removeHistoryDuplicates = input.removeHistoryDuplicates; + if (input.tabSize !== undefined) { validateUint32(input.tabSize, 'tabSize', true); this.tabSize = input.tabSize; } - removeHistoryDuplicates = input.removeHistoryDuplicates; if (input.prompt !== undefined) { prompt = input.prompt; } @@ -212,24 +209,18 @@ function InterfaceConstructor(input, output, completer, terminal) { crlfDelay = input.crlfDelay; input = input.input; - } - if (completer !== undefined && typeof completer !== 'function') { - throw new ERR_INVALID_ARG_VALUE('completer', completer); + input.size = historySize; + input.history = history; + input.removeHistoryDuplicates = removeHistoryDuplicates; } - if (history === undefined) { - history = []; - } else { - validateArray(history, 'history'); - } + this.setupHistoryManager(input); - if (historySize === undefined) { - historySize = kHistorySize; + if (completer !== undefined && typeof completer !== 'function') { + throw new ERR_INVALID_ARG_VALUE('completer', completer); } - validateNumber(historySize, 'historySize', 0); - // Backwards compat; check the isTTY prop of the output stream // when `terminal` was not specified if (terminal === undefined && !(output === null || output === undefined)) { @@ -245,8 +236,6 @@ function InterfaceConstructor(input, output, completer, terminal) { this.input = input; this[kUndoStack] = []; this[kRedoStack] = []; - this.history = history; - this.historySize = historySize; this[kPreviousCursorCols] = -1; // The kill ring is a global list of blocks of text that were previously @@ -257,7 +246,6 @@ function InterfaceConstructor(input, output, completer, terminal) { this[kKillRing] = []; this[kKillRingCursor] = 0; - this.removeHistoryDuplicates = !!removeHistoryDuplicates; this.crlfDelay = crlfDelay ? MathMax(kMincrlfDelay, crlfDelay) : kMincrlfDelay; @@ -267,7 +255,6 @@ function InterfaceConstructor(input, output, completer, terminal) { this.terminal = !!terminal; - function onerror(err) { self.emit('error', err); } @@ -346,8 +333,6 @@ function InterfaceConstructor(input, output, completer, terminal) { // Cursor position on the line. this.cursor = 0; - this.historyIndex = -1; - if (output !== null && output !== undefined) output.on('resize', onresize); @@ -400,6 +385,36 @@ class Interface extends InterfaceConstructor { return this[kPrompt]; } + setupHistoryManager(options) { + this.historyManager = new ReplHistory(this, options); + + if (options.onHistoryFileLoaded) { + this.historyManager.initialize(options.onHistoryFileLoaded); + } + + ObjectDefineProperty(this, 'history', { + __proto__: null, configurable: true, enumerable: true, + get() { return this.historyManager.history; }, + set(newHistory) { return this.historyManager.history = newHistory; }, + }); + + ObjectDefineProperty(this, 'historyIndex', { + __proto__: null, configurable: true, enumerable: true, + get() { return this.historyManager.index; }, + set(historyIndex) { return this.historyManager.index = historyIndex; }, + }); + + ObjectDefineProperty(this, 'historySize', { + __proto__: null, configurable: true, enumerable: true, + get() { return this.historyManager.size; }, + }); + + ObjectDefineProperty(this, 'isFlushing', { + __proto__: null, configurable: true, enumerable: true, + get() { return this.historyManager.isFlushing; }, + }); + } + [kSetRawMode](mode) { const wasInRawMode = this.input.isRaw; @@ -475,70 +490,8 @@ class Interface extends InterfaceConstructor { } } - // Convert newlines to a consistent format for history storage - [kNormalizeHistoryLineEndings](line, from, to, reverse = true) { - // Multiline history entries are saved reversed - // History is structured with the newest entries at the top - // and the oldest at the bottom. Multiline histories, however, only occupy - // one line in the history file. When loading multiline history with - // an old node binary, the history will be saved in the old format. - // This is why we need to reverse the multilines. - // Reversing the multilines is necessary when adding / editing and displaying them - if (reverse) { - // First reverse the lines for proper order, then convert separators - return reverseString(line, from, to); - } - // For normal cases (saving to history or non-multiline entries) - return StringPrototypeReplaceAll(line, from, to); - } - [kAddHistory]() { - if (this.line.length === 0) return ''; - - // If the history is disabled then return the line - if (this.historySize === 0) return this.line; - - // If the trimmed line is empty then return the line - if (StringPrototypeTrim(this.line).length === 0) return this.line; - - // This is necessary because each line would be saved in the history while creating - // A new multiline, and we don't want that. - if (this[kIsMultiline] && this.historyIndex === -1) { - ArrayPrototypeShift(this.history); - } else if (this[kLastCommandErrored]) { - // If the last command errored and we are trying to edit the history to fix it - // Remove the broken one from the history - ArrayPrototypeShift(this.history); - } - - const normalizedLine = this[kNormalizeHistoryLineEndings](this.line, '\n', '\r', true); - - if (this.history.length === 0 || this.history[0] !== normalizedLine) { - if (this.removeHistoryDuplicates) { - // Remove older history line if identical to new one - const dupIndex = ArrayPrototypeIndexOf(this.history, this.line); - if (dupIndex !== -1) ArrayPrototypeSplice(this.history, dupIndex, 1); - } - - // Add the new line to the history - ArrayPrototypeUnshift(this.history, normalizedLine); - - // Only store so many - if (this.history.length > this.historySize) - ArrayPrototypePop(this.history); - } - - this.historyIndex = -1; - - // The listener could change the history object, possibly - // to remove the last added entry if it is sensitive and should - // not be persisted in the history, like a password - const line = this[kIsMultiline] ? reverseString(this.history[0]) : this.history[0]; - - // Emit history event to notify listeners of update - this.emit('history', this.history); - - return line; + return this.historyManager.addHistory(this[kIsMultiline], this[kLastCommandErrored]); } [kRefreshLine]() { @@ -611,6 +564,9 @@ class Interface extends InterfaceConstructor { * @returns {void | Interface} */ pause() { + if (this.closed) { + throw new ERR_USE_AFTER_CLOSE('readline'); + } if (this.paused) return; this.input.pause(); this.paused = true; @@ -623,6 +579,9 @@ class Interface extends InterfaceConstructor { * @returns {void | Interface} */ resume() { + if (this.closed) { + throw new ERR_USE_AFTER_CLOSE('readline'); + } if (!this.paused) return; this.input.resume(); this.paused = false; @@ -643,6 +602,9 @@ class Interface extends InterfaceConstructor { * @returns {void} */ write(d, key) { + if (this.closed) { + throw new ERR_USE_AFTER_CLOSE('readline'); + } if (this.paused) this.resume(); if (this.terminal) { this[kTtyWrite](d, key); @@ -1172,26 +1134,12 @@ class Interface extends InterfaceConstructor { // + N. Only show this after two/three UPs or DOWNs, not on the first // one. [kHistoryNext]() { - if (this.historyIndex >= 0) { - this[kBeforeEdit](this.line, this.cursor); - const search = this[kSubstringSearch] || ''; - let index = this.historyIndex - 1; - while ( - index >= 0 && - (!StringPrototypeStartsWith(this.history[index], search) || - this.line === this.history[index]) - ) { - index--; - } - if (index === -1) { - this[kSetLine](search); - } else { - this[kSetLine](this[kNormalizeHistoryLineEndings](this.history[index], '\r', '\n')); - } - this.historyIndex = index; - this.cursor = this.line.length; // Set cursor to end of line. - this[kRefreshLine](); - } + if (!this.historyManager.canNavigateToNext()) { return; } + + this[kBeforeEdit](this.line, this.cursor); + this[kSetLine](this.historyManager.navigateToNext(this[kSubstringSearch])); + this.cursor = this.line.length; // Set cursor to end of line. + this[kRefreshLine](); } [kMoveUpOrHistoryPrev]() { @@ -1206,26 +1154,12 @@ class Interface extends InterfaceConstructor { } [kHistoryPrev]() { - if (this.historyIndex < this.history.length && this.history.length) { - this[kBeforeEdit](this.line, this.cursor); - const search = this[kSubstringSearch] || ''; - let index = this.historyIndex + 1; - while ( - index < this.history.length && - (!StringPrototypeStartsWith(this.history[index], search) || - this.line === this.history[index]) - ) { - index++; - } - if (index === this.history.length) { - this[kSetLine](search); - } else { - this[kSetLine](this[kNormalizeHistoryLineEndings](this.history[index], '\r', '\n')); - } - this.historyIndex = index; - this.cursor = this.line.length; // Set cursor to end of line. - this[kRefreshLine](); - } + if (!this.historyManager.canNavigateToPrevious()) { return; } + + this[kBeforeEdit](this.line, this.cursor); + this[kSetLine](this.historyManager.navigateToPrevious(this[kSubstringSearch])); + this.cursor = this.line.length; // Set cursor to end of line. + this[kRefreshLine](); } // Returns the last character's display position of the given string @@ -1628,7 +1562,9 @@ class Interface extends InterfaceConstructor { return this[kLineObjectStream]; } } -Interface.prototype[SymbolDispose] = Interface.prototype.close; +Interface.prototype[SymbolDispose] = assignFunctionName(SymbolDispose, function() { + this.close(); +}); module.exports = { Interface, diff --git a/lib/internal/repl.js b/lib/internal/repl.js index 2dc79b2784e189..2552aabf173e0d 100644 --- a/lib/internal/repl.js +++ b/lib/internal/repl.js @@ -40,14 +40,21 @@ function createRepl(env, opts, cb) { opts.replMode = REPL.REPL_MODE_SLOPPY; } - const historySize = Number(env.NODE_REPL_HISTORY_SIZE); - if (!NumberIsNaN(historySize) && historySize > 0) { - opts.historySize = historySize; + const size = Number(env.NODE_REPL_HISTORY_SIZE); + if (!NumberIsNaN(size) && size > 0) { + opts.size = size; } else { - opts.historySize = 1000; + opts.size = 1000; } - const repl = REPL.start(opts); const term = 'terminal' in opts ? opts.terminal : process.stdout.isTTY; - repl.setupHistory(term ? env.NODE_REPL_HISTORY : '', cb); + opts.filePath = term ? env.NODE_REPL_HISTORY : ''; + + const repl = REPL.start(opts); + + repl.setupHistory({ + filePath: opts.filePath, + size: opts.size, + onHistoryFileLoaded: cb, + }); } diff --git a/lib/internal/repl/history.js b/lib/internal/repl/history.js index 09647493895707..d05bb19d733a22 100644 --- a/lib/internal/repl/history.js +++ b/lib/internal/repl/history.js @@ -1,14 +1,21 @@ 'use strict'; const { + ArrayPrototypeIndexOf, ArrayPrototypeJoin, + ArrayPrototypePop, + ArrayPrototypeShift, + ArrayPrototypeSplice, + ArrayPrototypeUnshift, Boolean, - FunctionPrototype, RegExpPrototypeSymbolSplit, + StringPrototypeStartsWith, StringPrototypeTrim, + Symbol, } = primordials; -const { Interface } = require('readline'); +const { validateNumber, validateArray } = require('internal/validators'); + const path = require('path'); const fs = require('fs'); const os = require('os'); @@ -17,166 +24,400 @@ let debug = require('internal/util/debuglog').debuglog('repl', (fn) => { }); const permission = require('internal/process/permission'); const { clearTimeout, setTimeout } = require('timers'); +const { + reverseString, +} = require('internal/readline/utils'); -const noop = FunctionPrototype; - -// XXX(chrisdickinson): The 15ms debounce value is somewhat arbitrary. // The debounce is to guard against code pasted into the REPL. const kDebounceHistoryMS = 15; +const kHistorySize = 30; -module.exports = setupHistory; +// Class fields +const kTimer = Symbol('_kTimer'); +const kWriting = Symbol('_kWriting'); +const kPending = Symbol('_kPending'); +const kRemoveHistoryDuplicates = Symbol('_kRemoveHistoryDuplicates'); +const kHistoryHandle = Symbol('_kHistoryHandle'); +const kHistoryPath = Symbol('_kHistoryPath'); +const kContext = Symbol('_kContext'); +const kIsFlushing = Symbol('_kIsFlushing'); +const kHistory = Symbol('_kHistory'); +const kSize = Symbol('_kSize'); +const kIndex = Symbol('_kIndex'); -function _writeToOutput(repl, message) { - repl._writeToOutput(message); - repl._refreshLine(); -} +// Class methods +const kNormalizeLineEndings = Symbol('_kNormalizeLineEndings'); +const kWriteToOutput = Symbol('_kWriteToOutput'); +const kOnLine = Symbol('_kOnLine'); +const kOnExit = Symbol('_kOnExit'); +const kInitializeHistory = Symbol('_kInitializeHistory'); +const kHandleHistoryInitError = Symbol('_kHandleHistoryInitError'); +const kHasWritePermission = Symbol('_kHasWritePermission'); +const kValidateOptions = Symbol('_kValidateOptions'); +const kResolveHistoryPath = Symbol('_kResolveHistoryPath'); +const kReplHistoryMessage = Symbol('_kReplHistoryMessage'); +const kFlushHistory = Symbol('_kFlushHistory'); +const kGetHistoryPath = Symbol('_kGetHistoryPath'); -function setupHistory(repl, historyPath, ready) { - // Empty string disables persistent history - if (typeof historyPath === 'string') - historyPath = StringPrototypeTrim(historyPath); +class ReplHistory { + constructor(context, options) { + this[kValidateOptions](options); - if (historyPath === '') { - repl._historyPrev = _replHistoryMessage; - return ready(null, repl); + this[kHistoryPath] = ReplHistory[kGetHistoryPath](options); + this[kContext] = context; + this[kTimer] = null; + this[kWriting] = false; + this[kPending] = false; + this[kRemoveHistoryDuplicates] = options.removeHistoryDuplicates || false; + this[kHistoryHandle] = null; + this[kIsFlushing] = false; + this[kSize] = options.size ?? context.historySize ?? kHistorySize; + this[kHistory] = options.history ?? []; + this[kIndex] = -1; } - if (!historyPath) { - try { - historyPath = path.join(os.homedir(), '.node_repl_history'); - } catch (err) { - _writeToOutput(repl, '\nError: Could not get the home directory.\n' + - 'REPL session history will not be persisted.\n'); + initialize(onReadyCallback) { + // Empty string disables persistent history + if (this[kHistoryPath] === '') { + // Save a reference to the context's original _historyPrev + this.historyPrev = this[kContext]._historyPrev; + this[kContext]._historyPrev = this[kReplHistoryMessage].bind(this); + return onReadyCallback(null, this[kContext]); + } + + const resolvedPath = this[kResolveHistoryPath](); + if (!resolvedPath) { + ReplHistory[kWriteToOutput]( + this[kContext], + '\nError: Could not get the home directory.\n' + + 'REPL session history will not be persisted.\n', + ); - debug(err.stack); - repl._historyPrev = _replHistoryMessage; - return ready(null, repl); + // Save a reference to the context's original _historyPrev + this.historyPrev = this[kContext]._historyPrev; + this[kContext]._historyPrev = this[kReplHistoryMessage].bind(this); + return onReadyCallback(null, this[kContext]); } + + if (!this[kHasWritePermission]()) { + ReplHistory[kWriteToOutput]( + this[kContext], + '\nAccess to FileSystemWrite is restricted.\n' + + 'REPL session history will not be persisted.\n', + ); + return onReadyCallback(null, this[kContext]); + } + + this[kContext].pause(); + + this[kInitializeHistory](onReadyCallback).catch((err) => { + this[kHandleHistoryInitError](err, onReadyCallback); + }); } - if (permission.isEnabled() && permission.has('fs.write', historyPath) === false) { - _writeToOutput(repl, '\nAccess to FileSystemWrite is restricted.\n' + - 'REPL session history will not be persisted.\n'); - return ready(null, repl); + addHistory(isMultiline, lastCommandErrored) { + const line = this[kContext].line; + + if (line.length === 0) return ''; + + // If the history is disabled then return the line + if (this[kSize] === 0) return line; + + // If the trimmed line is empty then return the line + if (StringPrototypeTrim(line).length === 0) return line; + + // This is necessary because each line would be saved in the history while creating + // a new multiline, and we don't want that. + if (isMultiline && this[kIndex] === -1) { + ArrayPrototypeShift(this[kHistory]); + } else if (lastCommandErrored) { + // If the last command errored and we are trying to edit the history to fix it + // remove the broken one from the history + ArrayPrototypeShift(this[kHistory]); + } + + const normalizedLine = ReplHistory[kNormalizeLineEndings](line, '\n', '\r'); + + if (this[kHistory].length === 0 || this[kHistory][0] !== normalizedLine) { + if (this[kRemoveHistoryDuplicates]) { + // Remove older history line if identical to new one + const dupIndex = ArrayPrototypeIndexOf(this[kHistory], line); + if (dupIndex !== -1) ArrayPrototypeSplice(this[kHistory], dupIndex, 1); + } + + // Add the new line to the history + ArrayPrototypeUnshift(this[kHistory], normalizedLine); + + // Only store so many + if (this[kHistory].length > this[kSize]) + ArrayPrototypePop(this[kHistory]); + } + + this[kIndex] = -1; + + const finalLine = isMultiline ? reverseString(this[kHistory][0]) : this[kHistory][0]; + + // The listener could change the history object, possibly + // to remove the last added entry if it is sensitive and should + // not be persisted in the history, like a password + // Emit history event to notify listeners of update + this[kContext].emit('history', this[kHistory]); + + return finalLine; } - let timer = null; - let writing = false; - let pending = false; - repl.pause(); - // History files are conventionally not readable by others: - // https://github.com/nodejs/node/issues/3392 - // https://github.com/nodejs/node/pull/3394 - fs.open(historyPath, 'a+', 0o0600, oninit); + canNavigateToNext() { + return this[kIndex] > -1 && this[kHistory].length > 0; + } + + navigateToNext(substringSearch) { + if (!this.canNavigateToNext()) { + return null; + } + const search = substringSearch || ''; + let index = this[kIndex] - 1; + + while ( + index >= 0 && + (!StringPrototypeStartsWith(this[kHistory][index], search) || + this[kContext].line === this[kHistory][index]) + ) { + index--; + } - function oninit(err, hnd) { - if (err) { - // Cannot open history file. - // Don't crash, just don't persist history. - _writeToOutput(repl, '\nError: Could not open history file.\n' + - 'REPL session history will not be persisted.\n'); - debug(err.stack); + this[kIndex] = index; - repl._historyPrev = _replHistoryMessage; - repl.resume(); - return ready(null, repl); + if (index === -1) { + return search; } - fs.close(hnd, onclose); + + return ReplHistory[kNormalizeLineEndings](this[kHistory][index], '\r', '\n'); + } + + canNavigateToPrevious() { + return this[kHistory].length !== this[kIndex] && this[kHistory].length > 0; } - function onclose(err) { - if (err) { - return ready(err); + navigateToPrevious(substringSearch = '') { + if (!this.canNavigateToPrevious()) { + return null; + } + const search = substringSearch || ''; + let index = this[kIndex] + 1; + + while ( + index < this[kHistory].length && + (!StringPrototypeStartsWith(this[kHistory][index], search) || + this[kContext].line === this[kHistory][index]) + ) { + index++; } - fs.readFile(historyPath, 'utf8', onread); + + this[kIndex] = index; + + if (index === this[kHistory].length) { + return search; + } + + return ReplHistory[kNormalizeLineEndings](this[kHistory][index], '\r', '\n'); } - function onread(err, data) { - if (err) { - return ready(err); + get size() { return this[kSize]; } + get isFlushing() { return this[kIsFlushing]; } + get history() { return this[kHistory]; } + set history(value) { this[kHistory] = value; } + get index() { return this[kIndex]; } + set index(value) { this[kIndex] = value; } + + // Start private methods + + static [kGetHistoryPath](options) { + let historyPath = options.filePath; + if (typeof historyPath === 'string') { + historyPath = StringPrototypeTrim(historyPath); } + return historyPath; + } + + static [kNormalizeLineEndings](line, from, to) { + // Multiline history entries are saved reversed + // History is structured with the newest entries at the top + // and the oldest at the bottom. Multiline histories, however, only occupy + // one line in the history file. When loading multiline history with + // an old node binary, the history will be saved in the old format. + // This is why we need to reverse the multilines. + // Reversing the multilines is necessary when adding / editing and displaying them + return reverseString(line, from, to); + } - if (data) { - repl.history = RegExpPrototypeSymbolSplit(/\r?\n+/, data, repl.historySize); - } else { - repl.history = []; + static [kWriteToOutput](context, message) { + if (typeof context._writeToOutput === 'function') { + context._writeToOutput(message); + if (typeof context._refreshLine === 'function') { + context._refreshLine(); + } } + } - fs.open(historyPath, 'r+', onhandle); + [kResolveHistoryPath]() { + if (!this[kHistoryPath]) { + try { + this[kHistoryPath] = path.join(os.homedir(), '.node_repl_history'); + return this[kHistoryPath]; + } catch (err) { + debug(err.stack); + return null; + } + } + return this[kHistoryPath]; } - function onhandle(err, hnd) { - if (err) { - return ready(err); + [kHasWritePermission]() { + return !(permission.isEnabled() && + permission.has('fs.write', this[kHistoryPath]) === false); + } + + [kValidateOptions](options) { + if (typeof options.history !== 'undefined') { + validateArray(options.history, 'history'); + } + if (typeof options.size !== 'undefined') { + validateNumber(options.size, 'size', 0); } - fs.ftruncate(hnd, 0, (err) => { - repl._historyHandle = hnd; - repl.on('line', online); - repl.once('exit', onexit); + } + + async [kInitializeHistory](onReadyCallback) { + try { + // Open and close file first to ensure it exists + // History files are conventionally not readable by others + // 0o0600 = read/write for owner only + const hnd = await fs.promises.open(this[kHistoryPath], 'a+', 0o0600); + await hnd.close(); + + let data; + try { + data = await fs.promises.readFile(this[kHistoryPath], 'utf8'); + } catch (err) { + return this[kHandleHistoryInitError](err, onReadyCallback); + } + + if (data) { + this[kHistory] = RegExpPrototypeSymbolSplit(/\r?\n+/, data, this[kSize]); + } else { + this[kHistory] = []; + } + + validateArray(this[kHistory], 'history'); + + const handle = await fs.promises.open(this[kHistoryPath], 'r+'); + this[kHistoryHandle] = handle; + + await handle.truncate(0); - // Reading the file data out erases it - repl.once('flushHistory', function() { - repl.resume(); - ready(null, repl); + this[kContext].on('line', this[kOnLine].bind(this)); + this[kContext].once('exit', this[kOnExit].bind(this)); + + this[kContext].once('flushHistory', () => { + if (!this[kContext].closed) { + this[kContext].resume(); + onReadyCallback(null, this[kContext]); + } }); - flushHistory(); - }); + + await this[kFlushHistory](); + } catch (err) { + return this[kHandleHistoryInitError](err, onReadyCallback); + } } - // ------ history listeners ------ - function online(line) { - repl._flushing = true; + [kHandleHistoryInitError](err, onReadyCallback) { + // Cannot open history file. + // Don't crash, just don't persist history. + ReplHistory[kWriteToOutput]( + this[kContext], + '\nError: Could not open history file.\n' + + 'REPL session history will not be persisted.\n', + ); + debug(err.stack); - if (timer) { - clearTimeout(timer); + // Save a reference to the context's original _historyPrev + this.historyPrev = this[kContext]._historyPrev; + this[kContext]._historyPrev = this[kReplHistoryMessage].bind(this); + this[kContext].resume(); + return onReadyCallback(null, this[kContext]); + } + + [kOnLine]() { + this[kIsFlushing] = true; + + if (this[kTimer]) { + clearTimeout(this[kTimer]); } - timer = setTimeout(flushHistory, kDebounceHistoryMS); + this[kTimer] = setTimeout(() => this[kFlushHistory](), kDebounceHistoryMS); } - function flushHistory() { - timer = null; - if (writing) { - pending = true; + async [kFlushHistory]() { + this[kTimer] = null; + if (this[kWriting]) { + this[kPending] = true; return; } - writing = true; - const historyData = ArrayPrototypeJoin(repl.history, '\n'); - fs.write(repl._historyHandle, historyData, 0, 'utf8', onwritten); - } - function onwritten(err, data) { - writing = false; - if (pending) { - pending = false; - online(); - } else { - repl._flushing = Boolean(timer); - if (!repl._flushing) { - repl.emit('flushHistory'); + this[kWriting] = true; + const historyData = ArrayPrototypeJoin(this[kHistory], '\n'); + + try { + await this[kHistoryHandle].write(historyData, 0, 'utf8'); + this[kWriting] = false; + + if (this[kPending]) { + this[kPending] = false; + this[kOnLine](); + } else { + this[kIsFlushing] = Boolean(this[kTimer]); + if (!this[kIsFlushing]) { + this[kContext].emit('flushHistory'); + } } + } catch (err) { + this[kWriting] = false; + debug('Error writing history file:', err); } } - function onexit() { - if (repl._flushing) { - repl.once('flushHistory', onexit); + async [kOnExit]() { + if (this[kIsFlushing]) { + this[kContext].once('flushHistory', this[kOnExit].bind(this)); return; } - repl.off('line', online); - fs.close(repl._historyHandle, noop); + this[kContext].off('line', this[kOnLine].bind(this)); + + if (this[kHistoryHandle] !== null) { + try { + await this[kHistoryHandle].close(); + } catch (err) { + debug('Error closing history file:', err); + } + } } -} -function _replHistoryMessage() { - if (this.history.length === 0) { - _writeToOutput( - this, - '\nPersistent history support disabled. ' + - 'Set the NODE_REPL_HISTORY environment\nvariable to ' + - 'a valid, user-writable path to enable.\n', - ); + [kReplHistoryMessage]() { + if (this[kHistory].length === 0) { + ReplHistory[kWriteToOutput]( + this[kContext], + '\nPersistent history support disabled. ' + + 'Set the NODE_REPL_HISTORY environment\nvariable to ' + + 'a valid, user-writable path to enable.\n', + ); + } + // First restore the original method on the context + this[kContext]._historyPrev = this.historyPrev; + // Then call it with the correct context + return this[kContext]._historyPrev(); } - this._historyPrev = Interface.prototype._historyPrev; - return this._historyPrev(); } + +module.exports = { + ReplHistory, +}; diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js index 639051ec10fe61..603685290ad85f 100644 --- a/lib/internal/source_map/source_map_cache.js +++ b/lib/internal/source_map/source_map_cache.js @@ -10,7 +10,7 @@ const { StringPrototypeSplit, } = primordials; -// See https://sourcemaps.info/spec.html for SourceMap V3 specification. +// See https://tc39.es/ecma426/ for SourceMap V3 specification. const { Buffer } = require('buffer'); let debug = require('internal/util/debuglog').debuglog('source_map', (fn) => { debug = fn; @@ -139,7 +139,9 @@ function extractSourceMapURLMagicComment(content) { } /** - * Caches the source map if it is present in the content, with the given filename, moduleInstance, and sourceURL. + * Caches the source map, with the given filename, moduleInstance, sourceURL and sourceMapURL. + * This function does not automatically extract the source map from the content. The caller should either + * extract the source map from the content via V8 API or use {@link extractSourceURLMagicComment} explicitly. * @param {string} filename - the actual filename * @param {string} content - the actual source content * @param {import('internal/modules/cjs/loader').Module | ModuleWrap} moduleInstance - a module instance that @@ -162,20 +164,13 @@ function maybeCacheSourceMap(filename, content, moduleInstance, isGeneratedSourc return; } - if (sourceMapURL === undefined) { - sourceMapURL = extractSourceMapURLMagicComment(content); - } - // Bail out when there is no source map url. if (typeof sourceMapURL !== 'string') { return; } - // FIXME: callers should obtain sourceURL from v8 and pass it - // rather than leaving it undefined and extract by regex. - if (sourceURL === undefined) { - sourceURL = extractSourceURLMagicComment(content); - } + // Normalize the sourceURL to a file URL if it is a path. + sourceURL = normalizeReferrerURL(sourceURL); const data = dataFromUrl(filename, sourceMapURL); // `data` could be null if the source map is invalid. @@ -192,9 +187,6 @@ function maybeCacheSourceMap(filename, content, moduleInstance, isGeneratedSourc if (isGeneratedSource) { generatedSourceMapCache.set(filename, entry); - if (sourceURL) { - generatedSourceMapCache.set(sourceURL, entry); - } return; } // If it is not a generated source, we assume we are in a "cjs/esm" @@ -215,8 +207,14 @@ function maybeCacheGeneratedSourceMap(content) { if (sourceURL === null) { return; } + const sourceMapURL = extractSourceMapURLMagicComment(content); + if (sourceMapURL === null) { + return; + } + try { - maybeCacheSourceMap(sourceURL, content, null, true, sourceURL); + // Use the sourceURL as the filename, and do not create a duplicate entry. + maybeCacheSourceMap(sourceURL, content, null, true, undefined /** no duplicated sourceURL */, sourceMapURL); } catch (err) { // This can happen if the filename is not a valid URL. // If we fail to cache the source map, we should not fail the whole process. diff --git a/lib/internal/streams/readable.js b/lib/internal/streams/readable.js index ca8b4bcc851684..d4096a30994f44 100644 --- a/lib/internal/streams/readable.js +++ b/lib/internal/streams/readable.js @@ -369,13 +369,13 @@ Readable.prototype[EE.captureRejectionSymbol] = function(err) { this.destroy(err); }; -Readable.prototype[SymbolAsyncDispose] = function() { +Readable.prototype[SymbolAsyncDispose] = async function() { let error; if (!this.destroyed) { error = this.readableEnded ? null : new AbortError(); this.destroy(error); } - return new Promise((resolve, reject) => eos(this, (err) => (err && err !== error ? reject(err) : resolve(null)))); + await new Promise((resolve, reject) => eos(this, (err) => (err && err !== error ? reject(err) : resolve(null)))); }; // Manually shove something into the read() buffer. diff --git a/lib/internal/streams/writable.js b/lib/internal/streams/writable.js index ac14b202b6639c..1081db9ffcf661 100644 --- a/lib/internal/streams/writable.js +++ b/lib/internal/streams/writable.js @@ -1149,13 +1149,13 @@ Writable.toWeb = function(streamWritable) { return lazyWebStreams().newWritableStreamFromStreamWritable(streamWritable); }; -Writable.prototype[SymbolAsyncDispose] = function() { +Writable.prototype[SymbolAsyncDispose] = async function() { let error; if (!this.destroyed) { error = this.writableFinished ? null : new AbortError(); this.destroy(error); } - return new Promise((resolve, reject) => + await new Promise((resolve, reject) => eos(this, (err) => (err && err.name !== 'AbortError' ? reject(err) : resolve(null))), ); }; diff --git a/lib/internal/test_runner/reporter/spec.js b/lib/internal/test_runner/reporter/spec.js index e03c8df9e82489..9031025e57d930 100644 --- a/lib/internal/test_runner/reporter/spec.js +++ b/lib/internal/test_runner/reporter/spec.js @@ -94,8 +94,10 @@ class SpecReporter extends Transform { case 'test:stderr': case 'test:stdout': return data.message; - case 'test:diagnostic': - return `${reporterColorMap[type]}${indent(data.nesting)}${reporterUnicodeSymbolMap[type]}${data.message}${colors.white}\n`; + case 'test:diagnostic':{ + const diagnosticColor = reporterColorMap[data.level] || reporterColorMap['test:diagnostic']; + return `${diagnosticColor}${indent(data.nesting)}${reporterUnicodeSymbolMap[type]}${data.message}${colors.white}\n`; + } case 'test:coverage': return getCoverageReport(indent(data.nesting), data.summary, reporterUnicodeSymbolMap['test:coverage'], colors.blue, true); diff --git a/lib/internal/test_runner/reporter/utils.js b/lib/internal/test_runner/reporter/utils.js index 256619039e8e90..eb1a008aaf006a 100644 --- a/lib/internal/test_runner/reporter/utils.js +++ b/lib/internal/test_runner/reporter/utils.js @@ -37,6 +37,15 @@ const reporterColorMap = { get 'test:diagnostic'() { return colors.blue; }, + get 'info'() { + return colors.blue; + }, + get 'warn'() { + return colors.yellow; + }, + get 'error'() { + return colors.red; + }, }; function indent(nesting) { diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index 4c2949f4158ab1..1d9e9ba1b38c96 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -98,7 +98,13 @@ let debug = require('internal/util/debuglog').debuglog('test_runner', (fn) => { }); const kIsolatedProcessName = Symbol('kIsolatedProcessName'); -const kFilterArgs = ['--test', '--experimental-test-coverage', '--watch']; +const kFilterArgs = [ + '--test', + '--experimental-test-coverage', + '--watch', + '--experimental-default-config-file', + '--experimental-config-file', +]; const kFilterArgValues = ['--test-reporter', '--test-reporter-destination']; const kDiagnosticsFilterArgs = ['tests', 'suites', 'pass', 'fail', 'cancelled', 'skipped', 'todo', 'duration_ms']; @@ -481,6 +487,7 @@ function watchFiles(testFiles, opts) { // Reset the topLevel counter opts.root.harness.counters.topLevel = 0; } + await runningSubtests.get(file); runningSubtests.set(file, runTestFile(file, filesWatcher, opts)); } @@ -508,6 +515,8 @@ function watchFiles(testFiles, opts) { // Reset the root start time to recalculate the duration // of the run opts.root.clearExecutionTime(); + opts.root.reporter[kEmitMessage]('test:watch:restarted'); + // Restart test files if (opts.isolation === 'none') { PromisePrototypeThen(restartTestFile(kIsolatedProcessName), undefined, (error) => { diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index c8390586456db6..5b6a202761ea7a 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -1235,7 +1235,7 @@ class Test extends AsyncResource { if (actual < threshold) { harness.success = false; process.exitCode = kGenericUserError; - reporter.diagnostic(nesting, loc, `Error: ${NumberPrototypeToFixed(actual, 2)}% ${name} coverage does not meet threshold of ${threshold}%.`); + reporter.diagnostic(nesting, loc, `Error: ${NumberPrototypeToFixed(actual, 2)}% ${name} coverage does not meet threshold of ${threshold}%.`, 'error'); } } diff --git a/lib/internal/test_runner/tests_stream.js b/lib/internal/test_runner/tests_stream.js index 2fda1e68069c19..318d7f49998c0e 100644 --- a/lib/internal/test_runner/tests_stream.js +++ b/lib/internal/test_runner/tests_stream.js @@ -116,11 +116,12 @@ class TestsStream extends Readable { }); } - diagnostic(nesting, loc, message) { + diagnostic(nesting, loc, message, level = 'info') { this[kEmitMessage]('test:diagnostic', { __proto__: null, nesting, message, + level, ...loc, }); } diff --git a/lib/internal/tty.js b/lib/internal/tty.js index 486c2d06e7e9b8..0e3d901804f99e 100644 --- a/lib/internal/tty.js +++ b/lib/internal/tty.js @@ -24,7 +24,10 @@ const { ArrayPrototypeSome, + ObjectEntries, + ObjectPrototypeHasOwnProperty: hasOwn, RegExpPrototypeExec, + SafeMap, StringPrototypeSplit, StringPrototypeToLowerCase, } = primordials; @@ -64,17 +67,31 @@ const TERM_ENVS = { 'rxvt-unicode-24bit': COLORS_16m, // https://bugs.launchpad.net/terminator/+bug/1030562 'terminator': COLORS_16m, + 'xterm-kitty': COLORS_16m, }; +const CI_ENVS_MAP = new SafeMap(ObjectEntries({ + APPVEYOR: COLORS_256, + BUILDKITE: COLORS_256, + CIRCLECI: COLORS_16m, + DRONE: COLORS_256, + GITEA_ACTIONS: COLORS_16m, + GITHUB_ACTIONS: COLORS_16m, + GITLAB_CI: COLORS_256, + TRAVIS: COLORS_256, +})); + const TERM_ENVS_REG_EXP = [ /ansi/, /color/, /linux/, + /direct/, /^con[0-9]*x[0-9]/, /^rxvt/, /^screen/, /^xterm/, /^vt100/, + /^vt220/, ]; let warned = false; @@ -155,19 +172,21 @@ function getColorDepth(env = process.env) { } if (env.TMUX) { - return COLORS_256; + return COLORS_16m; + } + + // Azure DevOps + if (hasOwn(env, 'TF_BUILD') && hasOwn(env, 'AGENT_NAME')) { + return COLORS_16; } - if (env.CI) { - if ([ - 'APPVEYOR', - 'BUILDKITE', - 'CIRCLECI', - 'DRONE', - 'GITHUB_ACTIONS', - 'GITLAB_CI', - 'TRAVIS', - ].some((sign) => sign in env) || env.CI_NAME === 'codeship') { + if (hasOwn(env, 'CI')) { + for (const { 0: envName, 1: colors } of CI_ENVS_MAP) { + if (hasOwn(env, envName)) { + return colors; + } + } + if (env.CI_NAME === 'codeship') { return COLORS_256; } return COLORS_2; @@ -198,6 +217,10 @@ function getColorDepth(env = process.env) { } if (env.TERM) { + if (RegExpPrototypeExec(/truecolor/, env.TERM) !== null) { + return COLORS_16m; + } + if (RegExpPrototypeExec(/^xterm-256/, env.TERM) !== null) { return COLORS_256; } diff --git a/lib/internal/util.js b/lib/internal/util.js index 98dc3f81201084..180ca49b3207eb 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -135,6 +135,17 @@ function isPendingDeprecation() { !getOptionValue('--no-deprecation'); } +function deprecateProperty(key, msg, code, isPendingDeprecation) { + const emitDeprecationWarning = getDeprecationWarningEmitter( + code, msg, undefined, false, isPendingDeprecation, + ); + return (options) => { + if (key in options) { + emitDeprecationWarning(); + } + }; +} + // Internal deprecator for pending --pending-deprecation. This can be invoked // at snapshot building time as the warning permission is only queried at // run time. @@ -947,6 +958,7 @@ module.exports = { defineReplaceableLazyAttribute, deprecate, deprecateInstantiation, + deprecateProperty, emitExperimentalWarning, encodingsMap, exposeInterface, diff --git a/lib/internal/webstreams/compression.js b/lib/internal/webstreams/compression.js index 2299b9c49e05bd..b33b7134096c8b 100644 --- a/lib/internal/webstreams/compression.js +++ b/lib/internal/webstreams/compression.js @@ -99,16 +99,28 @@ class DecompressionStream { }); switch (format) { case 'deflate': - this.#handle = lazyZlib().createInflate(); + this.#handle = lazyZlib().createInflate({ + rejectGarbageAfterEnd: true, + }); break; case 'deflate-raw': this.#handle = lazyZlib().createInflateRaw(); break; case 'gzip': - this.#handle = lazyZlib().createGunzip(); + this.#handle = lazyZlib().createGunzip({ + rejectGarbageAfterEnd: true, + }); break; } this.#transform = newReadableWritablePairFromDuplex(this.#handle); + + this.#handle.on('error', (err) => { + if (this.#transform?.writable && + !this.#transform.writable.locked && + typeof this.#transform.writable.abort === 'function') { + this.#transform.writable.abort(err); + } + }); } /** diff --git a/lib/internal/worker.js b/lib/internal/worker.js index 8b43dcac320777..1df638ff77864c 100644 --- a/lib/internal/worker.js +++ b/lib/internal/worker.js @@ -7,7 +7,6 @@ const { AtomicsAdd, Float64Array, FunctionPrototypeBind, - JSONStringify, MathMax, ObjectEntries, Promise, @@ -19,6 +18,7 @@ const { String, StringPrototypeTrim, Symbol, + SymbolAsyncDispose, SymbolFor, TypedArrayPrototypeFill, Uint32Array, @@ -166,8 +166,8 @@ class Worker extends EventEmitter { doEval = 'classic'; } else if (isURL(filename) && filename.protocol === 'data:') { url = null; - doEval = 'module'; - filename = `import ${JSONStringify(`${filename}`)}`; + doEval = 'data-url'; + filename = `${filename}`; } else { doEval = false; if (isURL(filename)) { @@ -407,6 +407,10 @@ class Worker extends EventEmitter { }); } + async [SymbolAsyncDispose]() { + await this.terminate(); + } + ref() { if (this[kHandle] === null) return; diff --git a/lib/internal/worker/io.js b/lib/internal/worker/io.js index 29c7914982b67a..786ee36c1927fa 100644 --- a/lib/internal/worker/io.js +++ b/lib/internal/worker/io.js @@ -18,6 +18,7 @@ const { } = primordials; const { + assignFunctionName, kEnumerableProperty, setOwnProperty, } = require('internal/util'); @@ -121,7 +122,7 @@ ObjectSetPrototypeOf(MessagePort.prototype, NodeEventTarget.prototype); // changing the prototype of MessagePort.prototype implicitly removed them. MessagePort.prototype.ref = MessagePortPrototype.ref; MessagePort.prototype.unref = MessagePortPrototype.unref; -MessagePort.prototype.hasRef = function() { +MessagePort.prototype.hasRef = function hasRef() { return !!FunctionPrototypeCall(MessagePortPrototype.hasRef, this); }; @@ -131,14 +132,14 @@ ObjectDefineProperty( kCreateEvent, { __proto__: null, - value: function(data, type) { + value: assignFunctionName(kCreateEvent, function(data, type) { if (type !== 'message' && type !== 'messageerror') { return ReflectApply(originalCreateEvent, this, arguments); } const ports = this[kCurrentlyReceivingPorts]; this[kCurrentlyReceivingPorts] = undefined; return lazyMessageEvent(type, { data, ports }); - }, + }), configurable: false, writable: false, enumerable: false, @@ -179,7 +180,7 @@ ObjectDefineProperty(MessagePort.prototype, handleOnCloseSymbol, { value: onclose, }); -MessagePort.prototype.close = function(cb) { +MessagePort.prototype.close = function close(cb) { if (typeof cb === 'function') this.once('close', cb); FunctionPrototypeCall(MessagePortPrototype.close, this); diff --git a/lib/net.js b/lib/net.js index 7e0788556c8ef4..a391e9da30f861 100644 --- a/lib/net.js +++ b/lib/net.js @@ -238,11 +238,6 @@ function connect(...args) { debug('createConnection', normalized); const socket = new Socket(options); - if (netClientSocketChannel.hasSubscribers) { - netClientSocketChannel.publish({ - socket, - }); - } if (options.timeout) { socket.setTimeout(options.timeout); } @@ -1238,6 +1233,12 @@ Socket.prototype.connect = function(...args) { const options = normalized[0]; const cb = normalized[1]; + if (netClientSocketChannel.hasSubscribers) { + netClientSocketChannel.publish({ + socket: this, + }); + } + if (cb !== null) { this.once('connect', cb); } @@ -2394,7 +2395,7 @@ Server.prototype[SymbolAsyncDispose] = async function() { if (!this._handle) { return; } - return FunctionPrototypeCall(promisify(this.close), this); + await FunctionPrototypeCall(promisify(this.close), this); }; Server.prototype._emitCloseIfDrained = function() { diff --git a/lib/path.js b/lib/path.js index aa64a2032c6a71..26c020f5de06d9 100644 --- a/lib/path.js +++ b/lib/path.js @@ -95,7 +95,7 @@ function normalizeString(path, allowAboveRoot, separator, isPathSeparator) { StringPrototypeCharCodeAt(res, res.length - 1) !== CHAR_DOT || StringPrototypeCharCodeAt(res, res.length - 2) !== CHAR_DOT) { if (res.length > 2) { - const lastSlashIndex = StringPrototypeLastIndexOf(res, separator); + const lastSlashIndex = res.length - lastSegmentLength - 1; if (lastSlashIndex === -1) { res = ''; lastSegmentLength = 0; @@ -163,6 +163,8 @@ function _format(sep, pathObject) { return dir === pathObject.root ? `${dir}${base}` : `${dir}${sep}${base}`; } +const forwardSlashRegExp = /\//g; + const win32 = { /** * path.resolve([from ...], to) @@ -186,6 +188,14 @@ const win32 = { } } else if (resolvedDevice.length === 0) { path = process.cwd(); + // Fast path for current directory + if (args.length === 0 || ((args.length === 1 && (args[0] === '' || args[0] === '.')) && + isPathSeparator(StringPrototypeCharCodeAt(path, 0)))) { + if (!isWindows) { + path = StringPrototypeReplace(path, forwardSlashRegExp, '\\'); + } + return path; + } } else { // Windows has the concept of drive-specific current working // directories. If we've resolved a drive letter but not yet an @@ -1171,6 +1181,12 @@ const posix = { * @returns {string} */ resolve(...args) { + if (args.length === 0 || (args.length === 1 && (args[0] === '' || args[0] === '.'))) { + const cwd = posixCwd(); + if (StringPrototypeCharCodeAt(cwd, 0) === CHAR_FORWARD_SLASH) { + return cwd; + } + } let resolvedPath = ''; let resolvedAbsolute = false; diff --git a/lib/repl.js b/lib/repl.js index 42fa0dc5ae640c..d500181736b7ac 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -96,6 +96,10 @@ const { globalThis, } = primordials; +const { + isProxy, +} = require('internal/util/types'); + const { BuiltinModule } = require('internal/bootstrap/realm'); const { makeRequireFunction, @@ -186,7 +190,6 @@ const { stopSigintWatchdog, } = internalBinding('contextify'); -const history = require('internal/repl/history'); const { extensionFormatMap, } = require('internal/modules/esm/formats'); @@ -787,6 +790,8 @@ function REPLServer(prompt, [text, self.editorMode ? self.completeOnEditorMode(cb) : cb]); } + // All the parameters in the object are defining the "input" param of the + // InterfaceConstructor. ReflectApply(Interface, this, [{ input: options.input, output: options.output, @@ -974,9 +979,9 @@ function REPLServer(prompt, self.output.write(self.writer(ret) + '\n'); } - // Display prompt again (unless we already did by emitting the 'error' - // event on the domain instance). - if (!e) { + // If the REPL sever hasn't closed display prompt again (unless we already + // did by emitting the 'error' event on the domain instance). + if (!self.closed && !e) { self[kLastCommandErrored] = false; self.displayPrompt(); } @@ -1075,8 +1080,17 @@ function start(prompt, source, eval_, useGlobal, ignoreUndefined, replMode) { prompt, source, eval_, useGlobal, ignoreUndefined, replMode); } -REPLServer.prototype.setupHistory = function setupHistory(historyFile, cb) { - history(this, historyFile, cb); +REPLServer.prototype.setupHistory = function setupHistory(historyConfig = {}, cb) { + // TODO(puskin94): necessary because historyConfig can be a string for backwards compatibility + const options = typeof historyConfig === 'string' ? + { filePath: historyConfig } : + historyConfig; + + if (typeof cb === 'function') { + options.onHistoryFileLoaded = cb; + } + + this.setupHistoryManager(options); }; REPLServer.prototype.clearBufferedCommand = function clearBufferedCommand() { @@ -1084,7 +1098,7 @@ REPLServer.prototype.clearBufferedCommand = function clearBufferedCommand() { }; REPLServer.prototype.close = function close() { - if (this.terminal && this._flushing && !this._closingOnFlush) { + if (this.terminal && this.historyManager.isFlushing && !this._closingOnFlush) { this._closingOnFlush = true; this.once('flushHistory', () => ReflectApply(Interface.prototype.close, this, []), @@ -1318,8 +1332,10 @@ function completeFSFunctions(match) { // -> [['util.print', 'util.debug', 'util.log', 'util.inspect'], // 'util.' ] // -// Warning: This eval's code like "foo.bar.baz", so it will run property -// getter code. +// Warning: This evals code like "foo.bar.baz", so it could run property +// getter code. To avoid potential triggering side-effects with getters the completion +// logic is skipped when getters or proxies are involved in the expression. +// (see: https://github.com/nodejs/node/issues/57829). function complete(line, callback) { // List of completion lists, one for each inheritance "level" let completionGroups = []; @@ -1515,50 +1531,61 @@ function complete(line, callback) { return; } - let chaining = '.'; - if (StringPrototypeEndsWith(expr, '?')) { - expr = StringPrototypeSlice(expr, 0, -1); - chaining = '?.'; - } - - const memberGroups = []; - const evalExpr = `try { ${expr} } catch {}`; - this.eval(evalExpr, this.context, getREPLResourceName(), (e, obj) => { - try { - let p; - if ((typeof obj === 'object' && obj !== null) || - typeof obj === 'function') { - ArrayPrototypePush(memberGroups, filteredOwnPropertyNames(obj)); - p = ObjectGetPrototypeOf(obj); - } else { - p = obj.constructor ? obj.constructor.prototype : null; + return includesProxiesOrGetters( + StringPrototypeSplit(match, '.'), + this.eval, + this.context, + (includes) => { + if (includes) { + // The expression involves proxies or getters, meaning that it + // can trigger side-effectful behaviors, so bail out + return completionGroupsLoaded(); } - // Circular refs possible? Let's guard against that. - let sentinel = 5; - while (p !== null && sentinel-- !== 0) { - ArrayPrototypePush(memberGroups, filteredOwnPropertyNames(p)); - p = ObjectGetPrototypeOf(p); + + let chaining = '.'; + if (StringPrototypeEndsWith(expr, '?')) { + expr = StringPrototypeSlice(expr, 0, -1); + chaining = '?.'; } - } catch { - // Maybe a Proxy object without `getOwnPropertyNames` trap. - // We simply ignore it here, as we don't want to break the - // autocompletion. Fixes the bug - // https://github.com/nodejs/node/issues/2119 - } - if (memberGroups.length) { - expr += chaining; - ArrayPrototypeForEach(memberGroups, (group) => { - ArrayPrototypePush(completionGroups, - ArrayPrototypeMap(group, - (member) => `${expr}${member}`)); - }); - filter &&= `${expr}${filter}`; - } + const memberGroups = []; + const evalExpr = `try { ${expr} } catch {}`; + this.eval(evalExpr, this.context, getREPLResourceName(), (e, obj) => { + try { + let p; + if ((typeof obj === 'object' && obj !== null) || + typeof obj === 'function') { + ArrayPrototypePush(memberGroups, filteredOwnPropertyNames(obj)); + p = ObjectGetPrototypeOf(obj); + } else { + p = obj.constructor ? obj.constructor.prototype : null; + } + // Circular refs possible? Let's guard against that. + let sentinel = 5; + while (p !== null && sentinel-- !== 0) { + ArrayPrototypePush(memberGroups, filteredOwnPropertyNames(p)); + p = ObjectGetPrototypeOf(p); + } + } catch { + // Maybe a Proxy object without `getOwnPropertyNames` trap. + // We simply ignore it here, as we don't want to break the + // autocompletion. Fixes the bug + // https://github.com/nodejs/node/issues/2119 + } - completionGroupsLoaded(); - }); - return; + if (memberGroups.length) { + expr += chaining; + ArrayPrototypeForEach(memberGroups, (group) => { + ArrayPrototypePush(completionGroups, + ArrayPrototypeMap(group, + (member) => `${expr}${member}`)); + }); + filter &&= `${expr}${filter}`; + } + + completionGroupsLoaded(); + }); + }); } return completionGroupsLoaded(); @@ -1616,6 +1643,34 @@ function complete(line, callback) { } } +function includesProxiesOrGetters(exprSegments, evalFn, context, callback, currentExpr = '', idx = 0) { + const currentSegment = exprSegments[idx]; + currentExpr += `${currentExpr.length === 0 ? '' : '.'}${currentSegment}`; + evalFn(`try { ${currentExpr} } catch { }`, context, getREPLResourceName(), (_, currentObj) => { + if (typeof currentObj !== 'object' || currentObj === null) { + return callback(false); + } + + if (isProxy(currentObj)) { + return callback(true); + } + + const nextIdx = idx + 1; + + if (nextIdx >= exprSegments.length) { + return callback(false); + } + + const nextSegmentProp = ObjectGetOwnPropertyDescriptor(currentObj, exprSegments[nextIdx]); + const nextSegmentPropHasGetter = typeof nextSegmentProp?.get === 'function'; + if (nextSegmentPropHasGetter) { + return callback(true); + } + + return includesProxiesOrGetters(exprSegments, evalFn, context, callback, currentExpr, nextIdx); + }); +} + REPLServer.prototype.completeOnEditorMode = (callback) => (err, results) => { if (err) return callback(err); diff --git a/lib/util.js b/lib/util.js index 233da10e83c48d..a422daa212b855 100644 --- a/lib/util.js +++ b/lib/util.js @@ -100,10 +100,11 @@ function lazyAbortController() { let internalDeepEqual; /** - * @param {string} code + * @param {string} [code] * @returns {string} */ function escapeStyleCode(code) { + if (code === undefined) return ''; return `\u001b[${code}m`; } @@ -139,6 +140,7 @@ function styleText(format, text, { validateStream = true, stream = process.stdou let left = ''; let right = ''; for (const key of formatArray) { + if (key === 'none') continue; const formatCodes = inspect.colors[key]; // If the format is not a valid style, throw an error if (formatCodes == null) { diff --git a/lib/zlib.js b/lib/zlib.js index 058e03c7180620..bd9753baa41099 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -42,6 +42,7 @@ const { ERR_BUFFER_TOO_LARGE, ERR_INVALID_ARG_TYPE, ERR_OUT_OF_RANGE, + ERR_TRAILING_JUNK_AFTER_STREAM_END, ERR_ZSTD_INVALID_PARAM, }, genericNodeError, @@ -266,6 +267,8 @@ function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) { this._defaultFullFlushFlag = fullFlush; this._info = opts?.info; this._maxOutputLength = maxOutputLength; + + this._rejectGarbageAfterEnd = opts?.rejectGarbageAfterEnd === true; } ObjectSetPrototypeOf(ZlibBase.prototype, Transform.prototype); ObjectSetPrototypeOf(ZlibBase, Transform); @@ -304,7 +307,7 @@ ZlibBase.prototype._final = function(callback) { // This is currently only used to figure out which flush flag to use for the // last chunk. // Roughly, the following holds: -// Z_NO_FLUSH (< Z_TREES) < Z_BLOCK < Z_PARTIAL_FLUSH < +// Z_NO_FLUSH < Z_BLOCK < Z_PARTIAL_FLUSH < // Z_SYNC_FLUSH < Z_FULL_FLUSH < Z_FINISH const flushiness = []; const kFlushFlagList = [Z_NO_FLUSH, Z_BLOCK, Z_PARTIAL_FLUSH, @@ -570,6 +573,14 @@ function processCallback() { // stream has ended early. // This applies to streams where we don't check data past the end of // what was consumed; that is, everything except Gunzip/Unzip. + + if (self._rejectGarbageAfterEnd) { + const err = new ERR_TRAILING_JUNK_AFTER_STREAM_END(); + self.destroy(err); + this.cb(err); + return; + } + self.push(null); } @@ -662,6 +673,7 @@ function Zlib(opts, mode) { this._level = level; this._strategy = strategy; + this._mode = mode; } ObjectSetPrototypeOf(Zlib.prototype, ZlibBase.prototype); ObjectSetPrototypeOf(Zlib, ZlibBase); diff --git a/node.gyp b/node.gyp index 59303d9ab7c1d1..677ccdcafd772b 100644 --- a/node.gyp +++ b/node.gyp @@ -205,6 +205,7 @@ 'src/connect_wrap.h', 'src/connection_wrap.h', 'src/cppgc_helpers.h', + 'src/cppgc_helpers.cc', 'src/dataqueue/queue.h', 'src/debug_utils.h', 'src/debug_utils-inl.h', @@ -507,7 +508,7 @@ 'target_name': 'node_text_start', 'type': 'none', 'conditions': [ - [ 'OS in "linux freebsd solaris" and ' + [ 'OS in "linux freebsd solaris openharmony" and ' 'target_arch=="x64"', { 'type': 'static_library', 'sources': [ @@ -625,7 +626,7 @@ 'OTHER_LDFLAGS': [ '-Wl,-rpath,@loader_path', '-Wl,-rpath,@loader_path/../lib'], }, 'conditions': [ - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'ldflags': [ '-Wl,-rpath,\\$$ORIGIN/../lib' ], @@ -730,7 +731,7 @@ 'src/node_snapshot_stub.cc' ], }], - [ 'OS in "linux freebsd" and ' + [ 'OS in "linux freebsd openharmony" and ' 'target_arch=="x64"', { 'dependencies': [ 'node_text_start' ], 'ldflags+': [ @@ -955,7 +956,7 @@ ], 'defines': [ 'HAVE_SQLITE=1' ], }], - [ 'OS in "linux freebsd mac solaris" and ' + [ 'OS in "linux freebsd mac solaris openharmony" and ' 'target_arch=="x64" and ' 'node_target_type=="executable"', { 'defines': [ 'NODE_ENABLE_LARGE_CODE_PAGES=1' ], @@ -1064,11 +1065,11 @@ 'test/fuzzers/fuzz_env.cc', ], 'conditions': [ - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'ldflags': [ '-fsanitize=fuzzer' ] }], # Ensure that ossfuzz flag has been set and that we are on Linux - [ 'OS!="linux" or ossfuzz!="true"', { + [ 'OS not in "linux openharmony" or ossfuzz!="true"', { 'type': 'none', }], # Avoid excessive LTO @@ -1107,11 +1108,11 @@ 'test/fuzzers/fuzz_ClientHelloParser.cc', ], 'conditions': [ - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'ldflags': [ '-fsanitize=fuzzer' ] }], # Ensure that ossfuzz flag has been set and that we are on Linux - [ 'OS!="linux" or ossfuzz!="true"', { + [ 'OS not in "linux openharmony" or ossfuzz!="true"', { 'type': 'none', }], # Avoid excessive LTO @@ -1152,11 +1153,11 @@ 'test/fuzzers/fuzz_strings.cc', ], 'conditions': [ - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'ldflags': [ '-fsanitize=fuzzer' ] }], # Ensure that ossfuzz flag has been set and that we are on Linux - [ 'OS!="linux" or ossfuzz!="true"', { + [ 'OS not in "linux openharmony" or ossfuzz!="true"', { 'type': 'none', }], # Avoid excessive LTO @@ -1352,7 +1353,7 @@ [ 'node_shared_libuv=="false"', { 'dependencies': [ 'deps/uv/uv.gyp:libuv#host' ], }], - [ 'OS in "linux mac"', { + [ 'OS in "linux mac openharmony"', { 'defines': ['NODE_JS2C_USE_STRING_LITERALS'], }], [ 'debug_node=="true"', { diff --git a/node.gypi b/node.gypi index 2afd6f02b74726..a851fbbcb810bb 100644 --- a/node.gypi +++ b/node.gypi @@ -307,7 +307,7 @@ 'NODE_PLATFORM="sunos"', ], }], - [ '(OS=="freebsd" or OS=="linux") and node_shared=="false"' + [ '(OS=="freebsd" or OS=="linux" or OS=="openharmony") and node_shared=="false"' ' and force_load=="true"', { 'ldflags': [ '-Wl,-z,noexecstack', @@ -332,7 +332,7 @@ ], }, }], - [ 'coverage=="true" and node_shared=="false" and OS in "mac freebsd linux"', { + [ 'coverage=="true" and node_shared=="false" and OS in "mac freebsd linux openharmony"', { 'cflags!': [ '-O3' ], 'ldflags': [ '--coverage', '-g', @@ -364,12 +364,12 @@ [ 'OS=="sunos"', { 'ldflags': [ '-Wl,-M,/usr/lib/ld/map.noexstk' ], }], - [ 'OS=="linux"', { + [ 'OS=="linux" or OS=="openharmony"', { 'libraries!': [ '-lrt' ], }], - [ 'OS in "freebsd linux"', { + [ 'OS in "freebsd linux openharmony"', { 'ldflags': [ '-Wl,-z,relro', '-Wl,-z,now' ] }], @@ -401,7 +401,7 @@ }, }, 'conditions': [ - ['OS in "linux freebsd" and node_shared=="false"', { + ['OS in "linux freebsd openharmony" and node_shared=="false"', { 'ldflags': [ '-Wl,--whole-archive,' '<(obj_dir)/deps/openssl/<(openssl_product)', diff --git a/src/README.md b/src/README.md index a97e1b9ba52e8f..eab0bb203957c7 100644 --- a/src/README.md +++ b/src/README.md @@ -1131,6 +1131,17 @@ class MyWrap final : CPPGC_MIXIN(MyWrap) { } ``` +If the wrapper needs to perform cleanups when it's destroyed and that +cleanup relies on a living Node.js `Realm`, it should implement a +pattern like this: + +```cpp + ~MyWrap() { this->Finalize(); } + void Clean(Realm* env) override { + // Do cleanup that relies on a living Realm. + } +``` + `cppgc::GarbageCollected` types are expected to implement a `void Trace(cppgc::Visitor* visitor) const` method. When they are the final class in the hierarchy, this method must be marked `final`. For @@ -1182,7 +1193,7 @@ MyWrap* MyWrap::New(Environment* env, v8::Local object) { // pointer with this, as this is not managed by the native memory // allocator but by V8. return cppgc::MakeGarbageCollected( - env->isolate()->GetCppHeap()->GetAllocationHandle(), env, object); + env->cppgc_allocation_handle(), env, object); } // Binding method to be invoked by JavaScript. @@ -1285,16 +1296,76 @@ referrer->Set( ).ToLocalChecked(); ``` +#### Creating references between cppgc-managed objects and `BaseObject`s + +This is currently unsupported with the existing helpers. If this has +to be done, new helpers must be implemented first. Consult the cppgc +headers when trying to implement it. + +Another way to work around it is to always do the migration bottom-to-top. +If a cppgc-managed object needs to reference a `BaseObject`, convert +that `BaseObject` to be cppgc-managed first, and then use `cppgc::Member` +to create the references. + +#### Lifetime and cleanups of cppgc-managed objects + Typically, a newly created cppgc-managed wrapper object should be held alive by the JavaScript land (for example, by being returned by a method and staying alive in a closure). Long-lived cppgc objects can also be held alive from C++ using persistent handles (see `deps/v8/include/cppgc/persistent.h`) or as members of other living cppgc-managed objects (see `deps/v8/include/cppgc/member.h`) if necessary. -Its destructor will be called when no other objects from the V8 heap reference -it, this can happen at any time after the garbage collector notices that -it's no longer reachable and before the V8 isolate is torn down. -See the [Oilpan documentation in Chromium][] for more details. + +When a cppgc-managed object is no longer reachable in the heap, its destructor +will be invoked by the garbage collection, which can happen after the `Realm` +is already gone, or after any object it references is gone. It is therefore +unsafe to invoke V8 APIs directly in the destructors. To ensure safety, +the cleanups of a cppgc-managed object should adhere to different patterns, +depending on what it needs to do: + +1. If it does not need to do any non-trivial cleanup, nor does its members, just use + the default destructor. Cleanup of `v8::TracedReference` and + `cppgc::Member` are already handled automatically by V8 so if they are all the + non-trivial members the class has, this case applies. +2. If the cleanup relies on a living `Realm`, but does not need to access V8 + APIs, the class should use this pattern in its class body: + + ```cpp + ~MyWrap() { this->Finalize(); } + void Clean(Realm* env) override { + // Do cleanup that relies on a living Realm. This would be + // called by CppgcMixin::Finalize() first during Realm shutdown, + // while the Realm is still alive. If the destructor calls + // Finalize() again later during garbage collection that happens after + // Realm shutdown, Clean() would be skipped, preventing + // invalid access to the Realm. + } + ``` + + If implementers want to call `Finalize()` from `Clean()` again, they + need to make sure that calling `Clean()` recursively is safe. +3. If the cleanup relies on access to the V8 heap, including using any V8 + handles, in addition to 2, it should use the `CPPGC_USING_PRE_FINALIZER` + macro (from the [`cppgc/prefinalizer.h` header][]) in the private + section of its class body: + + ```cpp + private: + CPPGC_USING_PRE_FINALIZER(MyWrap, Finalize); + ``` + +Both the destructor and the pre-finalizer are always called on the thread +in which the object is created. + +It's worth noting that the use of pre-finalizers would have a negative impact +on the garbage collection performance as V8 needs to scan all of them during +each sweeping. If the object is expected to be created frequently in large +amounts in the application, it's better to avoid access to the V8 heap in its +cleanup to avoid having to use a pre-finalizer. + +For more information about the cleanup of cppgc-managed objects and +what can be done in a pre-finalizer, see the [cppgc documentation][] and +the [`cppgc/prefinalizer.h` header][]. ### Callback scopes @@ -1421,6 +1492,7 @@ static void GetUserInfo(const FunctionCallbackInfo& args) { [`async_hooks` module]: https://nodejs.org/api/async_hooks.html [`async_wrap.h`]: async_wrap.h [`base_object.h`]: base_object.h +[`cppgc/prefinalizer.h` header]: ../deps/v8/include/cppgc/prefinalizer.h [`handle_wrap.h`]: handle_wrap.h [`memory_tracker.h`]: memory_tracker.h [`req_wrap.h`]: req_wrap.h @@ -1432,6 +1504,7 @@ static void GetUserInfo(const FunctionCallbackInfo& args) { [`vm` module]: https://nodejs.org/api/vm.html [binding function]: #binding-functions [cleanup hooks]: #cleanup-hooks +[cppgc documentation]: ../deps/v8/include/cppgc/README.md [event loop]: #event-loop [exception handling]: #exception-handling [fast API calls]: ../doc/contributing/adding-v8-fast-api.md diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 6290bcd37f3411..5016c3d51dac66 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -879,9 +879,9 @@ void ChannelWrap::Setup() { } /* We do the call to ares_init_option for caller. */ - const int optmask = - ARES_OPT_FLAGS | ARES_OPT_TIMEOUTMS | - ARES_OPT_SOCK_STATE_CB | ARES_OPT_TRIES; + const int optmask = ARES_OPT_FLAGS | ARES_OPT_TIMEOUTMS | + ARES_OPT_SOCK_STATE_CB | ARES_OPT_TRIES | + ARES_OPT_QUERY_CACHE; r = ares_init_options(&channel_, &options, optmask); if (r != ARES_SUCCESS) { diff --git a/src/cppgc_helpers-inl.h b/src/cppgc_helpers-inl.h new file mode 100644 index 00000000000000..745ecab746f7c7 --- /dev/null +++ b/src/cppgc_helpers-inl.h @@ -0,0 +1,65 @@ +#ifndef SRC_CPPGC_HELPERS_INL_H_ +#define SRC_CPPGC_HELPERS_INL_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#include "cppgc_helpers.h" +#include "env-inl.h" + +namespace node { + +template +void CppgcMixin::Wrap(T* ptr, Realm* realm, v8::Local obj) { + CHECK_GE(obj->InternalFieldCount(), T::kInternalFieldCount); + ptr->realm_ = realm; + v8::Isolate* isolate = realm->isolate(); + ptr->traced_reference_ = v8::TracedReference(isolate, obj); + // Note that ptr must be of concrete type T in Wrap. + v8::Object::Wrap(isolate, obj, ptr); + // Keep the layout consistent with BaseObjects. + obj->SetAlignedPointerInInternalField( + kEmbedderType, realm->isolate_data()->embedder_id_for_cppgc()); + obj->SetAlignedPointerInInternalField(kSlot, ptr); + realm->TrackCppgcWrapper(ptr); +} + +template +void CppgcMixin::Wrap(T* ptr, Environment* env, v8::Local obj) { + Wrap(ptr, env->principal_realm(), obj); +} + +template +T* CppgcMixin::Unwrap(v8::Local obj) { + // We are not using v8::Object::Unwrap currently because that requires + // access to isolate which the ASSIGN_OR_RETURN_UNWRAP macro that we'll shim + // with ASSIGN_OR_RETURN_UNWRAP_GC doesn't take, and we also want a + // signature consistent with BaseObject::Unwrap() to avoid churn. Since + // cppgc-managed objects share the same layout as BaseObjects, just unwrap + // from the pointer in the internal field, which should be valid as long as + // the object is still alive. + if (obj->InternalFieldCount() != T::kInternalFieldCount) { + return nullptr; + } + T* ptr = static_cast(obj->GetAlignedPointerFromInternalField(T::kSlot)); + return ptr; +} + +v8::Local CppgcMixin::object() const { + return traced_reference_.Get(realm_->isolate()); +} + +Environment* CppgcMixin::env() const { + return realm_->env(); +} + +CppgcMixin::~CppgcMixin() { + if (realm_ != nullptr) { + realm_->set_should_purge_empty_cppgc_wrappers(true); + } +} + +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#endif // SRC_CPPGC_HELPERS_INL_H_ diff --git a/src/cppgc_helpers.cc b/src/cppgc_helpers.cc new file mode 100644 index 00000000000000..4e3ffb678c2d09 --- /dev/null +++ b/src/cppgc_helpers.cc @@ -0,0 +1,37 @@ +#include "cppgc_helpers.h" +#include "env-inl.h" + +namespace node { + +void CppgcWrapperList::Cleanup() { + for (auto node : *this) { + CppgcMixin* ptr = node->persistent.Get(); + if (ptr != nullptr) { + ptr->Finalize(); + } + } +} + +void CppgcWrapperList::MemoryInfo(MemoryTracker* tracker) const { + for (auto node : *this) { + CppgcMixin* ptr = node->persistent.Get(); + if (ptr != nullptr) { + tracker->Track(ptr); + } + } +} + +void CppgcWrapperList::PurgeEmpty() { + for (auto weak_it = begin(); weak_it != end();) { + CppgcWrapperListNode* node = *weak_it; + auto next_it = ++weak_it; + // The underlying cppgc wrapper has already been garbage collected. + // Remove it from the list. + if (!node->persistent) { + node->persistent.Clear(); + delete node; + } + weak_it = next_it; + } +} +} // namespace node diff --git a/src/cppgc_helpers.h b/src/cppgc_helpers.h index 20b9004917cfbe..fb2af584a4ae77 100644 --- a/src/cppgc_helpers.h +++ b/src/cppgc_helpers.h @@ -6,14 +6,19 @@ #include // std::remove_reference #include "cppgc/garbage-collected.h" #include "cppgc/name-provider.h" -#include "env.h" +#include "cppgc/persistent.h" #include "memory_tracker.h" +#include "util.h" #include "v8-cppgc.h" #include "v8-sandbox.h" #include "v8.h" namespace node { +class Environment; +class Realm; +class CppgcWrapperListNode; + /** * This is a helper mixin with a BaseObject-like interface to help * implementing wrapper objects managed by V8's cppgc (Oilpan) library. @@ -25,20 +30,29 @@ namespace node { * with V8's GC scheduling. * * A cppgc-managed native wrapper should look something like this, note - * that per cppgc rules, CPPGC_MIXIN(Klass) must be at the left-most + * that per cppgc rules, CPPGC_MIXIN(MyWrap) must be at the left-most * position in the hierarchy (which ensures cppgc::GarbageCollected * is at the left-most position). * - * class Klass final : CPPGC_MIXIN(Klass) { + * class MyWrap final : CPPGC_MIXIN(MyWrap) { * public: - * SET_CPPGC_NAME(Klass) // Sets the heap snapshot name to "Node / Klass" + * SET_CPPGC_NAME(MyWrap) // Sets the heap snapshot name to "Node / MyWrap" * void Trace(cppgc::Visitor* visitor) const final { * CppgcMixin::Trace(visitor); * visitor->Trace(...); // Trace any additional owned traceable data * } * } + * + * If the wrapper needs to perform cleanups when it's destroyed and that + * cleanup relies on a living Node.js `Realm`, it should implement a + * pattern like this: + * + * ~MyWrap() { this->Destroy(); } + * void Clean(Realm* env) override { + * // Do cleanup that relies on a living Environemnt. + * } */ -class CppgcMixin : public cppgc::GarbageCollectedMixin { +class CppgcMixin : public cppgc::GarbageCollectedMixin, public MemoryRetainer { public: // To help various callbacks access wrapper objects with different memory // management, cppgc-managed objects share the same layout as BaseObjects. @@ -48,39 +62,19 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin { // invoked from the child class constructor, per cppgc::GarbageCollectedMixin // rules. template - static void Wrap(T* ptr, Environment* env, v8::Local obj) { - CHECK_GE(obj->InternalFieldCount(), T::kInternalFieldCount); - ptr->env_ = env; - v8::Isolate* isolate = env->isolate(); - ptr->traced_reference_ = v8::TracedReference(isolate, obj); - v8::Object::Wrap(isolate, obj, ptr); - // Keep the layout consistent with BaseObjects. - obj->SetAlignedPointerInInternalField( - kEmbedderType, env->isolate_data()->embedder_id_for_cppgc()); - obj->SetAlignedPointerInInternalField(kSlot, ptr); - } + static inline void Wrap(T* ptr, Realm* realm, v8::Local obj); + template + static inline void Wrap(T* ptr, Environment* env, v8::Local obj); - v8::Local object() const { - return traced_reference_.Get(env_->isolate()); + inline v8::Local object() const; + inline Environment* env() const; + inline Realm* realm() const { return realm_; } + inline v8::Local object(v8::Isolate* isolate) const { + return traced_reference_.Get(isolate); } - Environment* env() const { return env_; } - template - static T* Unwrap(v8::Local obj) { - // We are not using v8::Object::Unwrap currently because that requires - // access to isolate which the ASSIGN_OR_RETURN_UNWRAP macro that we'll shim - // with ASSIGN_OR_RETURN_UNWRAP_GC doesn't take, and we also want a - // signature consistent with BaseObject::Unwrap() to avoid churn. Since - // cppgc-managed objects share the same layout as BaseObjects, just unwrap - // from the pointer in the internal field, which should be valid as long as - // the object is still alive. - if (obj->InternalFieldCount() != T::kInternalFieldCount) { - return nullptr; - } - T* ptr = static_cast(obj->GetAlignedPointerFromInternalField(T::kSlot)); - return ptr; - } + static inline T* Unwrap(v8::Local obj); // Subclasses are expected to invoke CppgcMixin::Trace() in their own Trace() // methods. @@ -88,8 +82,38 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin { visitor->Trace(traced_reference_); } + // TODO(joyeecheung): use ObjectSizeTrait; + inline size_t SelfSize() const override { return sizeof(*this); } + inline bool IsCppgcWrapper() const override { return true; } + + // This is run for all the remaining Cppgc wrappers tracked in the Realm + // during Realm shutdown. The destruction of the wrappers would happen later, + // when the final garbage collection is triggered when CppHeap is torn down as + // part of the Isolate teardown. If subclasses of CppgcMixin wish to perform + // cleanups that depend on the Realm during destruction, they should implment + // it in a Clean() override, and then call this->Finalize() from their + // destructor. Outside of Finalize(), subclasses should avoid calling + // into JavaScript or perform any operation that can trigger garbage + // collection during the destruction. + void Finalize() { + if (realm_ == nullptr) return; + this->Clean(realm_); + realm_ = nullptr; + } + + // The default implementation of Clean() is a no-op. If subclasses wish + // to perform cleanup that require a living Realm, they should + // should put the cleanups in a Clean() override, and call this->Finalize() + // in the destructor, instead of doing those cleanups directly in the + // destructor. + virtual void Clean(Realm* realm) {} + + inline ~CppgcMixin(); + + friend class CppgcWrapperListNode; + private: - Environment* env_; + Realm* realm_ = nullptr; v8::TracedReference traced_reference_; }; @@ -105,7 +129,8 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin { #define SET_CPPGC_NAME(Klass) \ inline const char* GetHumanReadableName() const final { \ return "Node / " #Klass; \ - } + } \ + inline const char* MemoryInfoName() const override { return #Klass; } /** * Similar to ASSIGN_OR_RETURN_UNWRAP() but works on cppgc-managed types diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc index a2f4493e1b8ec8..5ed2f8b35a1e2f 100644 --- a/src/crypto/crypto_cipher.cc +++ b/src/crypto/crypto_cipher.cc @@ -514,9 +514,9 @@ void CipherBase::GetAuthTag(const FunctionCallbackInfo& args) { ASSIGN_OR_RETURN_UNWRAP(&cipher, args.This()); // Only callable after Final and if encrypting. - if (cipher->ctx_ || - cipher->kind_ != kCipher || - cipher->auth_tag_len_ == kNoAuthTagLength) { + if (cipher->ctx_ || cipher->kind_ != kCipher || + cipher->auth_tag_len_ == kNoAuthTagLength || + cipher->auth_tag_state_ != kAuthTagComputed) { return; } @@ -577,29 +577,16 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo& args) { } cipher->auth_tag_len_ = tag_len; - cipher->auth_tag_state_ = kAuthTagKnown; - CHECK_LE(cipher->auth_tag_len_, sizeof(cipher->auth_tag_)); + CHECK_LE(cipher->auth_tag_len_, ncrypto::Cipher::MAX_AUTH_TAG_LENGTH); - memset(cipher->auth_tag_, 0, sizeof(cipher->auth_tag_)); - auth_tag.CopyTo(cipher->auth_tag_, cipher->auth_tag_len_); + if (!cipher->ctx_.setAeadTag({auth_tag.data(), cipher->auth_tag_len_})) { + return args.GetReturnValue().Set(false); + } + cipher->auth_tag_state_ = kAuthTagSetByUser; args.GetReturnValue().Set(true); } -bool CipherBase::MaybePassAuthTagToOpenSSL() { - if (auth_tag_state_ == kAuthTagKnown) { - ncrypto::Buffer buffer{ - .data = auth_tag_, - .len = auth_tag_len_, - }; - if (!ctx_.setAeadTag(buffer)) { - return false; - } - auth_tag_state_ = kAuthTagPassedToOpenSSL; - } - return true; -} - bool CipherBase::SetAAD( const ArrayBufferOrViewContents& data, int plaintext_len) { @@ -622,10 +609,6 @@ bool CipherBase::SetAAD( return false; } - if (kind_ == kDecipher && !MaybePassAuthTagToOpenSSL()) { - return false; - } - ncrypto::Buffer buffer{ .data = nullptr, .len = static_cast(plaintext_len), @@ -670,12 +653,6 @@ CipherBase::UpdateResult CipherBase::Update( return kErrorMessageSize; } - // Pass the authentication tag to OpenSSL if possible. This will only happen - // once, usually on the first update. - if (kind_ == kDecipher && IsAuthenticatedMode()) { - CHECK(MaybePassAuthTagToOpenSSL()); - } - const int block_size = ctx_.getBlockSize(); CHECK_GT(block_size, 0); if (len + block_size > INT_MAX) return kErrorState; @@ -708,7 +685,10 @@ CipherBase::UpdateResult CipherBase::Update( *out = ArrayBuffer::NewBackingStore(env()->isolate(), 0); } else if (static_cast(buf_len) != (*out)->ByteLength()) { std::unique_ptr old_out = std::move(*out); - *out = ArrayBuffer::NewBackingStore(env()->isolate(), buf_len); + *out = ArrayBuffer::NewBackingStore( + env()->isolate(), + buf_len, + BackingStoreInitializationMode::kUninitialized); memcpy((*out)->Data(), old_out->Data(), buf_len); } @@ -774,16 +754,11 @@ bool CipherBase::Final(std::unique_ptr* out) { static_cast(ctx_.getBlockSize()), BackingStoreInitializationMode::kUninitialized); - if (kind_ == kDecipher && - Cipher::FromCtx(ctx_).isSupportedAuthenticatedMode()) { - MaybePassAuthTagToOpenSSL(); - } - #if (OPENSSL_VERSION_NUMBER < 0x30000000L) // OpenSSL v1.x doesn't verify the presence of the auth tag so do // it ourselves, see https://github.com/nodejs/node/issues/45874. if (kind_ == kDecipher && ctx_.isChaCha20Poly1305() && - auth_tag_state_ != kAuthTagPassedToOpenSSL) { + auth_tag_state_ != kAuthTagSetByUser) { return false; } #endif @@ -804,7 +779,10 @@ bool CipherBase::Final(std::unique_ptr* out) { *out = ArrayBuffer::NewBackingStore(env()->isolate(), 0); } else if (static_cast(out_len) != (*out)->ByteLength()) { std::unique_ptr old_out = std::move(*out); - *out = ArrayBuffer::NewBackingStore(env()->isolate(), out_len); + *out = ArrayBuffer::NewBackingStore( + env()->isolate(), + out_len, + BackingStoreInitializationMode::kUninitialized); memcpy((*out)->Data(), old_out->Data(), out_len); } @@ -818,6 +796,9 @@ bool CipherBase::Final(std::unique_ptr* out) { } ok = ctx_.getAeadTag(auth_tag_len_, reinterpret_cast(auth_tag_)); + if (ok) { + auth_tag_state_ = kAuthTagComputed; + } } } @@ -880,7 +861,10 @@ bool PublicKeyCipher::Cipher( if (buf.size() == 0) { *out = ArrayBuffer::NewBackingStore(env->isolate(), 0); } else { - *out = ArrayBuffer::NewBackingStore(env->isolate(), buf.size()); + *out = ArrayBuffer::NewBackingStore( + env->isolate(), + buf.size(), + BackingStoreInitializationMode::kUninitialized); memcpy((*out)->Data(), buf.get(), buf.size()); } diff --git a/src/crypto/crypto_cipher.h b/src/crypto/crypto_cipher.h index 168943a890bda7..006d18a7118761 100644 --- a/src/crypto/crypto_cipher.h +++ b/src/crypto/crypto_cipher.h @@ -38,8 +38,8 @@ class CipherBase : public BaseObject { }; enum AuthTagState { kAuthTagUnknown, - kAuthTagKnown, - kAuthTagPassedToOpenSSL + kAuthTagSetByUser, + kAuthTagComputed, }; static const unsigned kNoAuthTagLength = static_cast(-1); @@ -64,10 +64,8 @@ class CipherBase : public BaseObject { bool SetAutoPadding(bool auto_padding); bool IsAuthenticatedMode() const; - bool SetAAD( - const ArrayBufferOrViewContents& data, - int plaintext_len); - bool MaybePassAuthTagToOpenSSL(); + bool SetAAD(const ArrayBufferOrViewContents& data, + int plaintext_len); static void New(const v8::FunctionCallbackInfo& args); static void Update(const v8::FunctionCallbackInfo& args); diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc index 2dda9be53b32e0..e35fda9ad2e8c5 100644 --- a/src/crypto/crypto_dh.cc +++ b/src/crypto/crypto_dh.cc @@ -22,6 +22,8 @@ using ncrypto::DHPointer; using ncrypto::EVPKeyCtxPointer; using ncrypto::EVPKeyPointer; using v8::ArrayBuffer; +using v8::BackingStoreInitializationMode; +using v8::BackingStoreOnFailureMode; using v8::ConstructorBehavior; using v8::Context; using v8::DontDelete; @@ -58,6 +60,20 @@ MaybeLocal DataPointerToBuffer(Environment* env, DataPointer&& data) { struct Flag { bool secure; }; +#ifdef V8_ENABLE_SANDBOX + auto backing = ArrayBuffer::NewBackingStore( + env->isolate(), + data.size(), + BackingStoreInitializationMode::kUninitialized, + BackingStoreOnFailureMode::kReturnNull); + if (!backing) { + THROW_ERR_MEMORY_ALLOCATION_FAILED(env); + return MaybeLocal(); + } + if (data.size() > 0) { + memcpy(backing->Data(), data.get(), data.size()); + } +#else auto backing = ArrayBuffer::NewBackingStore( data.get(), data.size(), @@ -67,6 +83,7 @@ MaybeLocal DataPointerToBuffer(Environment* env, DataPointer&& data) { }, new Flag{data.isSecure()}); data.release(); +#endif // V8_ENABLE_SANDBOX auto ab = ArrayBuffer::New(env->isolate(), std::move(backing)); return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local()); diff --git a/src/crypto/crypto_sig.cc b/src/crypto/crypto_sig.cc index 8518bdfd53b2d0..11007fbaeb862f 100644 --- a/src/crypto/crypto_sig.cc +++ b/src/crypto/crypto_sig.cc @@ -99,7 +99,10 @@ std::unique_ptr Node_SignFinal(Environment* env, [[likely]] { CHECK_LE(sig_buf.len, sig->ByteLength()); if (sig_buf.len < sig->ByteLength()) { - auto new_sig = ArrayBuffer::NewBackingStore(env->isolate(), sig_buf.len); + auto new_sig = ArrayBuffer::NewBackingStore( + env->isolate(), + sig_buf.len, + BackingStoreInitializationMode::kUninitialized); if (sig_buf.len > 0) [[likely]] { memcpy(new_sig->Data(), sig->Data(), sig_buf.len); } diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc index 00b533f5f77fa0..46b5202482d7c0 100644 --- a/src/crypto/crypto_util.cc +++ b/src/crypto/crypto_util.cc @@ -34,6 +34,8 @@ using ncrypto::EnginePointer; using ncrypto::SSLPointer; using v8::ArrayBuffer; using v8::BackingStore; +using v8::BackingStoreInitializationMode; +using v8::BackingStoreOnFailureMode; using v8::BigInt; using v8::Context; using v8::EscapableHandleScope; @@ -339,16 +341,37 @@ ByteSource& ByteSource::operator=(ByteSource&& other) noexcept { return *this; } -std::unique_ptr ByteSource::ReleaseToBackingStore() { +std::unique_ptr ByteSource::ReleaseToBackingStore( + Environment* env) { // It's ok for allocated_data_ to be nullptr but // only if size_ is zero. CHECK_IMPLIES(size_ > 0, allocated_data_ != nullptr); +#ifdef V8_ENABLE_SANDBOX + // If the v8 sandbox is enabled, then all array buffers must be allocated + // via the isolate. External buffers are not allowed. So, instead of wrapping + // the allocated data we'll copy it instead. + + // TODO(@jasnell): It would be nice to use an abstracted utility to do this + // branch instead of duplicating the V8_ENABLE_SANDBOX check each time. + std::unique_ptr ptr = ArrayBuffer::NewBackingStore( + env->isolate(), + size(), + BackingStoreInitializationMode::kUninitialized, + BackingStoreOnFailureMode::kReturnNull); + if (!ptr) { + THROW_ERR_MEMORY_ALLOCATION_FAILED(env); + return nullptr; + } + memcpy(ptr->Data(), allocated_data_, size()); + OPENSSL_clear_free(allocated_data_, size_); +#else std::unique_ptr ptr = ArrayBuffer::NewBackingStore( allocated_data_, size(), [](void* data, size_t length, void* deleter_data) { OPENSSL_clear_free(deleter_data, length); }, allocated_data_); +#endif // V8_ENABLE_SANDBOX CHECK(ptr); allocated_data_ = nullptr; data_ = nullptr; @@ -357,7 +380,7 @@ std::unique_ptr ByteSource::ReleaseToBackingStore() { } Local ByteSource::ToArrayBuffer(Environment* env) { - std::unique_ptr store = ReleaseToBackingStore(); + std::unique_ptr store = ReleaseToBackingStore(env); return ArrayBuffer::New(env->isolate(), std::move(store)); } @@ -648,8 +671,19 @@ namespace { // using OPENSSL_malloc. However, if the secure heap is // initialized, SecureBuffer will automatically use it. void SecureBuffer(const FunctionCallbackInfo& args) { - CHECK(args[0]->IsUint32()); Environment* env = Environment::GetCurrent(args); +#ifdef V8_ENABLE_SANDBOX + // The v8 sandbox is enabled, so we cannot use the secure heap because + // the sandbox requires that all array buffers be allocated via the isolate. + // That is fundamentally incompatible with the secure heap which allocates + // in openssl's secure heap area. Instead we'll just throw an error here. + // + // That said, we really shouldn't get here in the first place since the + // option to enable the secure heap is only available when the sandbox + // is disabled. + UNREACHABLE(); +#else + CHECK(args[0]->IsUint32()); uint32_t len = args[0].As()->Value(); auto data = DataPointer::SecureAlloc(len); @@ -676,6 +710,7 @@ void SecureBuffer(const FunctionCallbackInfo& args) { Local buffer = ArrayBuffer::New(env->isolate(), store); args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len)); +#endif // V8_ENABLE_SANDBOX } void SecureHeapUsed(const FunctionCallbackInfo& args) { diff --git a/src/crypto/crypto_util.h b/src/crypto/crypto_util.h index 4842bf0e4c791e..d2620b40c8bc4b 100644 --- a/src/crypto/crypto_util.h +++ b/src/crypto/crypto_util.h @@ -185,7 +185,7 @@ class ByteSource final { // Creates a v8::BackingStore that takes over responsibility for // any allocated data. The ByteSource will be reset with size = 0 // after being called. - std::unique_ptr ReleaseToBackingStore(); + std::unique_ptr ReleaseToBackingStore(Environment* env); v8::Local ToArrayBuffer(Environment* env); diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc index a1eb1298f96067..7d46e09be3e2c0 100644 --- a/src/crypto/crypto_x509.cc +++ b/src/crypto/crypto_x509.cc @@ -29,6 +29,7 @@ using v8::Array; using v8::ArrayBuffer; using v8::ArrayBufferView; using v8::BackingStoreInitializationMode; +using v8::BackingStoreOnFailureMode; using v8::Boolean; using v8::Context; using v8::Date; @@ -131,6 +132,21 @@ MaybeLocal ToBuffer(Environment* env, BIOPointer* bio) { if (bio == nullptr || !*bio) [[unlikely]] return {}; BUF_MEM* mem = *bio; +#ifdef V8_ENABLE_SANDBOX + // If the v8 sandbox is enabled, then all array buffers must be allocated + // via the isolate. External buffers are not allowed. So, instead of wrapping + // the BIOPointer we'll copy it instead. + auto backing = ArrayBuffer::NewBackingStore( + env->isolate(), + mem->length, + BackingStoreInitializationMode::kUninitialized, + BackingStoreOnFailureMode::kReturnNull); + if (!backing) { + THROW_ERR_MEMORY_ALLOCATION_FAILED(env); + return MaybeLocal(); + } + memcpy(backing->Data(), mem->data, mem->length); +#else auto backing = ArrayBuffer::NewBackingStore( mem->data, mem->length, @@ -138,6 +154,7 @@ MaybeLocal ToBuffer(Environment* env, BIOPointer* bio) { BIOPointer free_me(static_cast(data)); }, bio->release()); +#endif // V8_ENABLE_SANDBOX auto ab = ArrayBuffer::New(env->isolate(), std::move(backing)); Local ret; if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&ret)) return {}; diff --git a/src/env-inl.h b/src/env-inl.h index 9b8d8f6ab070ff..f4c42efefeca05 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -205,6 +205,10 @@ inline v8::Isolate* Environment::isolate() const { return isolate_; } +inline cppgc::AllocationHandle& Environment::cppgc_allocation_handle() const { + return isolate_->GetCppHeap()->GetAllocationHandle(); +} + inline v8::ExternalMemoryAccounter* Environment::external_memory_accounter() const { return external_memory_accounter_; @@ -775,6 +779,13 @@ inline void Environment::ThrowError( isolate()->ThrowException(fun(OneByteString(isolate(), errmsg), {})); } +inline void Environment::ThrowStdErrException(std::error_code error_code, + const char* syscall, + const char* path) { + ThrowErrnoException( + error_code.value(), syscall, error_code.message().c_str(), path); +} + inline void Environment::ThrowErrnoException(int errorno, const char* syscall, const char* message, diff --git a/src/env.cc b/src/env.cc index 6edb0d45b27f64..833f4bac4066f5 100644 --- a/src/env.cc +++ b/src/env.cc @@ -928,6 +928,25 @@ Environment::Environment(IsolateData* isolate_data, permission()->Apply(this, {"*"}, permission::PermissionScope::kWASI); } + // Implicit allow entrypoint to kFileSystemRead + if (!options_->has_eval_string && !options_->force_repl) { + std::string first_argv; + if (argv_.size() > 1) { + first_argv = argv_[1]; + } + + // Also implicit allow preloaded modules to kFileSystemRead + if (!options_->preload_cjs_modules.empty()) { + for (const std::string& mod : options_->preload_cjs_modules) { + options_->allow_fs_read.push_back(mod); + } + } + + if (first_argv != "inspect") { + options_->allow_fs_read.push_back(first_argv); + } + } + if (!options_->allow_fs_read.empty()) { permission()->Apply(this, options_->allow_fs_read, diff --git a/src/env.h b/src/env.h index b428f5937b96fd..10e579bee9c059 100644 --- a/src/env.h +++ b/src/env.h @@ -692,6 +692,7 @@ class Environment final : public MemoryRetainer { void StartProfilerIdleNotifier(); inline v8::Isolate* isolate() const; + inline cppgc::AllocationHandle& cppgc_allocation_handle() const; inline v8::ExternalMemoryAccounter* external_memory_accounter() const; inline uv_loop_t* event_loop() const; void TryLoadAddon(const char* filename, @@ -830,6 +831,9 @@ class Environment final : public MemoryRetainer { inline void ThrowError(const char* errmsg); inline void ThrowTypeError(const char* errmsg); inline void ThrowRangeError(const char* errmsg); + inline void ThrowStdErrException(std::error_code error_code, + const char* syscall, + const char* path = nullptr); inline void ThrowErrnoException(int errorno, const char* syscall = nullptr, const char* message = nullptr, diff --git a/src/env_properties.h b/src/env_properties.h index 5c90bfd8cd7948..8852d83eda3c3f 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -363,6 +363,7 @@ V(sni_context_string, "sni_context") \ V(source_string, "source") \ V(source_map_url_string, "sourceMapURL") \ + V(source_url_string, "sourceURL") \ V(specifier_string, "specifier") \ V(stack_string, "stack") \ V(standard_name_string, "standardName") \ diff --git a/src/inspector/network_agent.cc b/src/inspector/network_agent.cc index 497260ecc93c5f..faa49ead94a698 100644 --- a/src/inspector/network_agent.cc +++ b/src/inspector/network_agent.cc @@ -15,6 +15,7 @@ using v8::Maybe; using v8::MaybeLocal; using v8::Nothing; using v8::Object; +using v8::Uint8Array; using v8::Value; // Get a protocol string property from the object. @@ -168,11 +169,23 @@ std::unique_ptr createResponseFromObject( return {}; } + protocol::String mimeType; + if (!ObjectGetProtocolString(context, response, "mimeType").To(&mimeType)) { + mimeType = protocol::String(""); + } + + protocol::String charset = protocol::String(); + if (!ObjectGetProtocolString(context, response, "charset").To(&charset)) { + charset = protocol::String(""); + } + return protocol::Network::Response::create() .setUrl(url) .setStatus(status) .setStatusText(statusText) .setHeaders(std::move(headers)) + .setMimeType(mimeType) + .setCharset(charset) .build(); } @@ -183,6 +196,7 @@ NetworkAgent::NetworkAgent(NetworkInspector* inspector, event_notifier_map_["responseReceived"] = &NetworkAgent::responseReceived; event_notifier_map_["loadingFailed"] = &NetworkAgent::loadingFailed; event_notifier_map_["loadingFinished"] = &NetworkAgent::loadingFinished; + event_notifier_map_["dataReceived"] = &NetworkAgent::dataReceived; } void NetworkAgent::emitNotification(v8::Local context, @@ -211,6 +225,30 @@ protocol::DispatchResponse NetworkAgent::disable() { return protocol::DispatchResponse::Success(); } +protocol::DispatchResponse NetworkAgent::streamResourceContent( + const protocol::String& in_requestId, protocol::Binary* out_bufferedData) { + if (!requests_.contains(in_requestId)) { + // Request not found, ignore it. + return protocol::DispatchResponse::InvalidParams("Request not found"); + } + + auto& it = requests_[in_requestId]; + + it.is_streaming = true; + + // Concat response bodies. + *out_bufferedData = protocol::Binary::concat(it.response_data_blobs); + // Clear buffered data. + it.response_data_blobs.clear(); + + if (it.is_finished) { + // If the request is finished, remove the entry. + requests_.erase(in_requestId); + } + + return protocol::DispatchResponse::Success(); +} + void NetworkAgent::requestWillBeSent(v8::Local context, v8::Local params) { protocol::String request_id; @@ -247,6 +285,12 @@ void NetworkAgent::requestWillBeSent(v8::Local context, std::move(initiator), timestamp, wall_time); + + if (requests_.contains(request_id)) { + // Duplicate entry, ignore it. + return; + } + requests_.emplace(request_id, RequestEntry{timestamp, false, false, {}}); } void NetworkAgent::responseReceived(v8::Local context, @@ -295,6 +339,8 @@ void NetworkAgent::loadingFailed(v8::Local context, } frontend_->loadingFailed(request_id, timestamp, type, error_text); + + requests_.erase(request_id); } void NetworkAgent::loadingFinished(v8::Local context, @@ -309,6 +355,63 @@ void NetworkAgent::loadingFinished(v8::Local context, } frontend_->loadingFinished(request_id, timestamp); + + auto request_entry = requests_.find(request_id); + if (request_entry == requests_.end()) { + // No entry found. Ignore it. + return; + } + + if (request_entry->second.is_streaming) { + // Streaming finished, remove the entry. + requests_.erase(request_id); + } else { + request_entry->second.is_finished = true; + } +} + +void NetworkAgent::dataReceived(v8::Local context, + v8::Local params) { + protocol::String request_id; + if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) { + return; + } + + auto request_entry = requests_.find(request_id); + if (request_entry == requests_.end()) { + // No entry found. Ignore it. + return; + } + + double timestamp; + if (!ObjectGetDouble(context, params, "timestamp").To(×tamp)) { + return; + } + int data_length; + if (!ObjectGetInt(context, params, "dataLength").To(&data_length)) { + return; + } + int encoded_data_length; + if (!ObjectGetInt(context, params, "encodedDataLength") + .To(&encoded_data_length)) { + return; + } + Local data_obj; + if (!ObjectGetObject(context, params, "data").ToLocal(&data_obj)) { + return; + } + if (!data_obj->IsUint8Array()) { + return; + } + Local data = data_obj.As(); + auto data_bin = protocol::Binary::fromUint8Array(data); + + if (request_entry->second.is_streaming) { + frontend_->dataReceived( + request_id, timestamp, data_length, encoded_data_length, data_bin); + } else { + requests_[request_id].response_data_blobs.push_back(data_bin); + } } } // namespace inspector diff --git a/src/inspector/network_agent.h b/src/inspector/network_agent.h index 459195ad6d31c2..1229ae78044c3a 100644 --- a/src/inspector/network_agent.h +++ b/src/inspector/network_agent.h @@ -3,6 +3,7 @@ #include "node/inspector/protocol/Network.h" +#include #include namespace node { @@ -10,6 +11,13 @@ namespace inspector { class NetworkInspector; +struct RequestEntry { + double timestamp; + bool is_finished; + bool is_streaming; + std::vector response_data_blobs; +}; + class NetworkAgent : public protocol::Network::Backend { public: explicit NetworkAgent(NetworkInspector* inspector, @@ -21,6 +29,10 @@ class NetworkAgent : public protocol::Network::Backend { protocol::DispatchResponse disable() override; + protocol::DispatchResponse streamResourceContent( + const protocol::String& in_requestId, + protocol::Binary* out_bufferedData) override; + void emitNotification(v8::Local context, const protocol::String& event, v8::Local params); @@ -37,6 +49,9 @@ class NetworkAgent : public protocol::Network::Backend { void loadingFinished(v8::Local context, v8::Local params); + void dataReceived(v8::Local context, + v8::Local params); + private: NetworkInspector* inspector_; v8_inspector::V8Inspector* v8_inspector_; @@ -44,6 +59,7 @@ class NetworkAgent : public protocol::Network::Backend { using EventNotifier = void (NetworkAgent::*)(v8::Local context, v8::Local); std::unordered_map event_notifier_map_; + std::map requests_; }; } // namespace inspector diff --git a/src/inspector/node_protocol.pdl b/src/inspector/node_protocol.pdl index a0b59da6514adb..148a0debe28da1 100644 --- a/src/inspector/node_protocol.pdl +++ b/src/inspector/node_protocol.pdl @@ -173,6 +173,8 @@ experimental domain Network integer status string statusText Headers headers + string mimeType + string charset # Request / response headers as keys / values of JSON object. type Headers extends object @@ -183,6 +185,16 @@ experimental domain Network # Enables network tracking, network events will now be delivered to the client. command enable + # Enables streaming of the response for the given requestId. + # If enabled, the dataReceived event contains the data that was received during streaming. + experimental command streamResourceContent + parameters + # Identifier of the request to stream. + RequestId requestId + returns + # Data that has been buffered until streaming is enabled. + binary bufferedData + # Fired when page is about to send HTTP request. event requestWillBeSent parameters @@ -227,6 +239,20 @@ experimental domain Network # Timestamp. MonotonicTime timestamp + # Fired when data chunk was received over the network. + event dataReceived + parameters + # Request identifier. + RequestId requestId + # Timestamp. + MonotonicTime timestamp + # Data chunk length. + integer dataLength + # Actual bytes received (might be less than dataLength for compressed encodings). + integer encodedDataLength + # Data that was received. + experimental optional binary data + # Support for inspecting node process state. experimental domain NodeRuntime # Enable the NodeRuntime events except by `NodeRuntime.waitingForDisconnect`. diff --git a/src/inspector/node_string.cc b/src/inspector/node_string.cc index 6db4bee1072bfe..8521730bd03cdf 100644 --- a/src/inspector/node_string.cc +++ b/src/inspector/node_string.cc @@ -28,6 +28,20 @@ void ProtocolTypeTraits::Serialize(const std::string& value, cbor::EncodeString8(SpanFrom(value), bytes); } +bool ProtocolTypeTraits::Deserialize( + DeserializerState* state, node::inspector::protocol::Binary* value) { + CHECK(state->tokenizer()->TokenTag() == cbor::CBORTokenTag::BINARY); + span cbor_span = state->tokenizer()->GetBinary(); + *value = node::inspector::protocol::Binary::fromSpan(cbor_span); + return true; +} + +void ProtocolTypeTraits::Serialize( + const node::inspector::protocol::Binary& value, + std::vector* bytes) { + cbor::EncodeString8(SpanFrom(value.toBase64()), bytes); +} + } // namespace crdtp namespace node { @@ -93,6 +107,58 @@ size_t StringUtil::CharacterCount(const std::string_view s) { return s.length(); } +String Binary::toBase64() const { + MaybeStackBuffer buffer; + size_t str_len = simdutf::base64_length_from_binary(bytes_->size()); + buffer.SetLength(str_len); + + size_t len = + simdutf::binary_to_base64(reinterpret_cast(bytes_->data()), + bytes_->size(), + buffer.out()); + CHECK_EQ(len, str_len); + return buffer.ToString(); +} + +// static +Binary Binary::concat(const std::vector& binaries) { + size_t total_size = 0; + for (const auto& binary : binaries) { + total_size += binary.size(); + } + auto bytes = std::make_shared>(total_size); + uint8_t* data_ptr = bytes->data(); + for (const auto& binary : binaries) { + memcpy(data_ptr, binary.data(), binary.size()); + data_ptr += binary.size(); + } + return Binary(bytes); +} + +// static +Binary Binary::fromBase64(const String& base64, bool* success) { + Binary binary{}; + size_t base64_len = simdutf::maximal_binary_length_from_base64( + base64.data(), base64.length()); + binary.bytes_->resize(base64_len); + + simdutf::result result; + result = + simdutf::base64_to_binary(base64.data(), + base64.length(), + reinterpret_cast(binary.bytes_->data())); + CHECK_EQ(result.error, simdutf::error_code::SUCCESS); + return binary; +} + +// static +Binary Binary::fromUint8Array(v8::Local data) { + auto bytes = std::make_shared>(data->ByteLength()); + size_t size = data->CopyContents(bytes->data(), data->ByteLength()); + CHECK_EQ(size, data->ByteLength()); + return Binary(bytes); +} + } // namespace protocol } // namespace inspector } // namespace node diff --git a/src/inspector/node_string.h b/src/inspector/node_string.h index 38cf96e874dcc4..94ec9b2301998c 100644 --- a/src/inspector/node_string.h +++ b/src/inspector/node_string.h @@ -3,13 +3,17 @@ #ifndef SRC_INSPECTOR_NODE_STRING_H_ #define SRC_INSPECTOR_NODE_STRING_H_ +#include +#include +#include +#include "crdtp/maybe.h" #include "crdtp/protocol_core.h" #include "util.h" #include "v8-inspector.h" -#include -#include -#include +namespace node::inspector::protocol { +class Binary; +} namespace crdtp { @@ -19,6 +23,19 @@ struct ProtocolTypeTraits { static void Serialize(const std::string& value, std::vector* bytes); }; +template <> +struct ProtocolTypeTraits { + static bool Deserialize(DeserializerState* state, + node::inspector::protocol::Binary* value); + static void Serialize(const node::inspector::protocol::Binary& value, + std::vector* bytes); +}; + +template <> +struct detail::MaybeTypedef { + typedef ValueMaybe type; +}; + } // namespace crdtp namespace node { @@ -55,18 +72,32 @@ struct StringUtil { }; // A read-only sequence of uninterpreted bytes with reference-counted storage. -// Though the templates for generating the protocol bindings reference -// this type, js_protocol.pdl doesn't have a field of type 'binary', so -// therefore it's unnecessary to provide an implementation here. class Binary { public: - const uint8_t* data() const { UNREACHABLE(); } - size_t size() const { UNREACHABLE(); } - String toBase64() const { UNREACHABLE(); } - static Binary fromBase64(const std::string_view base64, bool* success) { - UNREACHABLE(); + Binary() : bytes_(std::make_shared>()) {} + + const uint8_t* data() const { return bytes_->data(); } + size_t size() const { return bytes_->size(); } + + String toBase64() const; + + static Binary concat(const std::vector& binaries); + + static Binary fromBase64(const String& base64, bool* success); + static Binary fromUint8Array(v8::Local data); + static Binary fromSpan(const uint8_t* data, size_t size) { + return Binary::fromSpan(crdtp::span(data, size)); + } + static Binary fromSpan(crdtp::span span) { + return Binary( + std::make_shared>(span.begin(), span.end())); } - static Binary fromSpan(const uint8_t* data, size_t size) { UNREACHABLE(); } + + private: + std::shared_ptr> bytes_; + + explicit Binary(std::shared_ptr> bytes) + : bytes_(bytes) {} }; } // namespace protocol diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index 8f97ca4d9cbb84..260a572ce71a82 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -114,7 +114,7 @@ napi_status NewExternalString(napi_env env, CHECK_NEW_STRING_ARGS(env, str, length, result); napi_status status; -#if defined(V8_ENABLE_SANDBOX) +#ifdef V8_ENABLE_SANDBOX status = create_api(env, str, length, result); if (status == napi_ok) { if (copied != nullptr) { @@ -2441,21 +2441,21 @@ napi_status NAPI_CDECL napi_get_value_string_latin1( v8::Local val = v8impl::V8LocalValueFromJsValue(value); RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected); + v8::Local str = val.As(); if (!buf) { CHECK_ARG(env, result); - *result = val.As()->Length(); + *result = str->Length(); } else if (bufsize != 0) { - int copied = - val.As()->WriteOneByte(env->isolate, - reinterpret_cast(buf), - 0, - bufsize - 1, - v8::String::NO_NULL_TERMINATION); - - buf[copied] = '\0'; + uint32_t length = static_cast( + std::min(bufsize - 1, static_cast(str->Length()))); + str->WriteOneByteV2(env->isolate, + 0, + length, + reinterpret_cast(buf), + v8::String::WriteFlags::kNullTerminate); if (result != nullptr) { - *result = copied; + *result = length; } } else if (result != nullptr) { *result = 0; @@ -2479,12 +2479,12 @@ napi_status NAPI_CDECL napi_get_value_string_utf8( v8::Local val = v8impl::V8LocalValueFromJsValue(value); RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected); + v8::Local str = val.As(); if (!buf) { CHECK_ARG(env, result); - *result = val.As()->Utf8LengthV2(env->isolate); + *result = str->Utf8LengthV2(env->isolate); } else if (bufsize != 0) { - auto str = val.As(); size_t copied = str->WriteUtf8V2(env->isolate, buf, @@ -2520,21 +2520,23 @@ napi_status NAPI_CDECL napi_get_value_string_utf16(napi_env env, v8::Local val = v8impl::V8LocalValueFromJsValue(value); RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected); + v8::Local str = val.As(); if (!buf) { CHECK_ARG(env, result); // V8 assumes UTF-16 length is the same as the number of characters. - *result = val.As()->Length(); + *result = str->Length(); } else if (bufsize != 0) { - int copied = val.As()->Write(env->isolate, - reinterpret_cast(buf), - 0, - bufsize - 1, - v8::String::NO_NULL_TERMINATION); + uint32_t length = static_cast( + std::min(bufsize - 1, static_cast(str->Length()))); + str->WriteV2(env->isolate, + 0, + length, + reinterpret_cast(buf), + v8::String::WriteFlags::kNullTerminate); - buf[copied] = '\0'; if (result != nullptr) { - *result = copied; + *result = length; } } else if (result != nullptr) { *result = 0; diff --git a/src/memory_tracker-inl.h b/src/memory_tracker-inl.h index 31ed6fad98ccc8..56f4a180633d39 100644 --- a/src/memory_tracker-inl.h +++ b/src/memory_tracker-inl.h @@ -3,6 +3,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS +#include "cppgc_helpers.h" #include "memory_tracker.h" #include "util-inl.h" @@ -36,6 +37,22 @@ class MemoryRetainerNode : public v8::EmbedderGraph::Node { detachedness_ = retainer_->GetDetachedness(); } + inline MemoryRetainerNode(MemoryTracker* tracker, const CppgcMixin* mixin) + : retainer_(mixin) { + // In this case, the MemoryRetainerNode is merely a wrapper + // to be used in the NodeMap and stack. The actual node being using to add + // edges is always the merged wrapper node of the cppgc-managed wrapper. + CHECK_NOT_NULL(retainer_); + v8::Isolate* isolate = tracker->isolate(); + v8::HandleScope handle_scope(isolate); + v8::Local obj = mixin->object(isolate); + wrapper_node_ = tracker->graph()->V8Node(obj.As()); + + name_ = retainer_->MemoryInfoName(); + size_ = 0; + detachedness_ = retainer_->GetDetachedness(); + } + inline MemoryRetainerNode(MemoryTracker* tracker, const char* name, size_t size, @@ -60,6 +77,11 @@ class MemoryRetainerNode : public v8::EmbedderGraph::Node { } return is_root_node_; } + + bool IsCppgcWrapper() const { + return retainer_ != nullptr && retainer_->IsCppgcWrapper(); + } + v8::EmbedderGraph::Node::Detachedness GetDetachedness() override { return detachedness_; } @@ -94,7 +116,7 @@ void MemoryTracker::TrackInlineFieldWithSize(const char* edge_name, const char* node_name) { if (size > 0) AddNode(GetNodeName(node_name, edge_name), size, edge_name); CHECK(CurrentNode()); - CurrentNode()->size_ -= size; + AdjustCurrentNodeSize(-static_cast(size)); } void MemoryTracker::TrackField(const char* edge_name, @@ -155,7 +177,7 @@ void MemoryTracker::TrackField(const char* edge_name, // Fall back to edge name if node names are not provided if (CurrentNode() != nullptr && subtract_from_self) { // Shift the self size of this container out to a separate node - CurrentNode()->size_ -= sizeof(T); + AdjustCurrentNodeSize(-static_cast(sizeof(T))); } PushNode(GetNodeName(node_name, edge_name), sizeof(T), edge_name); for (Iterator it = value.begin(); it != value.end(); ++it) { @@ -186,7 +208,7 @@ void MemoryTracker::TrackField(const char* edge_name, const T& value, const char* node_name) { // For numbers, creating new nodes is not worth the overhead. - CurrentNode()->size_ += sizeof(T); + AdjustCurrentNodeSize(static_cast(sizeof(T))); } template @@ -273,6 +295,22 @@ void MemoryTracker::TrackInlineField(const char* name, TrackInlineFieldWithSize(name, sizeof(value), "uv_async_t"); } +void MemoryTracker::Track(const CppgcMixin* retainer, const char* edge_name) { + v8::HandleScope handle_scope(isolate_); + auto it = seen_.find(retainer); + if (it != seen_.end()) { + if (CurrentNode() != nullptr) { + graph_->AddEdge(CurrentNode(), it->second, edge_name); + } + return; // It has already been tracked, no need to call MemoryInfo again + } + MemoryRetainerNode* n = PushNode(retainer, edge_name); + retainer->MemoryInfo(this); + CHECK_EQ(CurrentNode(), n->JSWrapperNode()); + // This is a dummy MemoryRetainerNode. The real graph node is wrapper_node_. + PopNode(); +} + void MemoryTracker::Track(const MemoryRetainer* retainer, const char* edge_name) { v8::HandleScope handle_scope(isolate_); @@ -294,7 +332,7 @@ void MemoryTracker::TrackInlineField(const MemoryRetainer* retainer, const char* edge_name) { Track(retainer, edge_name); CHECK(CurrentNode()); - CurrentNode()->size_ -= retainer->SelfSize(); + AdjustCurrentNodeSize(-(static_cast(retainer->SelfSize()))); } template @@ -315,12 +353,33 @@ inline void MemoryTracker::TraitTrackInline(const T& retainer, const char* edge_name) { TraitTrack(retainer, edge_name); CHECK(CurrentNode()); - CurrentNode()->size_ -= MemoryRetainerTraits::SelfSize(retainer); + AdjustCurrentNodeSize( + -(static_cast(MemoryRetainerTraits::SelfSize(retainer)))); } -MemoryRetainerNode* MemoryTracker::CurrentNode() const { +v8::EmbedderGraph::Node* MemoryTracker::CurrentNode() const { if (node_stack_.empty()) return nullptr; - return node_stack_.top(); + MemoryRetainerNode* n = node_stack_.top(); + if (n->IsCppgcWrapper()) { + return n->JSWrapperNode(); + } + return n; +} + +MemoryRetainerNode* MemoryTracker::AddNode(const CppgcMixin* retainer, + const char* edge_name) { + auto it = seen_.find(retainer); + if (it != seen_.end()) { + return it->second; + } + + MemoryRetainerNode* n = new MemoryRetainerNode(this, retainer); + seen_[retainer] = n; + if (CurrentNode() != nullptr) { + graph_->AddEdge(CurrentNode(), n->JSWrapperNode(), edge_name); + } + + return n; } MemoryRetainerNode* MemoryTracker::AddNode(const MemoryRetainer* retainer, @@ -354,6 +413,13 @@ MemoryRetainerNode* MemoryTracker::AddNode(const char* node_name, return n; } +MemoryRetainerNode* MemoryTracker::PushNode(const CppgcMixin* retainer, + const char* edge_name) { + MemoryRetainerNode* n = AddNode(retainer, edge_name); + node_stack_.push(n); + return n; +} + MemoryRetainerNode* MemoryTracker::PushNode(const MemoryRetainer* retainer, const char* edge_name) { MemoryRetainerNode* n = AddNode(retainer, edge_name); @@ -373,6 +439,14 @@ void MemoryTracker::PopNode() { node_stack_.pop(); } +void MemoryTracker::AdjustCurrentNodeSize(int diff) { + if (node_stack_.empty()) return; + MemoryRetainerNode* n = node_stack_.top(); + if (!n->IsCppgcWrapper()) { + n->size_ = static_cast(static_cast(n->size_) + diff); + } +} + } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/src/memory_tracker.h b/src/memory_tracker.h index 4e0a2fbaaac4f6..a6c3fee6a847a1 100644 --- a/src/memory_tracker.h +++ b/src/memory_tracker.h @@ -18,6 +18,8 @@ class BackingStore; namespace node { +class CppgcMixin; + template struct MallocedBuffer; @@ -133,6 +135,7 @@ class MemoryRetainer { } virtual bool IsRootNode() const { return false; } + virtual bool IsCppgcWrapper() const { return false; } virtual v8::EmbedderGraph::Node::Detachedness GetDetachedness() const { return v8::EmbedderGraph::Node::Detachedness::kUnknown; } @@ -267,6 +270,8 @@ class MemoryTracker { // Put a memory container into the graph, create an edge from // the current node if there is one on the stack. + inline void Track(const CppgcMixin* retainer, + const char* edge_name = nullptr); inline void Track(const MemoryRetainer* retainer, const char* edge_name = nullptr); @@ -299,9 +304,14 @@ class MemoryTracker { typedef std::unordered_map NodeMap; - inline MemoryRetainerNode* CurrentNode() const; + inline void AdjustCurrentNodeSize(int diff); + inline v8::EmbedderGraph::Node* CurrentNode() const; + inline MemoryRetainerNode* AddNode(const CppgcMixin* retainer, + const char* edge_name = nullptr); inline MemoryRetainerNode* AddNode(const MemoryRetainer* retainer, const char* edge_name = nullptr); + inline MemoryRetainerNode* PushNode(const CppgcMixin* retainer, + const char* edge_name = nullptr); inline MemoryRetainerNode* PushNode(const MemoryRetainer* retainer, const char* edge_name = nullptr); inline MemoryRetainerNode* AddNode(const char* node_name, diff --git a/src/module_wrap.cc b/src/module_wrap.cc index ac9840cecb3ed5..dd0f74c5580561 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -308,6 +308,13 @@ void ModuleWrap::New(const FunctionCallbackInfo& args) { return; } + if (that->Set(context, + realm->env()->source_url_string(), + module->GetUnboundModuleScript()->GetSourceURL()) + .IsNothing()) { + return; + } + if (that->Set(context, realm->env()->source_map_url_string(), module->GetUnboundModuleScript()->GetSourceMappingURL()) @@ -1020,16 +1027,23 @@ static MaybeLocal ImportModuleDynamicallyWithPhase( }; Local result; - if (import_callback->Call( - context, - Undefined(isolate), - arraysize(import_args), - import_args).ToLocal(&result)) { - CHECK(result->IsPromise()); - return handle_scope.Escape(result.As()); + if (!import_callback + ->Call( + context, Undefined(isolate), arraysize(import_args), import_args) + .ToLocal(&result)) { + return {}; } - return MaybeLocal(); + // Wrap the returned value in a promise created in the referrer context to + // avoid dynamic scopes. + Local resolver; + if (!Promise::Resolver::New(context).ToLocal(&resolver)) { + return {}; + } + if (resolver->Resolve(context, result).IsNothing()) { + return {}; + } + return handle_scope.Escape(resolver->GetPromise()); } static MaybeLocal ImportModuleDynamically( @@ -1058,10 +1072,8 @@ void ModuleWrap::SetImportModuleDynamicallyCallback( realm->set_host_import_module_dynamically_callback(import_callback); isolate->SetHostImportModuleDynamicallyCallback(ImportModuleDynamically); - // TODO(guybedford): Enable this once - // https://github.com/nodejs/node/pull/56842 lands. - // isolate->SetHostImportModuleWithPhaseDynamicallyCallback( - // ImportModuleDynamicallyWithPhase); + isolate->SetHostImportModuleWithPhaseDynamicallyCallback( + ImportModuleDynamicallyWithPhase); } void ModuleWrap::HostInitializeImportMetaObjectCallback( diff --git a/src/node.cc b/src/node.cc index f921303b639dbc..c70b2d53af954c 100644 --- a/src/node.cc +++ b/src/node.cc @@ -910,7 +910,7 @@ static ExitCode InitializeNodeWithArgsInternal( default: UNREACHABLE(); } - node_options_from_config = per_process::config_reader.AssignNodeOptions(); + node_options_from_config = per_process::config_reader.GetNodeOptions(); // (@marco-ippolito) Avoid reparsing the env options again std::vector env_argv_from_config = ParseNodeOptionsEnvVar(node_options_from_config, errors); @@ -956,7 +956,19 @@ static ExitCode InitializeNodeWithArgsInternal( #endif if (!(flags & ProcessInitializationFlags::kDisableCLIOptions)) { - const ExitCode exit_code = + // Parse the options coming from the config file. + // This is done before parsing the command line options + // as the cli flags are expected to override the config file ones. + std::vector extra_argv = + per_process::config_reader.GetNamespaceFlags(); + // [0] is expected to be the program name, fill it in from the real argv. + extra_argv.insert(extra_argv.begin(), argv->at(0)); + // Parse the extra argv coming from the config file + ExitCode exit_code = ProcessGlobalArgsInternal( + &extra_argv, nullptr, errors, kDisallowedInEnvvar); + if (exit_code != ExitCode::kNoFailure) return exit_code; + // Parse options coming from the command line. + exit_code = ProcessGlobalArgsInternal(argv, exec_argv, errors, kDisallowedInEnvvar); if (exit_code != ExitCode::kNoFailure) return exit_code; } @@ -1175,10 +1187,7 @@ InitializeOncePerProcessInternal(const std::vector& args, } #endif if (!crypto::ProcessFipsOptions()) { - // XXX: ERR_GET_REASON does not return something that is - // useful as an exit code at all. - result->exit_code_ = - static_cast(ERR_GET_REASON(ERR_peek_error())); + result->exit_code_ = ExitCode::kGenericUserError; result->early_return_ = true; result->errors_.emplace_back( "OpenSSL error when trying to enable FIPS:\n" + diff --git a/src/node_api.cc b/src/node_api.cc index 5c85ef063ecd77..fbe3d84fc20d12 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -704,9 +704,9 @@ void napi_module_register_by_symbol(v8::Local exports, napi_addon_register_func init, int32_t module_api_version) { node::Environment* node_env = node::Environment::GetCurrent(context); + CHECK_NOT_NULL(node_env); std::string module_filename = ""; if (init == nullptr) { - CHECK_NOT_NULL(node_env); node_env->ThrowError("Module has no declared entry point."); return; } @@ -1056,9 +1056,9 @@ napi_create_external_buffer(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, result); -#if defined(V8_ENABLE_SANDBOX) +#ifdef V8_ENABLE_SANDBOX return napi_set_last_error(env, napi_no_external_buffers_allowed); -#endif +#endif // V8_ENABLE_SANDBOX v8::Isolate* isolate = env->isolate; diff --git a/src/node_blob.cc b/src/node_blob.cc index d887485b9deed8..e8c0795fcaac60 100644 --- a/src/node_blob.cc +++ b/src/node_blob.cc @@ -21,6 +21,7 @@ using v8::Array; using v8::ArrayBuffer; using v8::ArrayBufferView; using v8::BackingStore; +using v8::BackingStoreInitializationMode; using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; @@ -82,8 +83,8 @@ void Concat(const FunctionCallbackInfo& args) { } } - std::shared_ptr store = - ArrayBuffer::NewBackingStore(env->isolate(), total); + std::shared_ptr store = ArrayBuffer::NewBackingStore( + env->isolate(), total, BackingStoreInitializationMode::kUninitialized); uint8_t* ptr = static_cast(store->Data()); for (size_t n = 0; n < views.size(); n++) { uint8_t* from = @@ -210,8 +211,8 @@ void Blob::New(const FunctionCallbackInfo& args) { } // If the ArrayBuffer is not detachable, we will copy from it instead. - std::shared_ptr store = - ArrayBuffer::NewBackingStore(isolate, byte_length); + std::shared_ptr store = ArrayBuffer::NewBackingStore( + isolate, byte_length, BackingStoreInitializationMode::kUninitialized); uint8_t* ptr = static_cast(buf->Data()) + byte_offset; std::copy(ptr, ptr + byte_length, static_cast(store->Data())); return DataQueue::CreateInMemoryEntryFromBackingStore( @@ -375,8 +376,10 @@ void Blob::Reader::Pull(const FunctionCallbackInfo& args) { size_t total = 0; for (size_t n = 0; n < count; n++) total += vecs[n].len; - std::shared_ptr store = - ArrayBuffer::NewBackingStore(env->isolate(), total); + std::shared_ptr store = ArrayBuffer::NewBackingStore( + env->isolate(), + total, + BackingStoreInitializationMode::kUninitialized); auto ptr = static_cast(store->Data()); for (size_t n = 0; n < count; n++) { std::copy(vecs[n].base, vecs[n].base + vecs[n].len, ptr); diff --git a/src/node_buffer.cc b/src/node_buffer.cc index f6329856e6ea93..8ec282107e1d99 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -329,7 +329,8 @@ MaybeLocal New(Isolate* isolate, if (actual > 0) [[likely]] { if (actual < length) { std::unique_ptr old_store = std::move(store); - store = ArrayBuffer::NewBackingStore(isolate, actual); + store = ArrayBuffer::NewBackingStore( + isolate, actual, BackingStoreInitializationMode::kUninitialized); memcpy(store->Data(), old_store->Data(), actual); } Local buf = ArrayBuffer::New(isolate, std::move(store)); @@ -416,7 +417,7 @@ MaybeLocal Copy(Environment* env, const char* data, size_t length) { CHECK(bs); - memcpy(bs->Data(), data, length); + if (length > 0) memcpy(bs->Data(), data, length); Local ab = ArrayBuffer::New(isolate, std::move(bs)); @@ -506,6 +507,17 @@ MaybeLocal New(Environment* env, } } +#if defined(V8_ENABLE_SANDBOX) + // When v8 sandbox is enabled, external backing stores are not supported + // since all arraybuffer allocations are expected to be done by the isolate. + // Since this violates the contract of this function, let's free the data and + // throw an error. + free(data); + THROW_ERR_OPERATION_FAILED( + env->isolate(), + "Wrapping external data is not supported when the v8 sandbox is enabled"); + return MaybeLocal(); +#else EscapableHandleScope handle_scope(env->isolate()); auto free_callback = [](void* data, size_t length, void* deleter_data) { @@ -520,6 +532,7 @@ MaybeLocal New(Environment* env, if (Buffer::New(env, ab, 0, length).ToLocal(&obj)) return handle_scope.Escape(obj); return Local(); +#endif } namespace { @@ -742,7 +755,7 @@ uint32_t FastByteLengthUtf8( Local sourceStr = sourceValue.As(); if (!sourceStr->IsExternalOneByte()) { - return sourceStr->Utf8Length(isolate); + return sourceStr->Utf8LengthV2(isolate); } auto source = sourceStr->GetExternalOneByteStringResource(); // For short inputs, the function call overhead to simdutf is maybe diff --git a/src/node_builtins.cc b/src/node_builtins.cc index 48b2debfbe9eac..ef42d8e0d4987d 100644 --- a/src/node_builtins.cc +++ b/src/node_builtins.cc @@ -64,6 +64,11 @@ BuiltinLoader::BuiltinLoader() #endif // HAVE_AMARO } +std::ranges::keys_view> +BuiltinLoader::GetBuiltinIds() const { + return std::views::keys(*source_.read()); +} + bool BuiltinLoader::Exists(const char* id) { auto source = source_.read(); return source->find(id) != source->end(); diff --git a/src/node_builtins.h b/src/node_builtins.h index 83ddad2127227d..7a7b84337feb67 100644 --- a/src/node_builtins.h +++ b/src/node_builtins.h @@ -127,9 +127,9 @@ class NODE_EXTERN_PRIVATE BuiltinLoader { void CopySourceAndCodeCacheReferenceFrom(const BuiltinLoader* other); - [[nodiscard]] auto GetBuiltinIds() const { - return std::views::keys(*source_.read()); - } + [[nodiscard]] std::ranges::keys_view< + std::ranges::ref_view> + GetBuiltinIds() const; void SetEagerCompile() { should_eager_compile_ = true; } diff --git a/src/node_config.cc b/src/node_config.cc index f6ca010ff9304f..6032bbd10f41da 100644 --- a/src/node_config.cc +++ b/src/node_config.cc @@ -48,6 +48,12 @@ static void InitConfig(Local target, READONLY_FALSE_PROPERTY(target, "isDebugBuild"); #endif // defined(DEBUG) && DEBUG +#ifdef OPENSSL_IS_BORINGSSL + READONLY_TRUE_PROPERTY(target, "openSSLIsBoringSSL"); +#else + READONLY_FALSE_PROPERTY(target, "openSSLIsBoringSSL"); +#endif // OPENSSL_IS_BORINGSSL + #if HAVE_OPENSSL READONLY_TRUE_PROPERTY(target, "hasOpenSSL"); #else diff --git a/src/node_config_file.cc b/src/node_config_file.cc index e697002ae1a2e0..fa064ce6c913ab 100644 --- a/src/node_config_file.cc +++ b/src/node_config_file.cc @@ -23,7 +23,7 @@ std::optional ConfigReader::GetDataFromArgs( } else if (it->starts_with(flag_path)) { // Case: "--experimental-config-file=foo" if (it->size() > flag_path.size() && (*it)[flag_path.size()] == '=') { - return it->substr(flag_path.size() + 1); + return std::string_view(*it).substr(flag_path.size() + 1); } } else if (*it == default_file || it->starts_with(default_file)) { has_default_config_file = true; @@ -37,121 +37,171 @@ std::optional ConfigReader::GetDataFromArgs( return std::nullopt; } -ParseResult ConfigReader::ParseNodeOptions( - simdjson::ondemand::object* node_options_object) { - auto env_options_map = options_parser::MapEnvOptionsFlagInputType(); - simdjson::ondemand::value ondemand_value; - std::string_view key; +ParseResult ConfigReader::ProcessOptionValue( + const std::pair& option_info, + simdjson::ondemand::value* option_value, + std::vector* output) { + const std::string& option_name = option_info.first; + const options_parser::OptionType option_type = option_info.second; - for (auto field : *node_options_object) { - if (field.unescaped_key().get(key) || field.value().get(ondemand_value)) { - return ParseResult::InvalidContent; - } - - // The key needs to match the CLI option - std::string prefix = "--"; - auto it = env_options_map.find(prefix.append(key)); - if (it != env_options_map.end()) { - switch (it->second) { - case options_parser::OptionType::kBoolean: { - bool result; - if (ondemand_value.get_bool().get(result)) { - FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); - return ParseResult::InvalidContent; - } + switch (option_type) { + case options_parser::OptionType::kBoolean: { + bool result; + if (option_value->get_bool().get(result)) { + FPrintF(stderr, "Invalid value for %s\n", option_name.c_str()); + return ParseResult::InvalidContent; + } - if (result) { - // If the value is true, we need to set the flag - node_options_.push_back(it->first); - } + if (result) { + // If the value is true, we need to set the flag + output->push_back(option_name); + } - break; - } - // String array can allow both string and array types - case options_parser::OptionType::kStringList: { - simdjson::ondemand::json_type field_type; - if (ondemand_value.type().get(field_type)) { + break; + } + // String array can allow both string and array types + case options_parser::OptionType::kStringList: { + simdjson::ondemand::json_type field_type; + if (option_value->type().get(field_type)) { + return ParseResult::InvalidContent; + } + switch (field_type) { + case simdjson::ondemand::json_type::array: { + std::vector result; + simdjson::ondemand::array raw_imports; + if (option_value->get_array().get(raw_imports)) { + FPrintF(stderr, "Invalid value for %s\n", option_name.c_str()); return ParseResult::InvalidContent; } - switch (field_type) { - case simdjson::ondemand::json_type::array: { - std::vector result; - simdjson::ondemand::array raw_imports; - if (ondemand_value.get_array().get(raw_imports)) { - FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); - return ParseResult::InvalidContent; - } - for (auto raw_import : raw_imports) { - std::string_view import; - if (raw_import.get_string(import)) { - FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); - return ParseResult::InvalidContent; - } - node_options_.push_back(it->first + "=" + std::string(import)); - } - break; - } - case simdjson::ondemand::json_type::string: { - std::string result; - if (ondemand_value.get_string(result)) { - FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); - return ParseResult::InvalidContent; - } - node_options_.push_back(it->first + "=" + result); - break; - } - default: - FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); + for (auto raw_import : raw_imports) { + std::string_view import; + if (raw_import.get_string(import)) { + FPrintF(stderr, "Invalid value for %s\n", option_name.c_str()); return ParseResult::InvalidContent; + } + output->push_back(option_name + "=" + std::string(import)); } break; } - case options_parser::OptionType::kString: { + case simdjson::ondemand::json_type::string: { std::string result; - if (ondemand_value.get_string(result)) { - FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); - return ParseResult::InvalidContent; - } - node_options_.push_back(it->first + "=" + result); - break; - } - case options_parser::OptionType::kInteger: { - int64_t result; - if (ondemand_value.get_int64().get(result)) { - FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); - return ParseResult::InvalidContent; - } - node_options_.push_back(it->first + "=" + std::to_string(result)); - break; - } - case options_parser::OptionType::kHostPort: - case options_parser::OptionType::kUInteger: { - uint64_t result; - if (ondemand_value.get_uint64().get(result)) { - FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); + if (option_value->get_string(result)) { + FPrintF(stderr, "Invalid value for %s\n", option_name.c_str()); return ParseResult::InvalidContent; } - node_options_.push_back(it->first + "=" + std::to_string(result)); + output->push_back(option_name + "=" + result); break; } - case options_parser::OptionType::kNoOp: { - FPrintF(stderr, - "No-op flag %s is currently not supported\n", - it->first.c_str()); - return ParseResult::InvalidContent; - break; - } - case options_parser::OptionType::kV8Option: { - FPrintF(stderr, - "V8 flag %s is currently not supported\n", - it->first.c_str()); - return ParseResult::InvalidContent; - } default: - UNREACHABLE(); + FPrintF(stderr, "Invalid value for %s\n", option_name.c_str()); + return ParseResult::InvalidContent; + } + break; + } + case options_parser::OptionType::kString: { + std::string result; + if (option_value->get_string(result)) { + FPrintF(stderr, "Invalid value for %s\n", option_name.c_str()); + return ParseResult::InvalidContent; + } + output->push_back(option_name + "=" + result); + break; + } + case options_parser::OptionType::kInteger: { + int64_t result; + if (option_value->get_int64().get(result)) { + FPrintF(stderr, "Invalid value for %s\n", option_name.c_str()); + return ParseResult::InvalidContent; + } + output->push_back(option_name + "=" + std::to_string(result)); + break; + } + case options_parser::OptionType::kHostPort: + case options_parser::OptionType::kUInteger: { + uint64_t result; + if (option_value->get_uint64().get(result)) { + FPrintF(stderr, "Invalid value for %s\n", option_name.c_str()); + return ParseResult::InvalidContent; + } + output->push_back(option_name + "=" + std::to_string(result)); + break; + } + case options_parser::OptionType::kNoOp: { + FPrintF(stderr, + "No-op flag %s is currently not supported\n", + option_name.c_str()); + return ParseResult::InvalidContent; + break; + } + case options_parser::OptionType::kV8Option: { + FPrintF(stderr, + "V8 flag %s is currently not supported\n", + option_name.c_str()); + return ParseResult::InvalidContent; + } + default: + UNREACHABLE(); + } + return ParseResult::Valid; +} + +ParseResult ConfigReader::ParseOptions( + simdjson::ondemand::object* options_object, + std::unordered_set* unique_options, + const std::string& namespace_name) { + // Determine which options map to use and output vector + std::unordered_map options_map; + std::vector* output_vector; + + if (namespace_name == "nodeOptions") { + // Special case for backward compatibility: handle nodeOptions with env + // options map + options_map = options_parser::MapEnvOptionsFlagInputType(); + output_vector = &node_options_; + } else { + // Handle other namespaces + options_map = options_parser::MapOptionsByNamespace(namespace_name); + output_vector = &namespace_options_; + + if (!env_options_initialized_) { + env_options_map_ = options_parser::MapEnvOptionsFlagInputType(); + env_options_initialized_ = true; + } + } + + simdjson::ondemand::value option_value; + std::string_view option_key; + + for (auto field : *options_object) { + if (field.unescaped_key().get(option_key) || + field.value().get(option_value)) { + return ParseResult::InvalidContent; + } + + // The key needs to match the CLI option + std::string prefix = "--"; + auto option = options_map.find(prefix.append(option_key)); + if (option != options_map.end()) { + // If the option has already been set, return an error + if (unique_options->contains(option->first)) { + FPrintF( + stderr, "Option %s is already defined\n", option->first.c_str()); + return ParseResult::InvalidContent; + } + // Add the option to the unique set to prevent duplicates + // on future iterations + unique_options->insert(option->first); + // Process the option value based on its type + ParseResult result = + ProcessOptionValue(*option, &option_value, output_vector); + if (result != ParseResult::Valid) { + return result; } } else { - FPrintF(stderr, "Unknown or not allowed option %s\n", key.data()); + FPrintF(stderr, + "Unknown or not allowed option %s for namespace %s\n", + option_key.data(), + namespace_name.c_str()); return ParseResult::InvalidContent; } } @@ -177,9 +227,10 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) { return ParseResult::InvalidContent; } + // Validate config is an object simdjson::ondemand::object main_object; - // If document is not an object, throw an error. - if (auto root_error = document.get_object().get(main_object)) { + auto root_error = document.get_object().get(main_object); + if (root_error) { if (root_error == simdjson::error_code::INCORRECT_TYPE) { FPrintF(stderr, "Root value unexpected not an object for %s\n\n", @@ -190,36 +241,67 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) { return ParseResult::InvalidContent; } - simdjson::ondemand::object node_options_object; - // If "nodeOptions" is an object, parse it - if (auto node_options_error = - main_object["nodeOptions"].get_object().get(node_options_object)) { - if (node_options_error != simdjson::error_code::NO_SUCH_FIELD) { + // Get all available namespaces for validation + std::vector available_namespaces = + options_parser::MapAvailableNamespaces(); + // Add "nodeOptions" as a special case for backward compatibility + available_namespaces.emplace_back("nodeOptions"); + + // Create a set for faster lookup of valid namespaces + std::unordered_set valid_namespaces(available_namespaces.begin(), + available_namespaces.end()); + // Create a set to track unique options + std::unordered_set unique_options; + // Iterate through the main object to find all namespaces + for (auto field : main_object) { + std::string_view field_name; + if (field.unescaped_key().get(field_name)) { + return ParseResult::InvalidContent; + } + + // Check if this field is a valid namespace + std::string namespace_name(field_name); + if (!valid_namespaces.contains(namespace_name)) { + // If not, skip it + continue; + } + + // Get the namespace object + simdjson::ondemand::object namespace_object; + auto field_error = field.value().get_object().get(namespace_object); + + // If namespace value is not an object + if (field_error) { FPrintF(stderr, - "\"nodeOptions\" value unexpected for %s\n\n", + "\"%s\" value unexpected for %s (should be an object)\n", + namespace_name.c_str(), config_path.data()); return ParseResult::InvalidContent; } - } else { - return ParseNodeOptions(&node_options_object); + + // Process options for this namespace using the unified method + ParseResult result = + ParseOptions(&namespace_object, &unique_options, namespace_name); + if (result != ParseResult::Valid) { + return result; + } } return ParseResult::Valid; } -std::string ConfigReader::AssignNodeOptions() { - if (node_options_.empty()) { - return ""; - } else { - DCHECK_GT(node_options_.size(), 0); - std::string acc; - acc.reserve(node_options_.size() * 2); - for (size_t i = 0; i < node_options_.size(); ++i) { - // The space is necessary at the beginning of the string - acc += " " + node_options_[i]; - } - return acc; +std::string ConfigReader::GetNodeOptions() { + std::string acc = ""; + const size_t total_options = node_options_.size(); + acc.reserve(total_options * 2); + for (auto& opt : node_options_) { + acc += " " + opt; } + return acc; +} + +const std::vector& ConfigReader::GetNamespaceFlags() const { + return namespace_options_; } size_t ConfigReader::GetFlagsSize() { diff --git a/src/node_config_file.h b/src/node_config_file.h index 5419590a9e05fb..b369dca97b0062 100644 --- a/src/node_config_file.h +++ b/src/node_config_file.h @@ -5,7 +5,10 @@ #include #include +#include +#include #include +#include #include "node_internals.h" #include "simdjson.h" #include "util-inl.h" @@ -29,14 +32,30 @@ class ConfigReader { std::optional GetDataFromArgs( const std::vector& args); - std::string AssignNodeOptions(); + std::string GetNodeOptions(); + const std::vector& GetNamespaceFlags() const; size_t GetFlagsSize(); private: - ParseResult ParseNodeOptions(simdjson::ondemand::object* node_options_object); + // Parse options for a specific namespace (including nodeOptions for backward + // compatibility) + ParseResult ParseOptions(simdjson::ondemand::object* options_object, + std::unordered_set* unique_options, + const std::string& namespace_name); + + // Process a single option value based on its type + ParseResult ProcessOptionValue( + const std::pair& option_info, + simdjson::ondemand::value* option_value, + std::vector* output); std::vector node_options_; + std::vector namespace_options_; + + // Cache for fast lookup of environment options + std::unordered_map env_options_map_; + bool env_options_initialized_ = false; }; } // namespace node diff --git a/src/node_constants.cc b/src/node_constants.cc index 906e1f6a632d9b..aebda8fb44b919 100644 --- a/src/node_constants.cc +++ b/src/node_constants.cc @@ -1041,7 +1041,7 @@ void DefineCryptoConstants(Local target) { #endif } -void DefineSystemConstants(Local target) { +void DefineFsConstants(Local target) { NODE_DEFINE_CONSTANT(target, UV_FS_SYMLINK_DIR); NODE_DEFINE_CONSTANT(target, UV_FS_SYMLINK_JUNCTION); // file access modes @@ -1059,10 +1059,6 @@ void DefineSystemConstants(Local target) { NODE_DEFINE_CONSTANT(target, UV_DIRENT_CHAR); NODE_DEFINE_CONSTANT(target, UV_DIRENT_BLOCK); - // Define module specific constants - NODE_DEFINE_CONSTANT(target, EXTENSIONLESS_FORMAT_JAVASCRIPT); - NODE_DEFINE_CONSTANT(target, EXTENSIONLESS_FORMAT_WASM); - NODE_DEFINE_CONSTANT(target, S_IFMT); NODE_DEFINE_CONSTANT(target, S_IFREG); NODE_DEFINE_CONSTANT(target, S_IFDIR); @@ -1250,6 +1246,12 @@ void DefineDLOpenConstants(Local target) { #endif } +void DefineInternalConstants(Local target) { + // Define module specific constants + NODE_DEFINE_CONSTANT(target, EXTENSIONLESS_FORMAT_JAVASCRIPT); + NODE_DEFINE_CONSTANT(target, EXTENSIONLESS_FORMAT_WASM); +} + void DefineTraceConstants(Local target) { NODE_DEFINE_CONSTANT(target, TRACE_EVENT_PHASE_BEGIN); NODE_DEFINE_CONSTANT(target, TRACE_EVENT_PHASE_END); @@ -1307,16 +1309,19 @@ void CreatePerContextProperties(Local target, Object::New(isolate, Null(isolate), nullptr, nullptr, 0); Local trace_constants = Object::New(isolate, Null(isolate), nullptr, nullptr, 0); + Local internal_constants = + Object::New(isolate, Null(isolate), nullptr, nullptr, 0); DefineErrnoConstants(err_constants); DefineWindowsErrorConstants(err_constants); DefineSignalConstants(sig_constants); DefinePriorityConstants(priority_constants); - DefineSystemConstants(fs_constants); + DefineFsConstants(fs_constants); DefineCryptoConstants(crypto_constants); DefineZlibConstants(zlib_constants); DefineDLOpenConstants(dlopen_constants); DefineTraceConstants(trace_constants); + DefineInternalConstants(internal_constants); // Define libuv constants. NODE_DEFINE_CONSTANT(os_constants, UV_UDP_REUSEADDR); @@ -1362,6 +1367,11 @@ void CreatePerContextProperties(Local target, FIXED_ONE_BYTE_STRING(isolate, "trace"), trace_constants) .Check(); + target + ->Set(env->context(), + FIXED_ONE_BYTE_STRING(isolate, "internal"), + internal_constants) + .Check(); } } // namespace constants diff --git a/src/node_contextify.cc b/src/node_contextify.cc index c0e84dbca0f7a1..7f3417adba863a 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -330,11 +330,7 @@ ContextifyContext* ContextifyContext::New(Local v8_context, } DCHECK_NOT_NULL(env->isolate()->GetCppHeap()); result = cppgc::MakeGarbageCollected( - env->isolate()->GetCppHeap()->GetAllocationHandle(), - env, - wrapper, - v8_context, - options); + env->cppgc_allocation_handle(), env, wrapper, v8_context, options); } Local wrapper_holder = @@ -365,13 +361,11 @@ void ContextifyContext::CreatePerIsolateProperties( IsolateData* isolate_data, Local target) { Isolate* isolate = isolate_data->isolate(); SetMethod(isolate, target, "makeContext", MakeContext); - SetMethod(isolate, target, "compileFunction", CompileFunction); } void ContextifyContext::RegisterExternalReferences( ExternalReferenceRegistry* registry) { registry->Register(MakeContext); - registry->Register(CompileFunction); registry->Register(PropertyQueryCallback); registry->Register(PropertyGetterCallback); registry->Register(PropertySetterCallback); @@ -977,7 +971,7 @@ ContextifyScript* ContextifyScript::New(Environment* env, Local object) { DCHECK_NOT_NULL(env->isolate()->GetCppHeap()); return cppgc::MakeGarbageCollected( - env->isolate()->GetCppHeap()->GetAllocationHandle(), env, object); + env->cppgc_allocation_handle(), env, object); } void ContextifyScript::New(const FunctionCallbackInfo& args) { @@ -1111,6 +1105,13 @@ void ContextifyScript::New(const FunctionCallbackInfo& args) { return; } + if (args.This() + ->Set(env->context(), + env->source_url_string(), + v8_script->GetSourceURL()) + .IsNothing()) + return; + if (args.This() ->Set(env->context(), env->source_map_url_string(), @@ -1163,22 +1164,6 @@ Maybe StoreCodeCacheResult( return JustVoid(); } -// TODO(RaisinTen): Reuse in ContextifyContext::CompileFunction(). -MaybeLocal CompileFunction(Local context, - Local filename, - Local content, - LocalVector* parameters) { - ScriptOrigin script_origin(filename, 0, 0, true); - ScriptCompiler::Source script_source(content, script_origin); - - return ScriptCompiler::CompileFunction(context, - &script_source, - parameters->size(), - parameters->data(), - 0, - nullptr); -} - bool ContextifyScript::InstanceOf(Environment* env, const Local& value) { return !value.IsEmpty() && @@ -1392,7 +1377,19 @@ ContextifyScript::ContextifyScript(Environment* env, Local object) { ContextifyScript::~ContextifyScript() {} -void ContextifyContext::CompileFunction( +void ContextifyFunction::RegisterExternalReferences( + ExternalReferenceRegistry* registry) { + registry->Register(CompileFunction); +} + +void ContextifyFunction::CreatePerIsolateProperties( + IsolateData* isolate_data, Local target) { + Isolate* isolate = isolate_data->isolate(); + + SetMethod(isolate, target, "compileFunction", CompileFunction); +} + +void ContextifyFunction::CompileFunction( const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); Isolate* isolate = env->isolate(); @@ -1511,24 +1508,22 @@ void ContextifyContext::CompileFunction( } TryCatchScope try_catch(env); - Local result = CompileFunctionAndCacheResult(env, - parsing_context, - &source, - params, - context_extensions, - options, - produce_cached_data, - id_symbol, - try_catch); - - if (try_catch.HasCaught() && !try_catch.HasTerminated()) { + MaybeLocal maybe_result = + CompileFunctionAndCacheResult(env, + parsing_context, + &source, + params, + context_extensions, + options, + produce_cached_data, + id_symbol, + try_catch); + Local result; + if (!maybe_result.ToLocal(&result)) { + CHECK(try_catch.HasCaught()); try_catch.ReThrow(); return; } - - if (result.IsEmpty()) { - return; - } args.GetReturnValue().Set(result); } @@ -1544,7 +1539,7 @@ static LocalVector GetCJSParameters(IsolateData* data) { return result; } -Local ContextifyContext::CompileFunctionAndCacheResult( +MaybeLocal ContextifyFunction::CompileFunctionAndCacheResult( Environment* env, Local parsing_context, ScriptCompiler::Source* source, @@ -1566,28 +1561,40 @@ Local ContextifyContext::CompileFunctionAndCacheResult( Local fn; if (!maybe_fn.ToLocal(&fn)) { - if (try_catch.HasCaught() && !try_catch.HasTerminated()) { + CHECK(try_catch.HasCaught()); + if (!try_catch.HasTerminated()) { errors::DecorateErrorStack(env, try_catch); - return Object::New(env->isolate()); } + return {}; } Local context = env->context(); if (fn->SetPrivate(context, env->host_defined_option_symbol(), id_symbol) .IsNothing()) { - return Object::New(env->isolate()); + return {}; } Isolate* isolate = env->isolate(); Local result = Object::New(isolate); if (result->Set(parsing_context, env->function_string(), fn).IsNothing()) - return Object::New(env->isolate()); + return {}; + + // ScriptOrigin::ResourceName() returns SourceURL magic comment content if + // present. + if (result + ->Set(parsing_context, + env->source_url_string(), + fn->GetScriptOrigin().ResourceName()) + .IsNothing()) { + return {}; + } if (result ->Set(parsing_context, env->source_map_url_string(), fn->GetScriptOrigin().SourceMapUrl()) - .IsNothing()) - return Object::New(env->isolate()); + .IsNothing()) { + return {}; + } std::unique_ptr new_cached_data; if (produce_cached_data) { @@ -1600,7 +1607,7 @@ Local ContextifyContext::CompileFunctionAndCacheResult( produce_cached_data, std::move(new_cached_data)) .IsNothing()) { - return Object::New(env->isolate()); + return {}; } return result; @@ -1825,12 +1832,16 @@ static void CompileFunctionForCJSLoader( Local names[] = { env->cached_data_rejected_string(), env->source_map_url_string(), + env->source_url_string(), env->function_string(), FIXED_ONE_BYTE_STRING(isolate, "canParseAsESM"), }; Local values[] = { Boolean::New(isolate, cache_rejected), fn.IsEmpty() ? undefined : fn->GetScriptOrigin().SourceMapUrl(), + // ScriptOrigin::ResourceName() returns SourceURL magic comment content if + // present. + fn.IsEmpty() ? undefined : fn->GetScriptOrigin().ResourceName(), fn.IsEmpty() ? undefined : fn.As(), Boolean::New(isolate, can_parse_as_esm), }; @@ -1974,6 +1985,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data, ContextifyContext::CreatePerIsolateProperties(isolate_data, target); ContextifyScript::CreatePerIsolateProperties(isolate_data, target); + ContextifyFunction::CreatePerIsolateProperties(isolate_data, target); SetMethod(isolate, target, "startSigintWatchdog", StartSigintWatchdog); SetMethod(isolate, target, "stopSigintWatchdog", StopSigintWatchdog); @@ -2026,6 +2038,7 @@ static void CreatePerContextProperties(Local target, void RegisterExternalReferences(ExternalReferenceRegistry* registry) { ContextifyContext::RegisterExternalReferences(registry); ContextifyScript::RegisterExternalReferences(registry); + ContextifyFunction::RegisterExternalReferences(registry); registry->Register(CompileFunctionForCJSLoader); registry->Register(StartSigintWatchdog); diff --git a/src/node_contextify.h b/src/node_contextify.h index ba964811bb6740..1066633daf65d4 100644 --- a/src/node_contextify.h +++ b/src/node_contextify.h @@ -4,7 +4,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "base_object-inl.h" -#include "cppgc_helpers.h" +#include "cppgc_helpers-inl.h" #include "node_context_data.h" #include "node_errors.h" @@ -77,6 +77,7 @@ class ContextifyContext final : CPPGC_MIXIN(ContextifyContext) { public: SET_CPPGC_NAME(ContextifyContext) void Trace(cppgc::Visitor* visitor) const final; + SET_NO_MEMORY_INFO() ContextifyContext(Environment* env, v8::Local wrapper, @@ -143,18 +144,6 @@ class ContextifyContext final : CPPGC_MIXIN(ContextifyContext) { static bool IsStillInitializing(const ContextifyContext* ctx); static void MakeContext(const v8::FunctionCallbackInfo& args); static void IsContext(const v8::FunctionCallbackInfo& args); - static void CompileFunction( - const v8::FunctionCallbackInfo& args); - static v8::Local CompileFunctionAndCacheResult( - Environment* env, - v8::Local parsing_context, - v8::ScriptCompiler::Source* source, - v8::LocalVector params, - v8::LocalVector context_extensions, - v8::ScriptCompiler::CompileOptions options, - bool produce_cached_data, - v8::Local id_symbol, - const errors::TryCatchScope& try_catch); static v8::Intercepted PropertyQueryCallback( v8::Local property, const v8::PropertyCallbackInfo& args); @@ -204,6 +193,7 @@ class ContextifyScript final : CPPGC_MIXIN(ContextifyScript) { public: SET_CPPGC_NAME(ContextifyScript) void Trace(cppgc::Visitor* visitor) const final; + SET_NO_MEMORY_INFO() ContextifyScript(Environment* env, v8::Local object); ~ContextifyScript() override; @@ -232,6 +222,29 @@ class ContextifyScript final : CPPGC_MIXIN(ContextifyScript) { v8::TracedReference script_; }; +class ContextifyFunction final { + public: + static void RegisterExternalReferences(ExternalReferenceRegistry* registry); + static void CreatePerIsolateProperties(IsolateData* isolate_data, + v8::Local target); + + static void CompileFunction(const v8::FunctionCallbackInfo& args); + static v8::MaybeLocal CompileFunctionAndCacheResult( + Environment* env, + v8::Local parsing_context, + v8::ScriptCompiler::Source* source, + v8::LocalVector params, + v8::LocalVector context_extensions, + v8::ScriptCompiler::CompileOptions options, + bool produce_cached_data, + v8::Local id_symbol, + const errors::TryCatchScope& try_catch); + + private: + ContextifyFunction() = delete; + ~ContextifyFunction() = delete; +}; + v8::Maybe StoreCodeCacheResult( Environment* env, v8::Local target, @@ -240,12 +253,6 @@ v8::Maybe StoreCodeCacheResult( bool produce_cached_data, std::unique_ptr new_cached_data); -v8::MaybeLocal CompileFunction( - v8::Local context, - v8::Local filename, - v8::Local content, - v8::LocalVector* parameters); - } // namespace contextify } // namespace node diff --git a/src/node_dotenv.cc b/src/node_dotenv.cc index d5f14fa92e2694..3bdeaab1a9cb23 100644 --- a/src/node_dotenv.cc +++ b/src/node_dotenv.cc @@ -65,18 +65,19 @@ std::vector Dotenv::GetDataFromArgs( } Maybe Dotenv::SetEnvironment(node::Environment* env) { - Local name; - Local val; auto context = env->context(); + auto env_vars = env->env_vars(); for (const auto& entry : store_) { - auto existing = env->env_vars()->Get(entry.first.data()); + auto existing = env_vars->Get(entry.first.data()); if (!existing.has_value()) { + Local name; + Local val; if (!ToV8Value(context, entry.first).ToLocal(&name) || !ToV8Value(context, entry.second).ToLocal(&val)) { return Nothing(); } - env->env_vars()->Set(env->isolate(), name.As(), val.As()); + env_vars->Set(env->isolate(), name.As(), val.As()); } } diff --git a/src/node_errors.h b/src/node_errors.h index 4d7132a9954505..48a9b59c418d12 100644 --- a/src/node_errors.h +++ b/src/node_errors.h @@ -78,7 +78,9 @@ void OOMErrorHandler(const char* location, const v8::OOMDetails& details); V(ERR_FS_CP_EINVAL, Error) \ V(ERR_FS_CP_DIR_TO_NON_DIR, Error) \ V(ERR_FS_CP_NON_DIR_TO_DIR, Error) \ + V(ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY, Error) \ V(ERR_FS_EISDIR, Error) \ + V(ERR_FS_CP_EEXIST, Error) \ V(ERR_FS_CP_SOCKET, Error) \ V(ERR_FS_CP_FIFO_PIPE, Error) \ V(ERR_FS_CP_UNKNOWN, Error) \ diff --git a/src/node_file.cc b/src/node_file.cc index 56b7a94ecdfe42..e4ccedc2624fac 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -43,6 +43,9 @@ #include "uv.h" #include "v8-fast-api-calls.h" +#include +#include +#include #include #if defined(__MINGW32__) || defined(_MSC_VER) @@ -63,7 +66,6 @@ using v8::Array; using v8::BigInt; using v8::Context; using v8::EscapableHandleScope; -using v8::FastApiCallbackOptions; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; @@ -1072,32 +1074,6 @@ static void InternalModuleStat(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(rc); } -static int32_t FastInternalModuleStat( - Local recv, - Local input_, - // NOLINTNEXTLINE(runtime/references) This is V8 api. - FastApiCallbackOptions& options) { - TRACK_V8_FAST_API_CALL("fs.internalModuleStat"); - HandleScope scope(options.isolate); - - CHECK(input_->IsString()); - Utf8Value input(options.isolate, input_.As()); - - auto path = std::filesystem::path(input.ToStringView()); - - switch (std::filesystem::status(path).type()) { - case std::filesystem::file_type::directory: - return 1; - case std::filesystem::file_type::regular: - return 0; - default: - return -1; - } -} - -v8::CFunction fast_internal_module_stat_( - v8::CFunction::Make(FastInternalModuleStat)); - constexpr bool is_uv_error_except_no_entry(int result) { return result < 0 && result != UV_ENOENT; } @@ -3350,6 +3326,289 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo& args) { } } +static void CpSyncOverrideFile(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + Isolate* isolate = env->isolate(); + + CHECK_EQ(args.Length(), 4); // src, dest, mode, preserveTimestamps + + BufferValue src(isolate, args[0]); + CHECK_NOT_NULL(*src); + ToNamespacedPath(env, &src); + + BufferValue dest(isolate, args[1]); + CHECK_NOT_NULL(*dest); + ToNamespacedPath(env, &dest); + + int mode; + if (!GetValidFileMode(env, args[2], UV_FS_COPYFILE).To(&mode)) { + return; + } + + bool preserve_timestamps = args[3]->IsTrue(); + + THROW_IF_INSUFFICIENT_PERMISSIONS( + env, permission::PermissionScope::kFileSystemRead, src.ToStringView()); + THROW_IF_INSUFFICIENT_PERMISSIONS( + env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView()); + + std::error_code error; + + if (!std::filesystem::remove(*dest, error)) { + return env->ThrowStdErrException(error, "unlink", *dest); + } + + if (mode == 0) { + // if no mode is specified use the faster std::filesystem API + if (!std::filesystem::copy_file(*src, *dest, error)) { + return env->ThrowStdErrException(error, "cp", *dest); + } + } else { + uv_fs_t req; + auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); }); + auto result = uv_fs_copyfile(nullptr, &req, *src, *dest, mode, nullptr); + if (is_uv_error(result)) { + return env->ThrowUVException(result, "cp", nullptr, *src, *dest); + } + } + + if (preserve_timestamps) { + uv_fs_t req; + auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); }); + int result = uv_fs_stat(nullptr, &req, *src, nullptr); + if (is_uv_error(result)) { + return env->ThrowUVException(result, "stat", nullptr, *src); + } + + const uv_stat_t* const s = static_cast(req.ptr); + const double source_atime = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; + const double source_mtime = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; + + int utime_result = + uv_fs_utime(nullptr, &req, *dest, source_atime, source_mtime, nullptr); + if (is_uv_error(utime_result)) { + return env->ThrowUVException(utime_result, "utime", nullptr, *dest); + } + } +} + +std::vector normalizePathToArray( + const std::filesystem::path& path) { + std::vector parts; + std::filesystem::path absPath = std::filesystem::absolute(path); + for (const auto& part : absPath) { + if (!part.empty()) parts.push_back(part.string()); + } + return parts; +} + +bool isInsideDir(const std::filesystem::path& src, + const std::filesystem::path& dest) { + auto srcArr = normalizePathToArray(src); + auto destArr = normalizePathToArray(dest); + if (srcArr.size() > destArr.size()) return false; + return std::equal(srcArr.begin(), srcArr.end(), destArr.begin()); +} + +static void CpSyncCopyDir(const FunctionCallbackInfo& args) { + CHECK_EQ(args.Length(), 7); // src, dest, force, dereference, errorOnExist, + // verbatimSymlinks, preserveTimestamps + + Environment* env = Environment::GetCurrent(args); + Isolate* isolate = env->isolate(); + + BufferValue src(isolate, args[0]); + CHECK_NOT_NULL(*src); + ToNamespacedPath(env, &src); + + BufferValue dest(isolate, args[1]); + CHECK_NOT_NULL(*dest); + ToNamespacedPath(env, &dest); + + bool force = args[2]->IsTrue(); + bool dereference = args[3]->IsTrue(); + bool error_on_exist = args[4]->IsTrue(); + bool verbatim_symlinks = args[5]->IsTrue(); + bool preserve_timestamps = args[6]->IsTrue(); + + std::error_code error; + std::filesystem::create_directories(*dest, error); + if (error) { + return env->ThrowStdErrException(error, "cp", *dest); + } + + auto file_copy_opts = std::filesystem::copy_options::recursive; + if (force) { + file_copy_opts |= std::filesystem::copy_options::overwrite_existing; + } else if (error_on_exist) { + file_copy_opts |= std::filesystem::copy_options::none; + } else { + file_copy_opts |= std::filesystem::copy_options::skip_existing; + } + + std::function + copy_dir_contents; + copy_dir_contents = [verbatim_symlinks, + ©_dir_contents, + &env, + file_copy_opts, + preserve_timestamps, + force, + error_on_exist, + dereference, + &isolate](std::filesystem::path src, + std::filesystem::path dest) { + std::error_code error; + for (auto dir_entry : std::filesystem::directory_iterator(src)) { + auto dest_file_path = dest / dir_entry.path().filename(); + auto dest_str = PathToString(dest); + + if (dir_entry.is_symlink()) { + if (verbatim_symlinks) { + std::filesystem::copy_symlink( + dir_entry.path(), dest_file_path, error); + if (error) { + env->ThrowStdErrException(error, "cp", dest_str.c_str()); + return false; + } + } else { + auto symlink_target = + std::filesystem::read_symlink(dir_entry.path().c_str(), error); + if (error) { + env->ThrowStdErrException(error, "cp", dest_str.c_str()); + return false; + } + + if (std::filesystem::exists(dest_file_path)) { + if (std::filesystem::is_symlink((dest_file_path.c_str()))) { + auto current_dest_symlink_target = + std::filesystem::read_symlink(dest_file_path.c_str(), error); + if (error) { + env->ThrowStdErrException(error, "cp", dest_str.c_str()); + return false; + } + + if (!dereference && + std::filesystem::is_directory(symlink_target) && + isInsideDir(symlink_target, current_dest_symlink_target)) { + std::string message = + "Cannot copy %s to a subdirectory of self %s"; + THROW_ERR_FS_CP_EINVAL(env, + message.c_str(), + symlink_target.c_str(), + current_dest_symlink_target.c_str()); + return false; + } + + // Prevent copy if src is a subdir of dest since unlinking + // dest in this case would result in removing src contents + // and therefore a broken symlink would be created. + if (std::filesystem::is_directory(dest_file_path) && + isInsideDir(current_dest_symlink_target, symlink_target)) { + std::string message = "cannot overwrite %s with %s"; + THROW_ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY( + env, + message.c_str(), + current_dest_symlink_target.c_str(), + symlink_target.c_str()); + return false; + } + + // symlinks get overridden by cp even if force: false, this is + // being applied here for backward compatibility, but is it + // correct? or is it a bug? + std::filesystem::remove(dest_file_path, error); + if (error) { + env->ThrowStdErrException(error, "cp", dest_str.c_str()); + return false; + } + } else if (std::filesystem::is_regular_file(dest_file_path)) { + if (!dereference || (!force && error_on_exist)) { + auto dest_file_path_str = PathToString(dest_file_path); + env->ThrowStdErrException( + std::make_error_code(std::errc::file_exists), + "cp", + dest_file_path_str.c_str()); + return false; + } + } + } + auto symlink_target_absolute = std::filesystem::weakly_canonical( + std::filesystem::absolute(src / symlink_target)); + if (dir_entry.is_directory()) { + std::filesystem::create_directory_symlink( + symlink_target_absolute, dest_file_path, error); + } else { + std::filesystem::create_symlink( + symlink_target_absolute, dest_file_path, error); + } + if (error) { + env->ThrowStdErrException(error, "cp", dest_str.c_str()); + return false; + } + } + } else if (dir_entry.is_directory()) { + auto entry_dir_path = src / dir_entry.path().filename(); + std::filesystem::create_directory(dest_file_path); + auto success = copy_dir_contents(entry_dir_path, dest_file_path); + if (!success) { + return false; + } + } else if (dir_entry.is_regular_file()) { + std::filesystem::copy_file( + dir_entry.path(), dest_file_path, file_copy_opts, error); + if (error) { + if (error.value() == EEXIST) { + THROW_ERR_FS_CP_EEXIST(isolate, + "[ERR_FS_CP_EEXIST]: Target already exists: " + "cp returned EEXIST (%s already exists)", + dest_file_path.c_str()); + return false; + } + env->ThrowStdErrException(error, "cp", dest_str.c_str()); + return false; + } + + if (preserve_timestamps) { + uv_fs_t req; + auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); }); + + auto dir_entry_path_str = PathToString(dir_entry.path()); + int result = + uv_fs_stat(nullptr, &req, dir_entry_path_str.c_str(), nullptr); + if (is_uv_error(result)) { + env->ThrowUVException( + result, "stat", nullptr, dir_entry_path_str.c_str()); + return false; + } + + const uv_stat_t* const s = static_cast(req.ptr); + const double source_atime = + s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; + const double source_mtime = + s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; + + auto dest_file_path_str = PathToString(dest_file_path); + int utime_result = uv_fs_utime(nullptr, + &req, + dest_file_path_str.c_str(), + source_atime, + source_mtime, + nullptr); + if (is_uv_error(utime_result)) { + env->ThrowUVException( + utime_result, "utime", nullptr, dest_file_path_str.c_str()); + return false; + } + } + } + } + return true; + }; + + copy_dir_contents(std::filesystem::path(*src), std::filesystem::path(*dest)); +} + BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile( Environment* env, const std::string& file_path) { THROW_IF_INSUFFICIENT_PERMISSIONS( @@ -3655,11 +3914,7 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data, SetMethod(isolate, target, "rmSync", RmSync); SetMethod(isolate, target, "mkdir", MKDir); SetMethod(isolate, target, "readdir", ReadDir); - SetFastMethod(isolate, - target, - "internalModuleStat", - InternalModuleStat, - &fast_internal_module_stat_); + SetMethod(isolate, target, "internalModuleStat", InternalModuleStat); SetMethod(isolate, target, "stat", Stat); SetMethod(isolate, target, "lstat", LStat); SetMethod(isolate, target, "fstat", FStat); @@ -3689,6 +3944,8 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data, SetMethod(isolate, target, "mkdtemp", Mkdtemp); SetMethod(isolate, target, "cpSyncCheckPaths", CpSyncCheckPaths); + SetMethod(isolate, target, "cpSyncOverrideFile", CpSyncOverrideFile); + SetMethod(isolate, target, "cpSyncCopyDir", CpSyncCopyDir); StatWatcher::CreatePerIsolateProperties(isolate_data, target); BindingData::CreatePerIsolateProperties(isolate_data, target); @@ -3783,8 +4040,6 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(MKDir); registry->Register(ReadDir); registry->Register(InternalModuleStat); - registry->Register(FastInternalModuleStat); - registry->Register(fast_internal_module_stat_.GetTypeInfo()); registry->Register(Stat); registry->Register(LStat); registry->Register(FStat); @@ -3801,6 +4056,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(CopyFile); registry->Register(CpSyncCheckPaths); + registry->Register(CpSyncOverrideFile); + registry->Register(CpSyncCopyDir); registry->Register(Chmod); registry->Register(FChmod); diff --git a/src/node_http2.cc b/src/node_http2.cc index 4415ea096d0ea0..8e51129930f2cd 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -159,6 +159,12 @@ Http2Options::Http2Options(Http2State* http2_state, SessionType type) { buffer[IDX_OPTIONS_PEER_MAX_CONCURRENT_STREAMS]); } + // Validate headers in accordance to RFC-9113 + if (flags & (1 << IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION)) { + nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation( + option, buffer[IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION]); + } + // The padding strategy sets the mechanism by which we determine how much // additional frame padding to apply to DATA and HEADERS frames. Currently // this is set on a per-session basis, but eventually we may switch to @@ -2104,7 +2110,10 @@ void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) { [[likely]] { // Shrink to the actual amount of used data. std::unique_ptr old_bs = std::move(bs); - bs = ArrayBuffer::NewBackingStore(env()->isolate(), nread); + bs = ArrayBuffer::NewBackingStore( + env()->isolate(), + nread, + BackingStoreInitializationMode::kUninitialized); memcpy(bs->Data(), old_bs->Data(), nread); } else { // This is a very unlikely case, and should only happen if the ReadStart() diff --git a/src/node_http2_state.h b/src/node_http2_state.h index 2957a2827f370e..914ad011e021f1 100644 --- a/src/node_http2_state.h +++ b/src/node_http2_state.h @@ -60,6 +60,7 @@ namespace http2 { IDX_OPTIONS_MAX_SETTINGS, IDX_OPTIONS_STREAM_RESET_RATE, IDX_OPTIONS_STREAM_RESET_BURST, + IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION, IDX_OPTIONS_FLAGS }; diff --git a/src/node_i18n.cc b/src/node_i18n.cc index 9f3ae18dcfe2b4..9e4628f0e3bc06 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -174,7 +174,7 @@ MaybeLocal TranscodeLatin1ToUcs2(Environment* env, const char* source, const size_t source_length, UErrorCode* status) { - MaybeStackBuffer destbuf(source_length); + MaybeStackBuffer destbuf(source_length); auto actual_length = simdutf::convert_latin1_to_utf16le(source, source_length, destbuf.out()); if (actual_length == 0) { @@ -218,7 +218,7 @@ MaybeLocal TranscodeUcs2FromUtf8(Environment* env, UErrorCode* status) { size_t expected_utf16_length = simdutf::utf16_length_from_utf8(source, source_length); - MaybeStackBuffer destbuf(expected_utf16_length); + MaybeStackBuffer destbuf(expected_utf16_length); auto actual_length = simdutf::convert_utf8_to_utf16le(source, source_length, destbuf.out()); diff --git a/src/node_options-inl.h b/src/node_options-inl.h index 55078af457fc7c..877e8ce4ded92b 100644 --- a/src/node_options-inl.h +++ b/src/node_options-inl.h @@ -31,98 +31,128 @@ namespace options_parser { template void OptionsParser::AddOption(const char* name, const char* help_text, - bool Options::* field, + bool Options::*field, OptionEnvvarSettings env_setting, - bool default_is_true) { + bool default_is_true, + OptionNamespaces namespace_id) { options_.emplace(name, OptionInfo{kBoolean, std::make_shared>(field), env_setting, help_text, - default_is_true}); + default_is_true, + NamespaceEnumToString(namespace_id)}); } template void OptionsParser::AddOption(const char* name, const char* help_text, - uint64_t Options::* field, - OptionEnvvarSettings env_setting) { + uint64_t Options::*field, + OptionEnvvarSettings env_setting, + OptionNamespaces namespace_id) { options_.emplace( name, OptionInfo{kUInteger, std::make_shared>(field), env_setting, - help_text}); + help_text, + false, + NamespaceEnumToString(namespace_id)}); } template void OptionsParser::AddOption(const char* name, const char* help_text, - int64_t Options::* field, - OptionEnvvarSettings env_setting) { + int64_t Options::*field, + OptionEnvvarSettings env_setting, + OptionNamespaces namespace_id) { options_.emplace( name, OptionInfo{kInteger, std::make_shared>(field), env_setting, - help_text}); + help_text, + false, + NamespaceEnumToString(namespace_id)}); } template void OptionsParser::AddOption(const char* name, const char* help_text, - std::string Options::* field, - OptionEnvvarSettings env_setting) { + std::string Options::*field, + OptionEnvvarSettings env_setting, + OptionNamespaces namespace_id) { options_.emplace( name, OptionInfo{kString, std::make_shared>(field), env_setting, - help_text}); + help_text, + false, + NamespaceEnumToString(namespace_id)}); } template -void OptionsParser::AddOption( - const char* name, - const char* help_text, - std::vector Options::* field, - OptionEnvvarSettings env_setting) { - options_.emplace(name, OptionInfo { - kStringList, - std::make_shared>>(field), - env_setting, - help_text - }); +void OptionsParser::AddOption(const char* name, + const char* help_text, + std::vector Options::*field, + OptionEnvvarSettings env_setting, + OptionNamespaces namespace_id) { + options_.emplace( + name, + OptionInfo{ + kStringList, + std::make_shared>>(field), + env_setting, + help_text, + false, + NamespaceEnumToString(namespace_id)}); } template void OptionsParser::AddOption(const char* name, const char* help_text, - HostPort Options::* field, - OptionEnvvarSettings env_setting) { + HostPort Options::*field, + OptionEnvvarSettings env_setting, + OptionNamespaces namespace_id) { options_.emplace( name, OptionInfo{kHostPort, std::make_shared>(field), env_setting, - help_text}); + help_text, + false, + NamespaceEnumToString(namespace_id)}); } template void OptionsParser::AddOption(const char* name, const char* help_text, NoOp no_op_tag, - OptionEnvvarSettings env_setting) { - options_.emplace(name, OptionInfo{kNoOp, nullptr, env_setting, help_text}); + OptionEnvvarSettings env_setting, + OptionNamespaces namespace_id) { + options_.emplace(name, + OptionInfo{kNoOp, + nullptr, + env_setting, + help_text, + false, + NamespaceEnumToString(namespace_id)}); } template void OptionsParser::AddOption(const char* name, const char* help_text, V8Option v8_option_tag, - OptionEnvvarSettings env_setting) { + OptionEnvvarSettings env_setting, + OptionNamespaces namespace_id) { options_.emplace(name, - OptionInfo{kV8Option, nullptr, env_setting, help_text}); + OptionInfo{kV8Option, + nullptr, + env_setting, + help_text, + false, + NamespaceEnumToString(namespace_id)}); } template @@ -198,7 +228,8 @@ auto OptionsParser::Convert( Convert(original.field, get_child), original.env_setting, original.help_text, - original.default_is_true}; + original.default_is_true, + original.namespace_id}; } template diff --git a/src/node_options.cc b/src/node_options.cc index 1d222fa14f780f..5adbcfd26eb04c 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -17,6 +17,7 @@ #include #include #include +#include using v8::Boolean; using v8::Context; @@ -81,6 +82,8 @@ void PerProcessOptions::CheckOptions(std::vector* errors, } // Any value less than 2 disables use of the secure heap. +#ifndef V8_ENABLE_SANDBOX + // The secure heap is not supported when V8_ENABLE_SANDBOX is enabled. if (secure_heap >= 2) { if ((secure_heap & (secure_heap - 1)) != 0) errors->push_back("--secure-heap must be a power of 2"); @@ -93,6 +96,7 @@ void PerProcessOptions::CheckOptions(std::vector* errors, if ((secure_heap_min & (secure_heap_min - 1)) != 0) errors->push_back("--secure-heap-min must be a power of 2"); } +#endif // V8_ENABLE_SANDBOX #endif // HAVE_OPENSSL if (use_largepages != "off" && @@ -241,6 +245,64 @@ void EnvironmentOptions::CheckOptions(std::vector* errors, namespace options_parser { +// Helper function to convert option types to their string representation +// and add them to a V8 Map +static bool AddOptionTypeToMap(Isolate* isolate, + Local context, + Local map, + const std::string& option_name, + const OptionType& option_type) { + std::string type; + switch (static_cast(option_type)) { + case 0: // No-op + case 1: // V8 flags + break; // V8 and NoOp flags are not supported + + case 2: + type = "boolean"; + break; + case 3: // integer + case 4: // unsigned integer + case 6: // host port + type = "number"; + break; + case 5: // string + type = "string"; + break; + case 7: // string array + type = "array"; + break; + default: + UNREACHABLE(); + } + + if (type.empty()) { + return true; // Skip this entry but continue processing + } + + Local option_key; + if (!String::NewFromUtf8(isolate, + option_name.data(), + v8::NewStringType::kNormal, + option_name.size()) + .ToLocal(&option_key)) { + return true; // Skip this entry but continue processing + } + + Local type_value; + if (!String::NewFromUtf8( + isolate, type.data(), v8::NewStringType::kNormal, type.size()) + .ToLocal(&type_value)) { + return true; // Skip this entry but continue processing + } + + if (map->Set(context, option_key, type_value).IsEmpty()) { + return false; // Error occurred, stop processing + } + + return true; +} + class DebugOptionsParser : public OptionsParser { public: DebugOptionsParser(); @@ -694,82 +756,119 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { &EnvironmentOptions::experimental_default_config_file); AddOption("--test", "launch test runner on startup", - &EnvironmentOptions::test_runner); + &EnvironmentOptions::test_runner, + kDisallowedInEnvvar); AddOption("--test-concurrency", "specify test runner concurrency", - &EnvironmentOptions::test_runner_concurrency); + &EnvironmentOptions::test_runner_concurrency, + kDisallowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-force-exit", "force test runner to exit upon completion", - &EnvironmentOptions::test_runner_force_exit); + &EnvironmentOptions::test_runner_force_exit, + kDisallowedInEnvvar, + false, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-timeout", "specify test runner timeout", - &EnvironmentOptions::test_runner_timeout); + &EnvironmentOptions::test_runner_timeout, + kDisallowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-update-snapshots", "regenerate test snapshots", - &EnvironmentOptions::test_runner_update_snapshots); + &EnvironmentOptions::test_runner_update_snapshots, + kDisallowedInEnvvar, + false, + OptionNamespaces::kTestRunnerNamespace); AddOption("--experimental-test-coverage", "enable code coverage in the test runner", - &EnvironmentOptions::test_runner_coverage); + &EnvironmentOptions::test_runner_coverage, + kDisallowedInEnvvar, + false, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-coverage-branches", "the branch coverage minimum threshold", &EnvironmentOptions::test_coverage_branches, - kAllowedInEnvvar); + kAllowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-coverage-functions", "the function coverage minimum threshold", &EnvironmentOptions::test_coverage_functions, - kAllowedInEnvvar); + kAllowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-coverage-lines", "the line coverage minimum threshold", &EnvironmentOptions::test_coverage_lines, - kAllowedInEnvvar); + kAllowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-isolation", "configures the type of test isolation used in the test runner", &EnvironmentOptions::test_isolation, - kAllowedInEnvvar); + kAllowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); // TODO(cjihrig): Remove this alias in a semver major. AddAlias("--experimental-test-isolation", "--test-isolation"); AddOption("--experimental-test-module-mocks", "enable module mocking in the test runner", - &EnvironmentOptions::test_runner_module_mocks); - AddOption("--experimental-test-snapshots", "", NoOp{}); + &EnvironmentOptions::test_runner_module_mocks, + kDisallowedInEnvvar, + false, + OptionNamespaces::kTestRunnerNamespace); + AddOption("--experimental-test-snapshots", + "", + NoOp{}, + kDisallowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-name-pattern", "run tests whose name matches this regular expression", &EnvironmentOptions::test_name_pattern, - kAllowedInEnvvar); + kAllowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-reporter", "report test output using the given reporter", &EnvironmentOptions::test_reporter, - kAllowedInEnvvar); + kAllowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-reporter-destination", "report given reporter to the given destination", &EnvironmentOptions::test_reporter_destination, - kAllowedInEnvvar); + kAllowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-only", "run tests with 'only' option set", &EnvironmentOptions::test_only, - kAllowedInEnvvar); + kAllowedInEnvvar, + false, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-shard", "run test at specific shard", &EnvironmentOptions::test_shard, - kAllowedInEnvvar); + kAllowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-skip-pattern", "run tests whose name do not match this regular expression", &EnvironmentOptions::test_skip_pattern, - kAllowedInEnvvar); + kAllowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-coverage-include", "include files in coverage report that match this glob pattern", &EnvironmentOptions::coverage_include_pattern, - kAllowedInEnvvar); + kAllowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-coverage-exclude", "exclude files from coverage report that match this glob pattern", &EnvironmentOptions::coverage_exclude_pattern, - kAllowedInEnvvar); + kAllowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); AddOption("--test-global-setup", "specifies the path to the global setup file", &EnvironmentOptions::test_global_setup_path, - kAllowedInEnvvar); - AddOption("--test-udp-no-try-send", "", // For testing only. - &EnvironmentOptions::test_udp_no_try_send); + kAllowedInEnvvar, + OptionNamespaces::kTestRunnerNamespace); + AddOption("--test-udp-no-try-send", + "", // For testing only. + &EnvironmentOptions::test_udp_no_try_send, + kDisallowedInEnvvar); AddOption("--throw-deprecation", "throw an exception on deprecations", &EnvironmentOptions::throw_deprecation, @@ -1173,6 +1272,7 @@ PerProcessOptionsParser::PerProcessOptionsParser( "force FIPS crypto (cannot be disabled)", &PerProcessOptions::force_fips_crypto, kAllowedInEnvvar); +#ifndef V8_ENABLE_SANDBOX AddOption("--secure-heap", "total size of the OpenSSL secure heap", &PerProcessOptions::secure_heap, @@ -1181,6 +1281,7 @@ PerProcessOptionsParser::PerProcessOptionsParser( "minimum allocation size from the OpenSSL secure heap", &PerProcessOptions::secure_heap_min, kAllowedInEnvvar); +#endif // V8_ENABLE_SANDBOX #endif // HAVE_OPENSSL #if OPENSSL_VERSION_MAJOR >= 3 AddOption("--openssl-legacy-provider", @@ -1327,6 +1428,49 @@ MapEnvOptionsFlagInputType() { return type_map; } +std::vector MapAvailableNamespaces() { + std::vector namespaceNames; + auto availableNamespaces = AllNamespaces(); + for (size_t i = 1; i < availableNamespaces.size(); i++) { + OptionNamespaces ns = availableNamespaces[i]; + std::string ns_string = NamespaceEnumToString(ns); + if (!ns_string.empty()) { + namespaceNames.push_back(ns_string); + } + } + + return namespaceNames; +} + +std::unordered_map +MapOptionsByNamespace(std::string namespace_name) { + std::unordered_map type_map; + const auto& parser = _ppop_instance; + for (const auto& item : parser.options_) { + if (!item.first.empty() && !item.first.starts_with('[') && + item.second.namespace_id == namespace_name) { + type_map[item.first] = item.second.type; + } + } + return type_map; +} + +std::unordered_map> +MapNamespaceOptionsAssociations() { + std::vector available_namespaces = + options_parser::MapAvailableNamespaces(); + std::unordered_map< + std::string, + std::unordered_map> + namespace_option_mapping; + for (const std::string& available_namespace : available_namespaces) { + namespace_option_mapping[available_namespace] = + options_parser::MapOptionsByNamespace(available_namespace); + } + return namespace_option_mapping; +} + struct IterateCLIOptionsScope { explicit IterateCLIOptionsScope(Environment* env) { // Temporarily act as if the current Environment's/IsolateData's options @@ -1594,56 +1738,71 @@ void GetEnvOptionsInputType(const FunctionCallbackInfo& args) { for (const auto& item : _ppop_instance.options_) { if (!item.first.empty() && !item.first.starts_with('[') && item.second.env_setting == kAllowedInEnvvar) { - std::string type; - switch (static_cast(item.second.type)) { - case 0: // No-op - case 1: // V8 flags - break; // V8 and NoOp flags are not supported - - case 2: - type = "boolean"; - break; - case 3: // integer - case 4: // unsigned integer - case 6: // host port - type = "number"; - break; - case 5: // string - type = "string"; - break; - case 7: // string array - type = "array"; - break; - default: - UNREACHABLE(); + if (!AddOptionTypeToMap( + isolate, context, flags_map, item.first, item.second.type)) { + return; } + } + } + args.GetReturnValue().Set(flags_map); +} - if (type.empty()) { - continue; - } +// This function returns a two-level nested map containing all the available +// options grouped by their namespaces along with their input types. This is +// used for config file JSON schema generation +void GetNamespaceOptionsInputType(const FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + Local context = isolate->GetCurrentContext(); + Environment* env = Environment::GetCurrent(context); - Local value; - if (!String::NewFromUtf8( - isolate, type.data(), v8::NewStringType::kNormal, type.size()) - .ToLocal(&value)) { - continue; + if (!env->has_run_bootstrapping_code()) { + // No code because this is an assertion. + THROW_ERR_OPTIONS_BEFORE_BOOTSTRAPPING( + isolate, "Should not query options before bootstrapping is done"); + } + + Mutex::ScopedLock lock(per_process::cli_options_mutex); + + Local namespaces_map = Map::New(isolate); + + // Get the mapping of namespaces to their options and types + auto namespace_options = options_parser::MapNamespaceOptionsAssociations(); + + for (const auto& ns_entry : namespace_options) { + const std::string& namespace_name = ns_entry.first; + const auto& options_map = ns_entry.second; + + Local options_type_map = Map::New(isolate); + + for (const auto& opt_entry : options_map) { + const std::string& option_name = opt_entry.first; + const options_parser::OptionType& option_type = opt_entry.second; + + if (!AddOptionTypeToMap( + isolate, context, options_type_map, option_name, option_type)) { + return; } + } - Local field; + // Only add namespaces that have options + if (options_type_map->Size() > 0) { + Local namespace_key; if (!String::NewFromUtf8(isolate, - item.first.data(), + namespace_name.data(), v8::NewStringType::kNormal, - item.first.size()) - .ToLocal(&field)) { + namespace_name.size()) + .ToLocal(&namespace_key)) { continue; } - if (flags_map->Set(context, field, value).IsEmpty()) { + if (namespaces_map->Set(context, namespace_key, options_type_map) + .IsEmpty()) { return; } } } - args.GetReturnValue().Set(flags_map); + + args.GetReturnValue().Set(namespaces_map); } void Initialize(Local target, @@ -1660,6 +1819,10 @@ void Initialize(Local target, context, target, "getEmbedderOptions", GetEmbedderOptions); SetMethodNoSideEffect( context, target, "getEnvOptionsInputType", GetEnvOptionsInputType); + SetMethodNoSideEffect(context, + target, + "getNamespaceOptionsInputType", + GetNamespaceOptionsInputType); Local env_settings = Object::New(isolate); NODE_DEFINE_CONSTANT(env_settings, kAllowedInEnvvar); NODE_DEFINE_CONSTANT(env_settings, kDisallowedInEnvvar); @@ -1686,6 +1849,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(GetCLIOptionsInfo); registry->Register(GetEmbedderOptions); registry->Register(GetEnvOptionsInputType); + registry->Register(GetNamespaceOptionsInputType); } } // namespace options_parser diff --git a/src/node_options.h b/src/node_options.h index d0c73722c9a68a..b616249d18e1c4 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -380,7 +380,7 @@ class PerProcessOptions : public Options { namespace options_parser { HostPort SplitHostPort(const std::string& arg, - std::vector* errors); + std::vector* errors); void GetOptions(const v8::FunctionCallbackInfo& args); std::string GetBashCompletion(); @@ -395,6 +395,43 @@ enum OptionType { kStringList, }; std::unordered_map MapEnvOptionsFlagInputType(); +std::unordered_map MapOptionsByNamespace( + std::string namespace_name); +std::unordered_map> +MapNamespaceOptionsAssociations(); +std::vector MapAvailableNamespaces(); + +// Define all namespace entries +#define OPTION_NAMESPACE_LIST(V) \ + V(kNoNamespace, "") \ + V(kTestRunnerNamespace, "testRunner") + +enum class OptionNamespaces { +#define V(name, _) name, + OPTION_NAMESPACE_LIST(V) +#undef V +}; + +inline const std::string NamespaceEnumToString(OptionNamespaces ns) { + switch (ns) { +#define V(name, string_value) \ + case OptionNamespaces::name: \ + return string_value; + OPTION_NAMESPACE_LIST(V) +#undef V + default: + return ""; + } +} + +inline constexpr auto AllNamespaces() { + return std::array{ +#define V(name, _) OptionNamespaces::name, + OPTION_NAMESPACE_LIST(V) +#undef V + }; +} template class OptionsParser { @@ -413,39 +450,55 @@ class OptionsParser { // default_is_true is only a hint in printing help text, it does not // affect the default value of the option. Set the default value in the // Options struct instead. - void AddOption(const char* name, - const char* help_text, - bool Options::*field, - OptionEnvvarSettings env_setting = kDisallowedInEnvvar, - bool default_is_true = false); - void AddOption(const char* name, - const char* help_text, - uint64_t Options::*field, - OptionEnvvarSettings env_setting = kDisallowedInEnvvar); - void AddOption(const char* name, - const char* help_text, - int64_t Options::*field, - OptionEnvvarSettings env_setting = kDisallowedInEnvvar); - void AddOption(const char* name, - const char* help_text, - std::string Options::*field, - OptionEnvvarSettings env_setting = kDisallowedInEnvvar); - void AddOption(const char* name, - const char* help_text, - std::vector Options::*field, - OptionEnvvarSettings env_setting = kDisallowedInEnvvar); - void AddOption(const char* name, - const char* help_text, - HostPort Options::*field, - OptionEnvvarSettings env_setting = kDisallowedInEnvvar); - void AddOption(const char* name, - const char* help_text, - NoOp no_op_tag, - OptionEnvvarSettings env_setting = kDisallowedInEnvvar); - void AddOption(const char* name, - const char* help_text, - V8Option v8_option_tag, - OptionEnvvarSettings env_setting = kDisallowedInEnvvar); + void AddOption( + const char* name, + const char* help_text, + bool Options::*field, + OptionEnvvarSettings env_setting = kDisallowedInEnvvar, + bool default_is_true = false, + OptionNamespaces namespace_id = OptionNamespaces::kNoNamespace); + void AddOption( + const char* name, + const char* help_text, + uint64_t Options::*field, + OptionEnvvarSettings env_setting = kDisallowedInEnvvar, + OptionNamespaces namespace_id = OptionNamespaces::kNoNamespace); + void AddOption( + const char* name, + const char* help_text, + int64_t Options::*field, + OptionEnvvarSettings env_setting = kDisallowedInEnvvar, + OptionNamespaces namespace_id = OptionNamespaces::kNoNamespace); + void AddOption( + const char* name, + const char* help_text, + std::string Options::*field, + OptionEnvvarSettings env_setting = kDisallowedInEnvvar, + OptionNamespaces namespace_id = OptionNamespaces::kNoNamespace); + void AddOption( + const char* name, + const char* help_text, + std::vector Options::*field, + OptionEnvvarSettings env_setting = kDisallowedInEnvvar, + OptionNamespaces namespace_id = OptionNamespaces::kNoNamespace); + void AddOption( + const char* name, + const char* help_text, + HostPort Options::*field, + OptionEnvvarSettings env_setting = kDisallowedInEnvvar, + OptionNamespaces namespace_id = OptionNamespaces::kNoNamespace); + void AddOption( + const char* name, + const char* help_text, + NoOp no_op_tag, + OptionEnvvarSettings env_setting = kDisallowedInEnvvar, + OptionNamespaces namespace_id = OptionNamespaces::kNoNamespace); + void AddOption( + const char* name, + const char* help_text, + V8Option v8_option_tag, + OptionEnvvarSettings env_setting = kDisallowedInEnvvar, + OptionNamespaces namespace_id = OptionNamespaces::kNoNamespace); // Adds aliases. An alias can be of the form "--option-a" -> "--option-b", // or have a more complex group expansion, like @@ -535,12 +588,15 @@ class OptionsParser { // - A type. // - A way to store/access the property value. // - The information of whether it may occur in an env var or not. + // - A default value (if applicable). + // - A namespace ID (optional) to allow for namespacing of options. struct OptionInfo { OptionType type; std::shared_ptr field; OptionEnvvarSettings env_setting; std::string help_text; bool default_is_true = false; + std::string namespace_id; }; // An implied option is composed of the information on where to store a @@ -581,6 +637,9 @@ class OptionsParser { friend std::string GetBashCompletion(); friend std::unordered_map MapEnvOptionsFlagInputType(); + friend std::unordered_map MapOptionsByNamespace( + std::string namespace_name); + friend std::vector MapAvailableNamespaces(); friend void GetEnvOptionsInputType( const v8::FunctionCallbackInfo& args); }; diff --git a/src/node_platform.h b/src/node_platform.h index cee61eecf1f864..f47e2a46b66b84 100644 --- a/src/node_platform.h +++ b/src/node_platform.h @@ -30,7 +30,7 @@ struct has_priority().priority)>> template class TaskQueue { public: - // If the entry type has a priority memeber, order the priority queue by + // If the entry type has a priority member, order the priority queue by // that - higher priority first. Otherwise, maintain insertion order. struct EntryCompare { bool operator()(const std::unique_ptr& a, diff --git a/src/node_realm-inl.h b/src/node_realm-inl.h index 9eea4e5703e33b..f162d1506c990a 100644 --- a/src/node_realm-inl.h +++ b/src/node_realm-inl.h @@ -130,6 +130,13 @@ void Realm::TrackBaseObject(BaseObject* bo) { ++base_object_count_; } +CppgcWrapperListNode::CppgcWrapperListNode(CppgcMixin* ptr) : persistent(ptr) {} + +void Realm::TrackCppgcWrapper(CppgcMixin* handle) { + DCHECK_EQ(handle->realm(), this); + cppgc_wrapper_list_.PushFront(new CppgcWrapperListNode(handle)); +} + void Realm::UntrackBaseObject(BaseObject* bo) { DCHECK_EQ(bo->realm(), this); --base_object_count_; diff --git a/src/node_realm.cc b/src/node_realm.cc index cd2b4c0107594a..b7ac5d74c3b7cc 100644 --- a/src/node_realm.cc +++ b/src/node_realm.cc @@ -10,7 +10,10 @@ namespace node { using v8::Context; using v8::EscapableHandleScope; +using v8::GCCallbackFlags; +using v8::GCType; using v8::HandleScope; +using v8::Isolate; using v8::Local; using v8::MaybeLocal; using v8::Object; @@ -22,12 +25,28 @@ Realm::Realm(Environment* env, v8::Local context, Kind kind) : env_(env), isolate_(context->GetIsolate()), kind_(kind) { context_.Reset(isolate_, context); env->AssignToContext(context, this, ContextInfo("")); + // The environment can also purge empty wrappers in the check callback, + // though that may be a bit excessive depending on usage patterns. + // For now using the GC epilogue is adequate. + isolate_->AddGCEpilogueCallback(PurgeEmptyCppgcWrappers, this); } Realm::~Realm() { + isolate_->RemoveGCEpilogueCallback(PurgeEmptyCppgcWrappers, this); CHECK_EQ(base_object_count_, 0); } +void Realm::PurgeEmptyCppgcWrappers(Isolate* isolate, + GCType type, + GCCallbackFlags flags, + void* data) { + Realm* realm = static_cast(data); + if (realm->should_purge_empty_cppgc_wrappers_) { + realm->cppgc_wrapper_list_.PurgeEmpty(); + realm->should_purge_empty_cppgc_wrappers_ = false; + } +} + void Realm::MemoryInfo(MemoryTracker* tracker) const { #define V(PropertyName, TypeName) \ tracker->TrackField(#PropertyName, PropertyName()); @@ -35,6 +54,7 @@ void Realm::MemoryInfo(MemoryTracker* tracker) const { #undef V tracker->TrackField("base_object_list", base_object_list_); + tracker->TrackField("cppgc_wrapper_list", cppgc_wrapper_list_); tracker->TrackField("builtins_with_cache", builtins_with_cache); tracker->TrackField("builtins_without_cache", builtins_without_cache); } @@ -216,6 +236,7 @@ void Realm::RunCleanup() { binding_data_store_[i].reset(); } base_object_list_.Cleanup(); + cppgc_wrapper_list_.Cleanup(); } void Realm::PrintInfoForSnapshot() { diff --git a/src/node_realm.h b/src/node_realm.h index be18f39c5bf78e..9ad38be761df06 100644 --- a/src/node_realm.h +++ b/src/node_realm.h @@ -6,6 +6,7 @@ #include #include #include "cleanup_queue.h" +#include "cppgc_helpers.h" #include "env_properties.h" #include "memory_tracker.h" #include "node_snapshotable.h" @@ -25,6 +26,40 @@ using BindingDataStore = std::array, static_cast(BindingDataType::kBindingDataTypeCount)>; +/** + * This is a wrapper around a weak persistent of CppgcMixin, used in the + * CppgcWrapperList to avoid accessing already garbage collected CppgcMixins. + */ +class CppgcWrapperListNode { + public: + explicit inline CppgcWrapperListNode(CppgcMixin* ptr); + inline explicit operator bool() const { return !persistent; } + inline CppgcMixin* operator->() const { return persistent.Get(); } + inline CppgcMixin* operator*() const { return persistent.Get(); } + + cppgc::WeakPersistent persistent; + // Used by ContainerOf in the ListNode implementation for fast manipulation of + // CppgcWrapperList. + ListNode wrapper_list_node; +}; + +/** + * A per-realm list of weak persistent of cppgc wrappers, which implements + * iterations that require iterate over cppgc wrappers created by Node.js. + */ +class CppgcWrapperList + : public ListHead, + public MemoryRetainer { + public: + void Cleanup(); + void PurgeEmpty(); + + SET_MEMORY_INFO_NAME(CppgcWrapperList) + SET_SELF_SIZE(CppgcWrapperList) + void MemoryInfo(MemoryTracker* tracker) const override; +}; + /** * node::Realm is a container for a set of JavaScript objects and functions * that associated with a particular global environment. @@ -113,6 +148,9 @@ class Realm : public MemoryRetainer { // Base object count created after the bootstrap of the realm. inline int64_t base_object_created_after_bootstrap() const; + inline void TrackCppgcWrapper(CppgcMixin* handle); + inline CppgcWrapperList* cppgc_wrapper_list() { return &cppgc_wrapper_list_; } + #define V(PropertyName, TypeName) \ virtual v8::Local PropertyName() const = 0; \ virtual void set_##PropertyName(v8::Local value) = 0; @@ -126,6 +164,14 @@ class Realm : public MemoryRetainer { // it's only used for tests. std::vector builtins_in_snapshot; + // This used during the destruction of cppgc wrappers to inform a GC epilogue + // callback to clean up the weak persistents used to track cppgc wrappers if + // the wrappers are already garbage collected to prevent holding on to + // excessive useless persistents. + inline void set_should_purge_empty_cppgc_wrappers(bool value) { + should_purge_empty_cppgc_wrappers_ = value; + } + protected: ~Realm(); @@ -135,11 +181,17 @@ class Realm : public MemoryRetainer { // Shorthand for isolate pointer. v8::Isolate* isolate_; v8::Global context_; + bool should_purge_empty_cppgc_wrappers_ = false; #define V(PropertyName, TypeName) v8::Global PropertyName##_; PER_REALM_STRONG_PERSISTENT_VALUES(V) #undef V + static void PurgeEmptyCppgcWrappers(v8::Isolate* isolate, + v8::GCType type, + v8::GCCallbackFlags flags, + void* data); + private: void InitializeContext(v8::Local context, const RealmSerializeInfo* realm_info); @@ -154,6 +206,7 @@ class Realm : public MemoryRetainer { BindingDataStore binding_data_store_; BaseObjectList base_object_list_; + CppgcWrapperList cppgc_wrapper_list_; }; class PrincipalRealm : public Realm { diff --git a/src/node_report.cc b/src/node_report.cc index c64fc1a2d5f08f..f96772a065996d 100644 --- a/src/node_report.cc +++ b/src/node_report.cc @@ -680,9 +680,9 @@ static void PrintResourceUsage(JSONWriter* writer) { writer->json_objectend(); } writer->json_objectend(); -#ifdef RUSAGE_THREAD - struct rusage stats; - if (getrusage(RUSAGE_THREAD, &stats) == 0) { + + uv_rusage_t stats; + if (uv_getrusage_thread(&stats) == 0) { writer->json_objectstart("uvthreadResourceUsage"); double user_cpu = stats.ru_utime.tv_sec + SEC_PER_MICROS * stats.ru_utime.tv_usec; @@ -703,7 +703,6 @@ static void PrintResourceUsage(JSONWriter* writer) { writer->json_objectend(); writer->json_objectend(); } -#endif // RUSAGE_THREAD } static void PrintEnvironmentVariables(JSONWriter* writer) { diff --git a/src/node_sea.cc b/src/node_sea.cc index 1f7f3c8a707f4e..65a338e00d4e22 100644 --- a/src/node_sea.cc +++ b/src/node_sea.cc @@ -41,6 +41,7 @@ using v8::MaybeLocal; using v8::NewStringType; using v8::Object; using v8::ScriptCompiler; +using v8::ScriptOrigin; using v8::String; using v8::Value; @@ -460,16 +461,23 @@ std::optional GenerateCodeCache(std::string_view main_path, FIXED_ONE_BYTE_STRING(isolate, "__filename"), FIXED_ONE_BYTE_STRING(isolate, "__dirname"), }); - - // TODO(RaisinTen): Using the V8 code cache prevents us from using `import()` - // in the SEA code. Support it. - // Refs: https://github.com/nodejs/node/pull/48191#discussion_r1213271430 + ScriptOrigin script_origin(filename, 0, 0, true); + ScriptCompiler::Source script_source(content, script_origin); + MaybeLocal maybe_fn = + ScriptCompiler::CompileFunction(context, + &script_source, + parameters.size(), + parameters.data(), + 0, + nullptr); Local fn; - if (!contextify::CompileFunction(context, filename, content, ¶meters) - .ToLocal(&fn)) { + if (!maybe_fn.ToLocal(&fn)) { return std::nullopt; } + // TODO(RaisinTen): Using the V8 code cache prevents us from using `import()` + // in the SEA code. Support it. + // Refs: https://github.com/nodejs/node/pull/48191#discussion_r1213271430 std::unique_ptr cache{ ScriptCompiler::CreateCodeCacheForFunction(fn)}; std::string code_cache(cache->data, cache->data + cache->length); diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index 01e05beaefa0a9..9bdef1032e4dc9 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -42,8 +42,11 @@ using v8::HandleScope; using v8::Isolate; using v8::Local; using v8::LocalVector; +using v8::MaybeLocal; using v8::Object; using v8::ObjectTemplate; +using v8::ScriptCompiler; +using v8::ScriptOrigin; using v8::SnapshotCreator; using v8::StartupData; using v8::String; @@ -1488,9 +1491,18 @@ void CompileSerializeMain(const FunctionCallbackInfo& args) { FIXED_ONE_BYTE_STRING(isolate, "__filename"), FIXED_ONE_BYTE_STRING(isolate, "__dirname"), }); + + ScriptOrigin script_origin(filename, 0, 0, true); + ScriptCompiler::Source script_source(source, script_origin); + MaybeLocal maybe_fn = + ScriptCompiler::CompileFunction(context, + &script_source, + parameters.size(), + parameters.data(), + 0, + nullptr); Local fn; - if (contextify::CompileFunction(context, filename, source, ¶meters) - .ToLocal(&fn)) { + if (maybe_fn.ToLocal(&fn)) { args.GetReturnValue().Set(fn); } } diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc index 0295ee4ff2f739..213b4cb155fef5 100644 --- a/src/node_sqlite.cc +++ b/src/node_sqlite.cc @@ -19,6 +19,7 @@ namespace sqlite { using v8::Array; using v8::ArrayBuffer; +using v8::BackingStoreInitializationMode; using v8::BigInt; using v8::Boolean; using v8::ConstructorBehavior; @@ -103,7 +104,8 @@ using v8::Value; static_cast(sqlite3_##from##_bytes(__VA_ARGS__)); \ auto data = reinterpret_cast( \ sqlite3_##from##_blob(__VA_ARGS__)); \ - auto store = ArrayBuffer::NewBackingStore((isolate), size); \ + auto store = ArrayBuffer::NewBackingStore( \ + (isolate), size, BackingStoreInitializationMode::kUninitialized); \ memcpy(store->Data(), data, size); \ auto ab = ArrayBuffer::New((isolate), std::move(store)); \ (result) = Uint8Array::New(ab, 0, size); \ @@ -373,7 +375,10 @@ class CustomAggregate { result = Local::New(isolate, agg->value); } - JSValueToSQLiteResult(isolate, ctx, result); + if (!result.IsEmpty()) { + JSValueToSQLiteResult(isolate, ctx, result); + } + if (is_final) { DestroyAggregateData(ctx); } diff --git a/src/node_version.h b/src/node_version.h index 00543da05924fe..feb09668537f80 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -23,13 +23,13 @@ #define SRC_NODE_VERSION_H_ #define NODE_MAJOR_VERSION 24 -#define NODE_MINOR_VERSION 1 -#define NODE_PATCH_VERSION 1 +#define NODE_MINOR_VERSION 2 +#define NODE_PATCH_VERSION 0 #define NODE_VERSION_IS_LTS 0 #define NODE_VERSION_LTS_CODENAME "" -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n) diff --git a/src/permission/fs_permission.cc b/src/permission/fs_permission.cc index 6d11e06e46ebe8..0d42b3f535a597 100644 --- a/src/permission/fs_permission.cc +++ b/src/permission/fs_permission.cc @@ -45,9 +45,7 @@ void FreeRecursivelyNode( } } - if (node->wildcard_child != nullptr) { - delete node->wildcard_child; - } + delete node->wildcard_child; delete node; } diff --git a/src/quic/session.cc b/src/quic/session.cc index 98eb56ff112457..416dc9c16d756b 100644 --- a/src/quic/session.cc +++ b/src/quic/session.cc @@ -2730,7 +2730,7 @@ void Session::EmitVersionNegotiation(const ngtcp2_pkt_hd& hd, versions[n] = Integer::NewFromUnsigned(env()->isolate(), sv[n]); } - // supported are the versions we acutually support expressed as a range. + // supported are the versions we actually support expressed as a range. // The first value is the minimum version, the second is the maximum. Local supported[] = { Integer::NewFromUnsigned(env()->isolate(), opts.min_version), diff --git a/src/quic/session.h b/src/quic/session.h index d6383f2d59c077..f30d7c590c4d8f 100644 --- a/src/quic/session.h +++ b/src/quic/session.h @@ -55,7 +55,7 @@ class Endpoint; // is created. This ngtcp2_conn is destroyed when the session object is freed. // However, the session can be in a closed/destroyed state and still have a // valid ngtcp2_conn pointer. This is important because the ngtcp2 still might -// be processsing data within the scope of an ngtcp2_conn after the session +// be processing data within the scope of an ngtcp2_conn after the session // object itself is closed/destroyed by user code. class Session final : public AsyncWrap, private SessionTicket::AppData::Source { public: diff --git a/src/quic/sessionticket.h b/src/quic/sessionticket.h index a2e6e3758f6f9c..bdfd38be72d22a 100644 --- a/src/quic/sessionticket.h +++ b/src/quic/sessionticket.h @@ -58,7 +58,7 @@ class SessionTicket final : public MemoryRetainer { }; // SessionTicket::AppData is a utility class that is used only during the -// generation or access of TLS stateless sesson tickets. It exists solely to +// generation or access of TLS stateless session tickets. It exists solely to // provide a easier way for Session::Application instances to set relevant // metadata in the session ticket when it is created, and the extract and // subsequently verify that data when a ticket is received and is being diff --git a/src/quic/streams.cc b/src/quic/streams.cc index 2e16b49f9bc40c..eb42d8ea67a2e4 100644 --- a/src/quic/streams.cc +++ b/src/quic/streams.cc @@ -18,6 +18,7 @@ namespace node { using v8::Array; using v8::ArrayBuffer; using v8::ArrayBufferView; +using v8::BackingStoreInitializationMode; using v8::BigInt; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -68,7 +69,7 @@ namespace quic { V(ACKED_AT, acked_at) \ /* Marks the timestamp when the stream was destroyed */ \ V(DESTROYED_AT, destroyed_at) \ - /* Records the total number of bytes receied by the stream */ \ + /* Records the total number of bytes received by the stream */ \ V(BYTES_RECEIVED, bytes_received) \ /* Records the total number of bytes sent by the stream */ \ V(BYTES_SENT, bytes_sent) \ @@ -1198,7 +1199,8 @@ void Stream::ReceiveData(const uint8_t* data, STAT_INCREMENT_N(Stats, bytes_received, len); STAT_RECORD_TIMESTAMP(Stats, received_at); - auto backing = ArrayBuffer::NewBackingStore(env()->isolate(), len); + auto backing = ArrayBuffer::NewBackingStore( + env()->isolate(), len, BackingStoreInitializationMode::kUninitialized); memcpy(backing->Data(), data, len); inbound_->append(DataQueue::CreateInMemoryEntryFromBackingStore( std::move(backing), 0, len)); diff --git a/src/quic/streams.h b/src/quic/streams.h index 4c6f63a851cf03..a84d3c68d20609 100644 --- a/src/quic/streams.h +++ b/src/quic/streams.h @@ -332,7 +332,7 @@ class Stream final : public AsyncWrap, // The headers_ field holds a block of headers that have been received and // are being buffered for delivery to the JavaScript side. // TODO(@jasnell): Use v8::Global instead of v8::Local here. - std::vector> headers_; + v8::LocalVector headers_; // The headers_kind_ field indicates the kind of headers that are being // buffered. diff --git a/src/stream_base.cc b/src/stream_base.cc index 0bf2642599ee91..566204e667c8e8 100644 --- a/src/stream_base.cc +++ b/src/stream_base.cc @@ -708,7 +708,8 @@ void EmitToJSStreamListener::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) { CHECK_LE(static_cast(nread), bs->ByteLength()); if (static_cast(nread) != bs->ByteLength()) { std::unique_ptr old_bs = std::move(bs); - bs = ArrayBuffer::NewBackingStore(isolate, nread); + bs = ArrayBuffer::NewBackingStore( + isolate, nread, BackingStoreInitializationMode::kUninitialized); memcpy(bs->Data(), old_bs->Data(), nread); } diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc index 4907d8394c7f47..37c58cf0cb7adc 100644 --- a/src/tty_wrap.cc +++ b/src/tty_wrap.cc @@ -116,7 +116,17 @@ void TTYWrap::SetRawMode(const FunctionCallbackInfo& args) { TTYWrap* wrap; ASSIGN_OR_RETURN_UNWRAP( &wrap, args.This(), args.GetReturnValue().Set(UV_EBADF)); - int err = uv_tty_set_mode(&wrap->handle_, args[0]->IsTrue()); + // UV_TTY_MODE_RAW_VT is a variant of UV_TTY_MODE_RAW that + // enables control sequence processing on the TTY implementer side, + // rather than having libuv translate keypress events into + // control sequences, aligning behavior more closely with + // POSIX platforms. This is also required to support some control + // sequences at all on Windows, such as bracketed paste mode. + // The Node.js readline implementation handles differences between + // these modes. + int err = uv_tty_set_mode( + &wrap->handle_, + args[0]->IsTrue() ? UV_TTY_MODE_RAW_VT : UV_TTY_MODE_NORMAL); args.GetReturnValue().Set(err); } diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index 7cdb3340855423..e720aa20884181 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -35,6 +35,7 @@ using errors::TryCatchScope; using v8::Array; using v8::ArrayBuffer; using v8::BackingStore; +using v8::BackingStoreInitializationMode; using v8::Boolean; using v8::Context; using v8::DontDelete; @@ -759,7 +760,8 @@ void UDPWrap::OnRecv(ssize_t nread, } else if (static_cast(nread) != bs->ByteLength()) { CHECK_LE(static_cast(nread), bs->ByteLength()); std::unique_ptr old_bs = std::move(bs); - bs = ArrayBuffer::NewBackingStore(isolate, nread); + bs = ArrayBuffer::NewBackingStore( + isolate, nread, BackingStoreInitializationMode::kUninitialized); memcpy(bs->Data(), old_bs->Data(), nread); } diff --git a/src/undici_version.h b/src/undici_version.h index f922c6bef49a89..0cba4a2b7d7842 100644 --- a/src/undici_version.h +++ b/src/undici_version.h @@ -2,5 +2,5 @@ // Refer to tools/dep_updaters/update-undici.sh #ifndef SRC_UNDICI_VERSION_H_ #define SRC_UNDICI_VERSION_H_ -#define UNDICI_VERSION "7.8.0" +#define UNDICI_VERSION "7.10.0" #endif // SRC_UNDICI_VERSION_H_ diff --git a/test/addons/make-callback/binding.cc b/test/addons/make-callback/binding.cc index 86ed203b98d8d9..920ec3df43cd19 100644 --- a/test/addons/make-callback/binding.cc +++ b/test/addons/make-callback/binding.cc @@ -11,7 +11,7 @@ void MakeCallback(const v8::FunctionCallbackInfo& args) { assert(args[1]->IsFunction() || args[1]->IsString()); auto isolate = args.GetIsolate(); auto recv = args[0].As(); - std::vector> argv; + v8::LocalVector argv(isolate); for (size_t n = 2; n < static_cast(args.Length()); n += 1) { argv.push_back(args[n]); } diff --git a/test/addons/openssl-providers/binding.cc b/test/addons/openssl-providers/binding.cc index 76cd076c1d953c..785a103bb6c6c7 100644 --- a/test/addons/openssl-providers/binding.cc +++ b/test/addons/openssl-providers/binding.cc @@ -13,6 +13,7 @@ using v8::Context; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; +using v8::LocalVector; using v8::Object; using v8::String; using v8::Value; @@ -26,7 +27,7 @@ int collectProviders(OSSL_PROVIDER* provider, void* cbdata) { inline void GetProviders(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); - std::vector> arr = {}; + LocalVector arr(isolate, 0); #if OPENSSL_VERSION_MAJOR >= 3 std::vector providers; OSSL_PROVIDER_do_all(nullptr, &collectProviders, &providers); diff --git a/test/async-hooks/test-emit-after-on-destroyed.js b/test/async-hooks/test-emit-after-on-destroyed.js index 1a10a1dfc74a74..913cec7bd6a61b 100644 --- a/test/async-hooks/test-emit-after-on-destroyed.js +++ b/test/async-hooks/test-emit-after-on-destroyed.js @@ -52,8 +52,15 @@ if (process.argv[2] === 'child') { child.stderr.on('data', (d) => { errData = Buffer.concat([ errData, d ]); }); child.stdout.on('data', (d) => { outData = Buffer.concat([ outData, d ]); }); - child.on('close', common.mustCall((code) => { - assert.strictEqual(code, 1); + child.on('close', common.mustCall((code, signal) => { + if ((common.isAIX || + (common.isLinux && process.arch === 'x64')) && + signal === 'SIGABRT') { + // XXX: The child process could be aborted due to unknown reasons. Work around it. + } else { + assert.strictEqual(signal, null); + assert.strictEqual(code, 1); + } assert.match(outData.toString(), heartbeatMsg, 'did not crash until we reached offending line of code ' + `(found ${outData})`); diff --git a/test/async-hooks/test-improper-unwind.js b/test/async-hooks/test-improper-unwind.js index ea0eee025d7fd3..fb7f212a6804b2 100644 --- a/test/async-hooks/test-improper-unwind.js +++ b/test/async-hooks/test-improper-unwind.js @@ -55,8 +55,15 @@ if (process.argv[2] === 'child') { child.stderr.on('data', (d) => { errData = Buffer.concat([ errData, d ]); }); child.stdout.on('data', (d) => { outData = Buffer.concat([ outData, d ]); }); - child.on('close', common.mustCall((code) => { - assert.strictEqual(code, 1); + child.on('close', common.mustCall((code, signal) => { + if ((common.isAIX || + (common.isLinux && process.arch === 'x64')) && + signal === 'SIGABRT') { + // XXX: The child process could be aborted due to unknown reasons. Work around it. + } else { + assert.strictEqual(signal, null); + assert.strictEqual(code, 1); + } assert.match(outData.toString(), heartbeatMsg, 'did not crash until we reached offending line of code ' + `(found ${outData})`); diff --git a/test/cctest/node_test_fixture.cc b/test/cctest/node_test_fixture.cc index cae9c7b76aee88..6b75e88d14c2b0 100644 --- a/test/cctest/node_test_fixture.cc +++ b/test/cctest/node_test_fixture.cc @@ -21,9 +21,6 @@ void NodeTestEnvironment::SetUp() { NodeZeroIsolateTestFixture::platform.reset( new node::NodePlatform(kV8ThreadPoolSize, tracing_controller)); v8::V8::InitializePlatform(NodeZeroIsolateTestFixture::platform.get()); -#ifdef V8_ENABLE_SANDBOX - ASSERT_TRUE(v8::V8::InitializeSandbox()); -#endif cppgc::InitializeProcess( NodeZeroIsolateTestFixture::platform->GetPageAllocator()); diff --git a/test/common/assertSnapshot.js b/test/common/assertSnapshot.js index dbd4a6079861fc..7a40c94389eda9 100644 --- a/test/common/assertSnapshot.js +++ b/test/common/assertSnapshot.js @@ -16,6 +16,10 @@ function replaceStackTrace(str, replacement = '$1*$7$8\n') { return str.replace(stackFramesRegexp, replacement); } +function replaceInternalStackTrace(str) { + return str.replaceAll(/(\W+).*node:internal.*/g, '$1*'); +} + function replaceWindowsLineEndings(str) { return str.replace(windowNewlineRegexp, ''); } @@ -24,8 +28,11 @@ function replaceWindowsPaths(str) { return common.isWindows ? str.replaceAll(path.win32.sep, path.posix.sep) : str; } -function replaceFullPaths(str) { - return str.replaceAll('\\\'', "'").replaceAll(path.resolve(__dirname, '../..'), ''); +function transformProjectRoot(replacement = '') { + const projectRoot = path.resolve(__dirname, '../..'); + return (str) => { + return str.replaceAll('\\\'', "'").replaceAll(projectRoot, replacement); + }; } function transform(...args) { @@ -94,11 +101,12 @@ async function spawnAndAssert(filename, transform = (x) => x, { tty = false, ... module.exports = { assertSnapshot, getSnapshotPath, - replaceFullPaths, replaceNodeVersion, replaceStackTrace, + replaceInternalStackTrace, replaceWindowsLineEndings, replaceWindowsPaths, spawnAndAssert, transform, + transformProjectRoot, }; diff --git a/test/es-module/es-module.status b/test/es-module/es-module.status index 58a422dc152258..32b712cbef0c8f 100644 --- a/test/es-module/es-module.status +++ b/test/es-module/es-module.status @@ -13,3 +13,7 @@ test-esm-loader-http-imports: PASS,FLAKY [$arch==arm || $arch==arm64] # https://github.com/nodejs/node/issues/47297 test-wasm-web-api: SKIP + +[$system==ibmi] +# https://github.com/nodejs/node/issues/58582 +test-wasm-web-api: PASS,FLAKY diff --git a/test/es-module/test-esm-import-meta-main-eval.mjs b/test/es-module/test-esm-import-meta-main-eval.mjs new file mode 100644 index 00000000000000..66171164b748bf --- /dev/null +++ b/test/es-module/test-esm-import-meta-main-eval.mjs @@ -0,0 +1,74 @@ +import { spawnPromisified } from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.js'; +import assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; + +const importMetaMainScript = ` +import assert from 'node:assert/strict'; + +assert.strictEqual(import.meta.main, true, 'import.meta.main should evaluate true in main module'); + +const { isMain: importedModuleIsMain } = await import( + ${JSON.stringify(fixtures.fileURL('es-modules/import-meta-main.mjs'))} +); +assert.strictEqual(importedModuleIsMain, false, 'import.meta.main should evaluate false in imported module'); +`; + +function wrapScriptInEvalWorker(script) { + return ` + import { Worker } from 'node:worker_threads'; + new Worker(${JSON.stringify(script)}, { eval: true }); + `; +} + +function convertScriptSourceToDataUrl(script) { + return new URL(`data:text/javascript,${encodeURIComponent(script)}`); +} + +function wrapScriptInUrlWorker(script) { + return ` + import { Worker } from 'node:worker_threads'; + new Worker(new URL(${JSON.stringify(convertScriptSourceToDataUrl(script))})); + `; +} + +describe('import.meta.main in evaluated scripts', () => { + it('should evaluate true in evaluated script', async () => { + const result = await spawnPromisified( + process.execPath, + ['--input-type=module', '--eval', importMetaMainScript], + ); + assert.deepStrictEqual(result, { + stderr: '', + stdout: '', + code: 0, + signal: null, + }); + }); + + it('should evaluate true in worker instantiated with module source by evaluated script', async () => { + const result = await spawnPromisified( + process.execPath, + ['--input-type=module', '--eval', wrapScriptInEvalWorker(importMetaMainScript)], + ); + assert.deepStrictEqual(result, { + stderr: '', + stdout: '', + code: 0, + signal: null, + }); + }); + + it('should evaluate true in worker instantiated with `data:` URL by evaluated script', async () => { + const result = await spawnPromisified( + process.execPath, + ['--input-type=module', '--eval', wrapScriptInUrlWorker(importMetaMainScript)], + ); + assert.deepStrictEqual(result, { + stderr: '', + stdout: '', + code: 0, + signal: null, + }); + }); +}); diff --git a/test/es-module/test-esm-import-meta-main.mjs b/test/es-module/test-esm-import-meta-main.mjs new file mode 100644 index 00000000000000..61251ceb9ed1b2 --- /dev/null +++ b/test/es-module/test-esm-import-meta-main.mjs @@ -0,0 +1,26 @@ +import '../common/index.mjs'; +import assert from 'node:assert/strict'; +import { Worker } from 'node:worker_threads'; + +function get_environment() { + if (process.env.HAS_STARTED_WORKER) return 'in worker thread started by ES Module'; + return 'in ES Module'; +} + +assert.strictEqual( + import.meta.main, + true, + `\`import.meta.main\` at top-level module ${get_environment()} should evaluate \`true\`` +); + +const { isMain: importedModuleIsMain } = await import('../fixtures/es-modules/import-meta-main.mjs'); +assert.strictEqual( + importedModuleIsMain, + false, + `\`import.meta.main\` at dynamically imported module ${get_environment()} should evaluate \`false\`` +); + +if (!process.env.HAS_STARTED_WORKER) { + process.env.HAS_STARTED_WORKER = 1; + new Worker(import.meta.filename); +} diff --git a/test/es-module/test-esm-import-meta.mjs b/test/es-module/test-esm-import-meta.mjs index eace54884f7121..a2575c4d108cc1 100644 --- a/test/es-module/test-esm-import-meta.mjs +++ b/test/es-module/test-esm-import-meta.mjs @@ -3,7 +3,7 @@ import assert from 'assert'; assert.strictEqual(Object.getPrototypeOf(import.meta), null); -const keys = ['dirname', 'filename', 'resolve', 'url']; +const keys = ['dirname', 'filename', 'main', 'resolve', 'url']; assert.deepStrictEqual(Reflect.ownKeys(import.meta), keys); const descriptors = Object.getOwnPropertyDescriptors(import.meta); diff --git a/test/es-module/test-esm-wasm.mjs b/test/es-module/test-esm-wasm.mjs index b7a9230dd184b2..dcd9d9ab5435c4 100644 --- a/test/es-module/test-esm-wasm.mjs +++ b/test/es-module/test-esm-wasm.mjs @@ -52,7 +52,154 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () => [ 'import { strictEqual } from "node:assert";', `import * as wasmExports from ${JSON.stringify(fixtures.fileURL('es-modules/export-name-syntax-error.wasm'))};`, - 'assert.strictEqual(wasmExports["?f!o:oa[r]"]?.value, 12682);', + 'assert.strictEqual(wasmExports["?f!o:oa[r]"], 12682);', + ].join('\n'), + ]); + + strictEqual(stderr, ''); + strictEqual(stdout, ''); + strictEqual(code, 0); + }); + + it('should properly handle all WebAssembly global types', async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-wasm-modules', + '--input-type=module', + '--eval', + [ + 'import { strictEqual, deepStrictEqual, ok } from "node:assert";', + + // SIMD is not supported on rhel8-ppc64le + 'let wasmExports;', + 'try {', + ` wasmExports = await import(${JSON.stringify(fixtures.fileURL('es-modules/globals.wasm'))});`, + '} catch (e) {', + ' ok(e instanceof WebAssembly.CompileError);', + ' ok(e.message.includes("SIMD unsupported"));', + '}', + + 'if (wasmExports) {', + + // Test imported globals using direct access + ' strictEqual(wasmExports.importedI32, 42);', + ' strictEqual(wasmExports.importedMutI32, 100);', + ' strictEqual(wasmExports.importedI64, 9223372036854775807n);', + ' strictEqual(wasmExports.importedMutI64, 200n);', + ' strictEqual(Math.round(wasmExports.importedF32 * 100000) / 100000, 3.14159);', + ' strictEqual(Math.round(wasmExports.importedMutF32 * 100000) / 100000, 2.71828);', + ' strictEqual(wasmExports.importedF64, 3.141592653589793);', + ' strictEqual(wasmExports.importedMutF64, 2.718281828459045);', + ' strictEqual(wasmExports.importedExternref !== null, true);', + ' strictEqual(wasmExports.importedMutExternref !== null, true);', + ' strictEqual(wasmExports.importedNullExternref, null);', + + // Test local globals exported directly + ' strictEqual(wasmExports[\'🚀localI32\'], 42);', + ' strictEqual(wasmExports.localMutI32, 100);', + ' strictEqual(wasmExports.localI64, 9223372036854775807n);', + ' strictEqual(wasmExports.localMutI64, 200n);', + ' strictEqual(Math.round(wasmExports.localF32 * 100000) / 100000, 3.14159);', + ' strictEqual(Math.round(wasmExports.localMutF32 * 100000) / 100000, 2.71828);', + ' strictEqual(wasmExports.localF64, 2.718281828459045);', + ' strictEqual(wasmExports.localMutF64, 3.141592653589793);', + + // Test imported globals using getter functions + ' strictEqual(wasmExports.getImportedMutI32(), 100);', + ' strictEqual(wasmExports.getImportedMutI64(), 200n);', + ' strictEqual(Math.round(wasmExports.getImportedMutF32() * 100000) / 100000, 2.71828);', + ' strictEqual(wasmExports.getImportedMutF64(), 2.718281828459045);', + ' strictEqual(wasmExports.getImportedMutExternref() !== null, true);', + + // Test local globals using getter functions + ' strictEqual(wasmExports.getLocalMutI32(), 100);', + ' strictEqual(wasmExports.getLocalMutI64(), 200n);', + ' strictEqual(Math.round(wasmExports.getLocalMutF32() * 100000) / 100000, 2.71828);', + ' strictEqual(wasmExports.getLocalMutF64(), 3.141592653589793);', + ' strictEqual(wasmExports.getLocalMutExternref(), null);', + + ' assert.throws(wasmExports.getLocalMutV128);', + + // Pending TDZ support + ' strictEqual(wasmExports.depV128, undefined);', + + // Test modifying mutable globals and reading the new values + ' wasmExports.setImportedMutI32(999);', + ' strictEqual(wasmExports.getImportedMutI32(), 999);', + + ' wasmExports.setImportedMutI64(888n);', + ' strictEqual(wasmExports.getImportedMutI64(), 888n);', + + ' wasmExports.setImportedMutF32(7.77);', + ' strictEqual(Math.round(wasmExports.getImportedMutF32() * 100) / 100, 7.77);', + + ' wasmExports.setImportedMutF64(6.66);', + ' strictEqual(wasmExports.getImportedMutF64(), 6.66);', + + // Test modifying mutable externref + ' const testObj = { test: "object" };', + ' wasmExports.setImportedMutExternref(testObj);', + ' strictEqual(wasmExports.getImportedMutExternref(), testObj);', + + // Test modifying local mutable globals + ' wasmExports.setLocalMutI32(555);', + ' strictEqual(wasmExports.getLocalMutI32(), 555);', + + ' wasmExports.setLocalMutI64(444n);', + ' strictEqual(wasmExports.getLocalMutI64(), 444n);', + + ' wasmExports.setLocalMutF32(3.33);', + ' strictEqual(Math.round(wasmExports.getLocalMutF32() * 100) / 100, 3.33);', + + ' wasmExports.setLocalMutF64(2.22);', + ' strictEqual(wasmExports.getLocalMutF64(), 2.22);', + + // These mutating pending live bindings support + ' strictEqual(wasmExports.localMutI32, 100);', + ' strictEqual(wasmExports.localMutI64, 200n);', + ' strictEqual(Math.round(wasmExports.localMutF32 * 100) / 100, 2.72);', + ' strictEqual(wasmExports.localMutF64, 3.141592653589793);', + + // Test modifying local mutable externref + ' const anotherTestObj = { another: "test object" };', + ' wasmExports.setLocalMutExternref(anotherTestObj);', + ' strictEqual(wasmExports.getLocalMutExternref(), anotherTestObj);', + ' strictEqual(wasmExports.localMutExternref, null);', + + // Test dep.wasm imports + ' strictEqual(wasmExports.depI32, 1001);', + ' strictEqual(wasmExports.depMutI32, 2001);', + ' strictEqual(wasmExports.getDepMutI32(), 2001);', + ' strictEqual(wasmExports.depI64, 10000000001n);', + ' strictEqual(wasmExports.depMutI64, 20000000001n);', + ' strictEqual(wasmExports.getDepMutI64(), 20000000001n);', + ' strictEqual(Math.round(wasmExports.depF32 * 100) / 100, 10.01);', + ' strictEqual(Math.round(wasmExports.depMutF32 * 100) / 100, 20.01);', + ' strictEqual(Math.round(wasmExports.getDepMutF32() * 100) / 100, 20.01);', + ' strictEqual(wasmExports.depF64, 100.0001);', + ' strictEqual(wasmExports.depMutF64, 200.0001);', + ' strictEqual(wasmExports.getDepMutF64(), 200.0001);', + + // Test modifying dep.wasm mutable globals + ' wasmExports.setDepMutI32(3001);', + ' strictEqual(wasmExports.getDepMutI32(), 3001);', + + ' wasmExports.setDepMutI64(30000000001n);', + ' strictEqual(wasmExports.getDepMutI64(), 30000000001n);', + + ' wasmExports.setDepMutF32(30.01);', + ' strictEqual(Math.round(wasmExports.getDepMutF32() * 100) / 100, 30.01);', + + ' wasmExports.setDepMutF64(300.0001);', + ' strictEqual(wasmExports.getDepMutF64(), 300.0001);', + + // These pending live bindings support + ' strictEqual(wasmExports.depMutI32, 2001);', + ' strictEqual(wasmExports.depMutI64, 20000000001n);', + ' strictEqual(Math.round(wasmExports.depMutF32 * 100) / 100, 20.01);', + ' strictEqual(wasmExports.depMutF64, 200.0001);', + + '}', ].join('\n'), ]); @@ -124,8 +271,7 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () => strictEqual(code, 0); }); - // TODO: Enable this once https://github.com/nodejs/node/pull/56842 lands. - it.skip('should support dynamic source phase imports', async () => { + it('should support dynamic source phase imports', async () => { const { code, stderr, stdout } = await spawnPromisified(execPath, [ '--no-warnings', '--experimental-wasm-modules', @@ -166,8 +312,7 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () => strictEqual(code, 0); }); - // TODO: Enable this once https://github.com/nodejs/node/pull/56842 lands. - it.skip('should not execute dynamic source phase imports', async () => { + it('should not execute dynamic source phase imports', async () => { const { code, stderr, stdout } = await spawnPromisified(execPath, [ '--no-warnings', '--experimental-wasm-modules', @@ -181,8 +326,7 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () => strictEqual(code, 0); }); - // TODO: Enable this once https://github.com/nodejs/node/pull/56842 lands. - it.skip('should throw for dynamic source phase imports not defined', async () => { + it('should throw for dynamic source phase imports not defined', async () => { const fileUrl = fixtures.fileURL('es-modules/wasm-source-phase.js'); const { code, stderr, stdout } = await spawnPromisified(execPath, [ '--no-warnings', @@ -195,6 +339,7 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () => ' strictEqual(e instanceof SyntaxError, true);', ' strictEqual(e.message.includes("Source phase import object is not defined for module"), true);', ` strictEqual(e.message.includes(${JSON.stringify(fileUrl)}), true);`, + ` return true`, '});', ].join('\n'), ]); @@ -238,8 +383,7 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () => notStrictEqual(code, 0); }); - // TODO: Enable this once https://github.com/nodejs/node/pull/56842 lands. - it.skip('should throw for vm source phase dynamic import', async () => { + it('should throw for vm source phase dynamic import', async () => { const { code, stderr, stdout } = await spawnPromisified(execPath, [ '--no-warnings', '--experimental-wasm-modules', diff --git a/test/es-module/test-require-module-error-catching.js b/test/es-module/test-require-module-error-catching.js index c314513d9bbf04..5400564b3182c6 100644 --- a/test/es-module/test-require-module-error-catching.js +++ b/test/es-module/test-require-module-error-catching.js @@ -17,5 +17,5 @@ assert.throws(() => { require('../fixtures/es-modules/reference-error-esm.js'); }, { name: 'ReferenceError', - message: 'exports is not defined' + message: 'exports is not defined in ES module scope' }); diff --git a/test/es-module/test-wasm-web-api.js b/test/es-module/test-wasm-web-api.js index b199393a18c370..879748e4403b07 100644 --- a/test/es-module/test-wasm-web-api.js +++ b/test/es-module/test-wasm-web-api.js @@ -106,7 +106,9 @@ function testCompileStreamingRejectionUsingFetch(responseCallback, rejection) { // Response whose body is a ReadableStream instead of calling fetch(). await testCompileStreamingSuccess(async () => { const handle = await fs.open(fixtures.path('simple.wasm')); - const stream = handle.readableWebStream(); + // We set the autoClose option to true so that the file handle is closed + // automatically when the stream is completed or canceled. + const stream = handle.readableWebStream({ autoClose: true }); return Promise.resolve(new Response(stream, { status: 200, headers: { 'Content-Type': 'application/wasm' } diff --git a/test/fixtures/console/stack_overflow.js b/test/fixtures/console/stack_overflow.js index 565692b6d6e4ba..14bceef878b5cf 100644 --- a/test/fixtures/console/stack_overflow.js +++ b/test/fixtures/console/stack_overflow.js @@ -26,11 +26,15 @@ Error.stackTraceLimit = 0; console.error('before'); +// Invalidate elements protector to force slow-path. +// The fast-path of JSON.stringify is iterative and won't throw. +Array.prototype[2] = 'foo'; + // Trigger stack overflow by stringifying a deeply nested array. -let array = []; -for (let i = 0; i < 100000; i++) { - array = [ array ]; -} +// eslint-disable-next-line no-sparse-arrays +let array = [,]; +for (let i = 0; i < 10000; i++) + array = [array]; JSON.stringify(array); diff --git a/test/fixtures/es-modules/dep.wasm b/test/fixtures/es-modules/dep.wasm new file mode 100644 index 00000000000000..ad9abfaa66af53 Binary files /dev/null and b/test/fixtures/es-modules/dep.wasm differ diff --git a/test/fixtures/es-modules/dep.wat b/test/fixtures/es-modules/dep.wat new file mode 100644 index 00000000000000..26edc9799ce5cb --- /dev/null +++ b/test/fixtures/es-modules/dep.wat @@ -0,0 +1,32 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result i64))) + (type (;2;) (func (result f32))) + (type (;3;) (func (result f64))) + (type (;4;) (func (result externref))) + (type (;5;) (func (result v128))) + (global $i32_value (;0;) i32 i32.const 1001) + (global $i32_mut_value (;1;) (mut i32) i32.const 2001) + (global $i64_value (;2;) i64 i64.const 10000000001) + (global $i64_mut_value (;3;) (mut i64) i64.const 20000000001) + (global $f32_value (;4;) f32 f32.const 0x1.4051ecp+3 (;=10.01;)) + (global $f32_mut_value (;5;) (mut f32) f32.const 0x1.4028f6p+4 (;=20.01;)) + (global $f64_value (;6;) f64 f64.const 0x1.90001a36e2eb2p+6 (;=100.0001;)) + (global $f64_mut_value (;7;) (mut f64) f64.const 0x1.90000d1b71759p+7 (;=200.0001;)) + (global $externref_value (;8;) externref ref.null extern) + (global $externref_mut_value (;9;) (mut externref) ref.null extern) + (global $v128_value (;10;) v128 v128.const i32x4 0x0000000a 0x00000014 0x0000001e 0x00000028) + (global $v128_mut_value (;11;) (mut v128) v128.const i32x4 0x00000032 0x0000003c 0x00000046 0x00000050) + (export "i32_value" (global $i32_value)) + (export "i32_mut_value" (global $i32_mut_value)) + (export "i64_value" (global $i64_value)) + (export "i64_mut_value" (global $i64_mut_value)) + (export "f32_value" (global $f32_value)) + (export "f32_mut_value" (global $f32_mut_value)) + (export "f64_value" (global $f64_value)) + (export "f64_mut_value" (global $f64_mut_value)) + (export "externref_value" (global $externref_value)) + (export "externref_mut_value" (global $externref_mut_value)) + (export "v128_value" (global $v128_value)) + (export "v128_mut_value" (global $v128_mut_value)) +) diff --git a/test/fixtures/es-modules/globals.js b/test/fixtures/es-modules/globals.js new file mode 100644 index 00000000000000..0b01c0225e020d --- /dev/null +++ b/test/fixtures/es-modules/globals.js @@ -0,0 +1,18 @@ +// globals.js - Direct global exports for WebAssembly imports + +// Immutable globals (simple values) +const i32_value = 42; +export { i32_value as '🚀i32_value' } +export const i64_value = 9223372036854775807n; // Max i64 value +export const f32_value = 3.14159; +export const f64_value = 3.141592653589793; + +// Mutable globals with WebAssembly.Global wrapper +export const i32_mut_value = new WebAssembly.Global({ value: 'i32', mutable: true }, 100); +export const i64_mut_value = new WebAssembly.Global({ value: 'i64', mutable: true }, 200n); +export const f32_mut_value = new WebAssembly.Global({ value: 'f32', mutable: true }, 2.71828); +export const f64_mut_value = new WebAssembly.Global({ value: 'f64', mutable: true }, 2.718281828459045); + +export const externref_value = { hello: 'world' }; +export const externref_mut_value = new WebAssembly.Global({ value: 'externref', mutable: true }, { mutable: 'global' }); +export const null_externref_value = null; diff --git a/test/fixtures/es-modules/globals.wasm b/test/fixtures/es-modules/globals.wasm new file mode 100644 index 00000000000000..45188ab26ee5c1 Binary files /dev/null and b/test/fixtures/es-modules/globals.wasm differ diff --git a/test/fixtures/es-modules/globals.wat b/test/fixtures/es-modules/globals.wat new file mode 100644 index 00000000000000..c261222dd3cdab --- /dev/null +++ b/test/fixtures/es-modules/globals.wat @@ -0,0 +1,237 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result i64))) + (type (;2;) (func (result f32))) + (type (;3;) (func (result f64))) + (type (;4;) (func (result externref))) + (type (;5;) (func (result v128))) + (type (;6;) (func (param i32))) + (type (;7;) (func (param i64))) + (type (;8;) (func (param f32))) + (type (;9;) (func (param f64))) + (type (;10;) (func (param externref))) + (type (;11;) (func (param v128))) + (import "./globals.js" "\u{1f680}i32_value" (global $imported_i32 (;0;) i32)) + (import "./globals.js" "i32_mut_value" (global $imported_mut_i32 (;1;) (mut i32))) + (import "./globals.js" "i64_value" (global $imported_i64 (;2;) i64)) + (import "./globals.js" "i64_mut_value" (global $imported_mut_i64 (;3;) (mut i64))) + (import "./globals.js" "f32_value" (global $imported_f32 (;4;) f32)) + (import "./globals.js" "f32_mut_value" (global $imported_mut_f32 (;5;) (mut f32))) + (import "./globals.js" "f64_value" (global $imported_f64 (;6;) f64)) + (import "./globals.js" "f64_mut_value" (global $imported_mut_f64 (;7;) (mut f64))) + (import "./globals.js" "externref_value" (global $imported_externref (;8;) externref)) + (import "./globals.js" "externref_mut_value" (global $imported_mut_externref (;9;) (mut externref))) + (import "./globals.js" "null_externref_value" (global $imported_null_externref (;10;) externref)) + (import "./dep.wasm" "i32_value" (global $dep_i32 (;11;) i32)) + (import "./dep.wasm" "i32_mut_value" (global $dep_mut_i32 (;12;) (mut i32))) + (import "./dep.wasm" "i64_value" (global $dep_i64 (;13;) i64)) + (import "./dep.wasm" "i64_mut_value" (global $dep_mut_i64 (;14;) (mut i64))) + (import "./dep.wasm" "f32_value" (global $dep_f32 (;15;) f32)) + (import "./dep.wasm" "f32_mut_value" (global $dep_mut_f32 (;16;) (mut f32))) + (import "./dep.wasm" "f64_value" (global $dep_f64 (;17;) f64)) + (import "./dep.wasm" "f64_mut_value" (global $dep_mut_f64 (;18;) (mut f64))) + (import "./dep.wasm" "externref_value" (global $dep_externref (;19;) externref)) + (import "./dep.wasm" "externref_mut_value" (global $dep_mut_externref (;20;) (mut externref))) + (import "./dep.wasm" "v128_value" (global $dep_v128 (;21;) v128)) + (import "./dep.wasm" "v128_mut_value" (global $dep_mut_v128 (;22;) (mut v128))) + (global $local_i32 (;23;) i32 i32.const 42) + (global $local_mut_i32 (;24;) (mut i32) i32.const 100) + (global $local_i64 (;25;) i64 i64.const 9223372036854775807) + (global $local_mut_i64 (;26;) (mut i64) i64.const 200) + (global $local_f32 (;27;) f32 f32.const 0x1.921fap+1 (;=3.14159;)) + (global $local_mut_f32 (;28;) (mut f32) f32.const 0x1.5bf09ap+1 (;=2.71828;)) + (global $local_f64 (;29;) f64 f64.const 0x1.5bf0a8b145769p+1 (;=2.718281828459045;)) + (global $local_mut_f64 (;30;) (mut f64) f64.const 0x1.921fb54442d18p+1 (;=3.141592653589793;)) + (global $local_externref (;31;) externref ref.null extern) + (global $local_mut_externref (;32;) (mut externref) ref.null extern) + (global $local_v128 (;33;) v128 v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004) + (global $local_mut_v128 (;34;) (mut v128) v128.const i32x4 0x00000005 0x00000006 0x00000007 0x00000008) + (export "importedI32" (global $imported_i32)) + (export "importedMutI32" (global $imported_mut_i32)) + (export "importedI64" (global $imported_i64)) + (export "importedMutI64" (global $imported_mut_i64)) + (export "importedF32" (global $imported_f32)) + (export "importedMutF32" (global $imported_mut_f32)) + (export "importedF64" (global $imported_f64)) + (export "importedMutF64" (global $imported_mut_f64)) + (export "importedExternref" (global $imported_externref)) + (export "importedMutExternref" (global $imported_mut_externref)) + (export "importedNullExternref" (global $imported_null_externref)) + (export "depI32" (global $dep_i32)) + (export "depMutI32" (global $dep_mut_i32)) + (export "depI64" (global $dep_i64)) + (export "depMutI64" (global $dep_mut_i64)) + (export "depF32" (global $dep_f32)) + (export "depMutF32" (global $dep_mut_f32)) + (export "depF64" (global $dep_f64)) + (export "depMutF64" (global $dep_mut_f64)) + (export "depExternref" (global $dep_externref)) + (export "depMutExternref" (global $dep_mut_externref)) + (export "depV128" (global $dep_v128)) + (export "depMutV128" (global $dep_mut_v128)) + (export "\u{1f680}localI32" (global $local_i32)) + (export "localMutI32" (global $local_mut_i32)) + (export "localI64" (global $local_i64)) + (export "localMutI64" (global $local_mut_i64)) + (export "localF32" (global $local_f32)) + (export "localMutF32" (global $local_mut_f32)) + (export "localF64" (global $local_f64)) + (export "localMutF64" (global $local_mut_f64)) + (export "localExternref" (global $local_externref)) + (export "localMutExternref" (global $local_mut_externref)) + (export "localV128" (global $local_v128)) + (export "localMutV128" (global $local_mut_v128)) + (export "getImportedMutI32" (func $getImportedMutI32)) + (export "getImportedMutI64" (func $getImportedMutI64)) + (export "getImportedMutF32" (func $getImportedMutF32)) + (export "getImportedMutF64" (func $getImportedMutF64)) + (export "getImportedMutExternref" (func $getImportedMutExternref)) + (export "getLocalMutI32" (func $getLocalMutI32)) + (export "getLocalMutI64" (func $getLocalMutI64)) + (export "getLocalMutF32" (func $getLocalMutF32)) + (export "getLocalMutF64" (func $getLocalMutF64)) + (export "getLocalMutExternref" (func $getLocalMutExternref)) + (export "getLocalMutV128" (func $getLocalMutV128)) + (export "getDepMutI32" (func $getDepMutI32)) + (export "getDepMutI64" (func $getDepMutI64)) + (export "getDepMutF32" (func $getDepMutF32)) + (export "getDepMutF64" (func $getDepMutF64)) + (export "getDepMutExternref" (func $getDepMutExternref)) + (export "getDepMutV128" (func $getDepMutV128)) + (export "setImportedMutI32" (func $setImportedMutI32)) + (export "setImportedMutI64" (func $setImportedMutI64)) + (export "setImportedMutF32" (func $setImportedMutF32)) + (export "setImportedMutF64" (func $setImportedMutF64)) + (export "setImportedMutExternref" (func $setImportedMutExternref)) + (export "setLocalMutI32" (func $setLocalMutI32)) + (export "setLocalMutI64" (func $setLocalMutI64)) + (export "setLocalMutF32" (func $setLocalMutF32)) + (export "setLocalMutF64" (func $setLocalMutF64)) + (export "setLocalMutExternref" (func $setLocalMutExternref)) + (export "setLocalMutV128" (func $setLocalMutV128)) + (export "setDepMutI32" (func $setDepMutI32)) + (export "setDepMutI64" (func $setDepMutI64)) + (export "setDepMutF32" (func $setDepMutF32)) + (export "setDepMutF64" (func $setDepMutF64)) + (export "setDepMutExternref" (func $setDepMutExternref)) + (export "setDepMutV128" (func $setDepMutV128)) + (func $getImportedMutI32 (;0;) (type 0) (result i32) + global.get $imported_mut_i32 + ) + (func $getImportedMutI64 (;1;) (type 1) (result i64) + global.get $imported_mut_i64 + ) + (func $getImportedMutF32 (;2;) (type 2) (result f32) + global.get $imported_mut_f32 + ) + (func $getImportedMutF64 (;3;) (type 3) (result f64) + global.get $imported_mut_f64 + ) + (func $getImportedMutExternref (;4;) (type 4) (result externref) + global.get $imported_mut_externref + ) + (func $setImportedMutI32 (;5;) (type 6) (param i32) + local.get 0 + global.set $imported_mut_i32 + ) + (func $setImportedMutI64 (;6;) (type 7) (param i64) + local.get 0 + global.set $imported_mut_i64 + ) + (func $setImportedMutF32 (;7;) (type 8) (param f32) + local.get 0 + global.set $imported_mut_f32 + ) + (func $setImportedMutF64 (;8;) (type 9) (param f64) + local.get 0 + global.set $imported_mut_f64 + ) + (func $setImportedMutExternref (;9;) (type 10) (param externref) + local.get 0 + global.set $imported_mut_externref + ) + (func $getLocalMutI32 (;10;) (type 0) (result i32) + global.get $local_mut_i32 + ) + (func $getLocalMutI64 (;11;) (type 1) (result i64) + global.get $local_mut_i64 + ) + (func $getLocalMutF32 (;12;) (type 2) (result f32) + global.get $local_mut_f32 + ) + (func $getLocalMutF64 (;13;) (type 3) (result f64) + global.get $local_mut_f64 + ) + (func $getLocalMutExternref (;14;) (type 4) (result externref) + global.get $local_mut_externref + ) + (func $getLocalMutV128 (;15;) (type 5) (result v128) + global.get $local_mut_v128 + ) + (func $setLocalMutI32 (;16;) (type 6) (param i32) + local.get 0 + global.set $local_mut_i32 + ) + (func $setLocalMutI64 (;17;) (type 7) (param i64) + local.get 0 + global.set $local_mut_i64 + ) + (func $setLocalMutF32 (;18;) (type 8) (param f32) + local.get 0 + global.set $local_mut_f32 + ) + (func $setLocalMutF64 (;19;) (type 9) (param f64) + local.get 0 + global.set $local_mut_f64 + ) + (func $setLocalMutExternref (;20;) (type 10) (param externref) + local.get 0 + global.set $local_mut_externref + ) + (func $setLocalMutV128 (;21;) (type 11) (param v128) + local.get 0 + global.set $local_mut_v128 + ) + (func $getDepMutI32 (;22;) (type 0) (result i32) + global.get $dep_mut_i32 + ) + (func $getDepMutI64 (;23;) (type 1) (result i64) + global.get $dep_mut_i64 + ) + (func $getDepMutF32 (;24;) (type 2) (result f32) + global.get $dep_mut_f32 + ) + (func $getDepMutF64 (;25;) (type 3) (result f64) + global.get $dep_mut_f64 + ) + (func $getDepMutExternref (;26;) (type 4) (result externref) + global.get $dep_mut_externref + ) + (func $getDepMutV128 (;27;) (type 5) (result v128) + global.get $dep_mut_v128 + ) + (func $setDepMutI32 (;28;) (type 6) (param i32) + local.get 0 + global.set $dep_mut_i32 + ) + (func $setDepMutI64 (;29;) (type 7) (param i64) + local.get 0 + global.set $dep_mut_i64 + ) + (func $setDepMutF32 (;30;) (type 8) (param f32) + local.get 0 + global.set $dep_mut_f32 + ) + (func $setDepMutF64 (;31;) (type 9) (param f64) + local.get 0 + global.set $dep_mut_f64 + ) + (func $setDepMutExternref (;32;) (type 10) (param externref) + local.get 0 + global.set $dep_mut_externref + ) + (func $setDepMutV128 (;33;) (type 11) (param v128) + local.get 0 + global.set $dep_mut_v128 + ) +) diff --git a/test/fixtures/es-modules/import-meta-main.mjs b/test/fixtures/es-modules/import-meta-main.mjs new file mode 100644 index 00000000000000..bee2c8e2651335 --- /dev/null +++ b/test/fixtures/es-modules/import-meta-main.mjs @@ -0,0 +1 @@ +export const isMain = import.meta.main; diff --git a/test/fixtures/permission/fs-read-loader.js b/test/fixtures/permission/fs-read-loader.js new file mode 100644 index 00000000000000..aaef61e8ce715d --- /dev/null +++ b/test/fixtures/permission/fs-read-loader.js @@ -0,0 +1,15 @@ +const fs = require('node:fs') +const path = require('node:path') +const assert = require('node:assert'); + +{ + fs.readFileSync(__filename); + console.log('Read its own contents') // Should not throw +} +{ + const simpleLoaderPath = path.join(__dirname, 'simple-loader.js'); + fs.readFile(simpleLoaderPath, (err) => { + assert.ok(err.code, 'ERR_ACCESS_DENIED'); + assert.ok(err.permission, 'FileSystemRead'); + }); // Should throw ERR_ACCESS_DENIED +} \ No newline at end of file diff --git a/test/fixtures/permission/hello-world.js b/test/fixtures/permission/hello-world.js new file mode 100644 index 00000000000000..f5bda8dadd6a09 --- /dev/null +++ b/test/fixtures/permission/hello-world.js @@ -0,0 +1 @@ +console.log('Hello world') \ No newline at end of file diff --git a/test/fixtures/permission/simple-loader.js b/test/fixtures/permission/simple-loader.js new file mode 100644 index 00000000000000..43e2a9bb77899b --- /dev/null +++ b/test/fixtures/permission/simple-loader.js @@ -0,0 +1,3 @@ +// Simulate a regular loading without fs operations +// but with access to Node core modules +require('node:fs') \ No newline at end of file diff --git a/test/fixtures/rc/duplicate-namespace-option/node.config.json b/test/fixtures/rc/duplicate-namespace-option/node.config.json new file mode 100644 index 00000000000000..4d948fbd33961d --- /dev/null +++ b/test/fixtures/rc/duplicate-namespace-option/node.config.json @@ -0,0 +1,6 @@ +{ + "testRunner": { + "test-name-pattern": "first-pattern", + "test-name-pattern": "second-pattern" + } +} diff --git a/test/fixtures/rc/empty-valid-namespace.json b/test/fixtures/rc/empty-valid-namespace.json new file mode 100644 index 00000000000000..dbeb33d7aa8b59 --- /dev/null +++ b/test/fixtures/rc/empty-valid-namespace.json @@ -0,0 +1,3 @@ +{ + "testRunner": {} +} diff --git a/test/fixtures/rc/namespace-with-array.json b/test/fixtures/rc/namespace-with-array.json new file mode 100644 index 00000000000000..056a4291e9b666 --- /dev/null +++ b/test/fixtures/rc/namespace-with-array.json @@ -0,0 +1,5 @@ +{ + "testRunner": { + "test-coverage-exclude": ["config-pattern1", "config-pattern2"] + } +} diff --git a/test/fixtures/rc/namespace-with-disallowed-envvar.json b/test/fixtures/rc/namespace-with-disallowed-envvar.json new file mode 100644 index 00000000000000..6152684e0583f4 --- /dev/null +++ b/test/fixtures/rc/namespace-with-disallowed-envvar.json @@ -0,0 +1,6 @@ +{ + "testRunner": { + "test-concurrency": 1, + "experimental-test-coverage": true + } +} diff --git a/test/fixtures/rc/namespaced/node.config.json b/test/fixtures/rc/namespaced/node.config.json new file mode 100644 index 00000000000000..df929d25c10b52 --- /dev/null +++ b/test/fixtures/rc/namespaced/node.config.json @@ -0,0 +1,5 @@ +{ + "testRunner": { + "test-isolation": "none" + } +} diff --git a/test/fixtures/rc/override-namespace.json b/test/fixtures/rc/override-namespace.json new file mode 100644 index 00000000000000..acb37b2eec485c --- /dev/null +++ b/test/fixtures/rc/override-namespace.json @@ -0,0 +1,8 @@ +{ + "testRunner": { + "test-isolation": "process" + }, + "nodeOptions": { + "test-isolation": "none" + } +} diff --git a/test/fixtures/rc/override-node-option-with-namespace.json b/test/fixtures/rc/override-node-option-with-namespace.json new file mode 100644 index 00000000000000..2db9e1a47f07ea --- /dev/null +++ b/test/fixtures/rc/override-node-option-with-namespace.json @@ -0,0 +1,8 @@ +{ + "nodeOptions": { + "test-isolation": "none" + }, + "testRunner": { + "test-isolation": "process" + } +} diff --git a/test/fixtures/rc/unknown-flag-namespace.json b/test/fixtures/rc/unknown-flag-namespace.json new file mode 100644 index 00000000000000..b5d87ad8dd3acd --- /dev/null +++ b/test/fixtures/rc/unknown-flag-namespace.json @@ -0,0 +1,5 @@ +{ + "testRunner": { + "unknown-flag": true + } +} diff --git a/test/fixtures/rc/unknown-namespace.json b/test/fixtures/rc/unknown-namespace.json new file mode 100644 index 00000000000000..14730d83efff73 --- /dev/null +++ b/test/fixtures/rc/unknown-namespace.json @@ -0,0 +1,5 @@ +{ + "an-invalid-namespace": { + "a-key": "a-value" + } +} diff --git a/test/fixtures/source-map/output/source_map_disabled_by_api.snapshot b/test/fixtures/source-map/output/source_map_disabled_by_api.snapshot index 655cd6695e1116..f538904873393e 100644 --- a/test/fixtures/source-map/output/source_map_disabled_by_api.snapshot +++ b/test/fixtures/source-map/output/source_map_disabled_by_api.snapshot @@ -1,12 +1,12 @@ Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionC (*enclosing-call-site-min.js:1:97) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionC (*/test/fixtures/source-map/enclosing-call-site-min.js:1:97) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) diff --git a/test/fixtures/source-map/output/source_map_disabled_by_process_api.snapshot b/test/fixtures/source-map/output/source_map_disabled_by_process_api.snapshot index 655cd6695e1116..f538904873393e 100644 --- a/test/fixtures/source-map/output/source_map_disabled_by_process_api.snapshot +++ b/test/fixtures/source-map/output/source_map_disabled_by_process_api.snapshot @@ -1,12 +1,12 @@ Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionC (*enclosing-call-site-min.js:1:97) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionC (*/test/fixtures/source-map/enclosing-call-site-min.js:1:97) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) diff --git a/test/fixtures/source-map/output/source_map_enabled_by_api.snapshot b/test/fixtures/source-map/output/source_map_enabled_by_api.snapshot index 082b3f310ed4f9..9fe43a29865b35 100644 --- a/test/fixtures/source-map/output/source_map_enabled_by_api.snapshot +++ b/test/fixtures/source-map/output/source_map_enabled_by_api.snapshot @@ -1,12 +1,12 @@ Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionC (*enclosing-call-site-min.js:1:97) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionC (*/test/fixtures/source-map/enclosing-call-site-min.js:1:97) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) diff --git a/test/fixtures/source-map/output/source_map_enabled_by_api_node_modules.snapshot b/test/fixtures/source-map/output/source_map_enabled_by_api_node_modules.snapshot index f46c21dbe42057..decc8ee3632f70 100644 --- a/test/fixtures/source-map/output/source_map_enabled_by_api_node_modules.snapshot +++ b/test/fixtures/source-map/output/source_map_enabled_by_api_node_modules.snapshot @@ -1,12 +1,12 @@ Error: an error! - at functionD (*node_modules*error-stack*enclosing-call-site.js:16:17) - at functionC (*node_modules*error-stack*enclosing-call-site.js:10:3) - at functionB (*node_modules*error-stack*enclosing-call-site.js:6:3) - at functionA (*node_modules*error-stack*enclosing-call-site.js:2:3) - at Object. (*node_modules*error-stack*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site.js:24:3) Error: an error! - at functionD (*node_modules*error-stack*enclosing-call-site-min.js:1:156) - at functionC (*node_modules*error-stack*enclosing-call-site-min.js:1:97) - at functionB (*node_modules*error-stack*enclosing-call-site-min.js:1:60) - at functionA (*node_modules*error-stack*enclosing-call-site-min.js:1:26) - at Object. (*node_modules*error-stack*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site-min.js:1:156) + at functionC (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site-min.js:1:97) + at functionB (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site-min.js:1:199) diff --git a/test/fixtures/source-map/output/source_map_enabled_by_process_api.snapshot b/test/fixtures/source-map/output/source_map_enabled_by_process_api.snapshot index 082b3f310ed4f9..9fe43a29865b35 100644 --- a/test/fixtures/source-map/output/source_map_enabled_by_process_api.snapshot +++ b/test/fixtures/source-map/output/source_map_enabled_by_process_api.snapshot @@ -1,12 +1,12 @@ Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionC (*enclosing-call-site-min.js:1:97) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionC (*/test/fixtures/source-map/enclosing-call-site-min.js:1:97) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) diff --git a/test/fixtures/source-map/output/source_map_enclosing_function.snapshot b/test/fixtures/source-map/output/source_map_enclosing_function.snapshot index 976cd4fdbbc6e9..b60f988be3214e 100644 --- a/test/fixtures/source-map/output/source_map_enclosing_function.snapshot +++ b/test/fixtures/source-map/output/source_map_enclosing_function.snapshot @@ -1,13 +1,13 @@ -*enclosing-call-site.js:26 +*/test/fixtures/source-map/enclosing-call-site.js:26 throw err ^ Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) Node.js * diff --git a/test/fixtures/source-map/output/source_map_eval.js b/test/fixtures/source-map/output/source_map_eval.js index 5492c179248180..6454096f58a5a6 100644 --- a/test/fixtures/source-map/output/source_map_eval.js +++ b/test/fixtures/source-map/output/source_map_eval.js @@ -6,5 +6,6 @@ Error.stackTraceLimit = 3; const fs = require('fs'); -const content = fs.readFileSync(require.resolve('../tabs.js'), 'utf8'); +const content = fs.readFileSync(require.resolve('../tabs-source-url.js'), 'utf8'); +// SourceURL magic comment is hardcoded in the source content. eval(content); diff --git a/test/fixtures/source-map/output/source_map_eval.snapshot b/test/fixtures/source-map/output/source_map_eval.snapshot index a4fcdb25282dfa..ff636e44063aa7 100644 --- a/test/fixtures/source-map/output/source_map_eval.snapshot +++ b/test/fixtures/source-map/output/source_map_eval.snapshot @@ -1,11 +1,11 @@ -*tabs.coffee:26 +*/synthesized/workspace/tabs-source-url.coffee:26 alert "I knew it!" ^ ReferenceError: alert is not defined - at Object.eval (*tabs.coffee:26:2) - at eval (*tabs.coffee:1:14) - at Object. (*output*source_map_eval.js:10:1) + at Object.eval (*/synthesized/workspace/tabs-source-url.coffee:26:2) + at eval (*/synthesized/workspace/tabs-source-url.coffee:1:14) + at Object. (*/test/fixtures/source-map/output/source_map_eval.js:11:1) Node.js * diff --git a/test/fixtures/source-map/output/source_map_no_source_file.snapshot b/test/fixtures/source-map/output/source_map_no_source_file.snapshot index cf9329747ba692..6d0e0cf6db727e 100644 --- a/test/fixtures/source-map/output/source_map_no_source_file.snapshot +++ b/test/fixtures/source-map/output/source_map_no_source_file.snapshot @@ -1,9 +1,9 @@ -*no-source.js:2 +*/test/fixtures/source-map/no-source.js:2 throw new Error('foo'); ^ Error: foo - at Throw (*file-not-exists.ts:2:9) - at Object. (*file-not-exists.ts:5:1) + at Throw (*/test/fixtures/source-map/file-not-exists.ts:2:9) + at Object. (*/test/fixtures/source-map/file-not-exists.ts:5:1) Node.js * diff --git a/test/fixtures/source-map/output/source_map_prepare_stack_trace.snapshot b/test/fixtures/source-map/output/source_map_prepare_stack_trace.snapshot index 9e9740a26fc34e..57bac36a2e5214 100644 --- a/test/fixtures/source-map/output/source_map_prepare_stack_trace.snapshot +++ b/test/fixtures/source-map/output/source_map_prepare_stack_trace.snapshot @@ -1,10 +1,10 @@ Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) diff --git a/test/fixtures/source-map/output/source_map_reference_error_tabs.snapshot b/test/fixtures/source-map/output/source_map_reference_error_tabs.snapshot index 97d02f176c0cb7..2043bd0a88e897 100644 --- a/test/fixtures/source-map/output/source_map_reference_error_tabs.snapshot +++ b/test/fixtures/source-map/output/source_map_reference_error_tabs.snapshot @@ -1,10 +1,10 @@ -*tabs.coffee:26 +*/test/fixtures/source-map/tabs.coffee:26 alert "I knew it!" ^ ReferenceError: alert is not defined - at Object. (*tabs.coffee:26:2) - at Object. (*tabs.coffee:1:14) + at Object. (*/test/fixtures/source-map/tabs.coffee:26:2) + at Object. (*/test/fixtures/source-map/tabs.coffee:1:14) Node.js * diff --git a/test/fixtures/source-map/output/source_map_sourcemapping_url_string.snapshot b/test/fixtures/source-map/output/source_map_sourcemapping_url_string.snapshot index 6a109c904e1155..52d4e6a28ee5ce 100644 --- a/test/fixtures/source-map/output/source_map_sourcemapping_url_string.snapshot +++ b/test/fixtures/source-map/output/source_map_sourcemapping_url_string.snapshot @@ -1,3 +1,3 @@ Error: an exception. - at Object. (*typescript-sourcemapping_url_string.ts:3:7) + at Object. (*/test/fixtures/source-map/typescript-sourcemapping_url_string.ts:3:7) * diff --git a/test/fixtures/source-map/output/source_map_throw_async_stack_trace.snapshot b/test/fixtures/source-map/output/source_map_throw_async_stack_trace.snapshot index 8f7f0490587585..f53aec68ce8bb3 100644 --- a/test/fixtures/source-map/output/source_map_throw_async_stack_trace.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_async_stack_trace.snapshot @@ -1,11 +1,11 @@ -*output*source_map_throw_async_stack_trace.mts:13 +*/test/fixtures/source-map/output/source_map_throw_async_stack_trace.mts:13 throw new Error('message') ^ Error: message - at Throw (*output*source_map_throw_async_stack_trace.mts:13:9) + at Throw (*/test/fixtures/source-map/output/source_map_throw_async_stack_trace.mts:13:9) at async Promise.all (index 3) - at async main (*output*source_map_throw_async_stack_trace.mts:17:3) + at async main (*/test/fixtures/source-map/output/source_map_throw_async_stack_trace.mts:17:3) Node.js * diff --git a/test/fixtures/source-map/output/source_map_throw_catch.snapshot b/test/fixtures/source-map/output/source_map_throw_catch.snapshot index 5eaffbfbf7874f..6e80e500c8cf17 100644 --- a/test/fixtures/source-map/output/source_map_throw_catch.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_catch.snapshot @@ -1,4 +1,4 @@ reachable Error: an exception - at branch (*typescript-throw.ts:18:11) - at Object. (*typescript-throw.ts:24:1) + at branch (*/test/fixtures/source-map/typescript-throw.ts:18:11) + at Object. (*/test/fixtures/source-map/typescript-throw.ts:24:1) diff --git a/test/fixtures/source-map/output/source_map_throw_construct.snapshot b/test/fixtures/source-map/output/source_map_throw_construct.snapshot index 8618d4b51a46ec..dc28053240aa0b 100644 --- a/test/fixtures/source-map/output/source_map_throw_construct.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_construct.snapshot @@ -1,11 +1,11 @@ -*output*source_map_throw_construct.mts:13 +*/test/fixtures/source-map/output/source_map_throw_construct.mts:13 throw new Error('message'); ^ Error: message - at new Foo (*output*source_map_throw_construct.mts:13:11) - at (*output*source_map_throw_construct.mts:17:1) + at new Foo (*/test/fixtures/source-map/output/source_map_throw_construct.mts:13:11) + at (*/test/fixtures/source-map/output/source_map_throw_construct.mts:17:1) * * * diff --git a/test/fixtures/source-map/output/source_map_throw_first_tick.snapshot b/test/fixtures/source-map/output/source_map_throw_first_tick.snapshot index fba8c95cc1103f..e129d73ef1581c 100644 --- a/test/fixtures/source-map/output/source_map_throw_first_tick.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_first_tick.snapshot @@ -1,11 +1,11 @@ reachable -*typescript-throw.ts:18 +*/test/fixtures/source-map/typescript-throw.ts:18 throw Error('an exception'); ^ Error: an exception - at branch (*typescript-throw.ts:18:11) - at Object. (*typescript-throw.ts:24:1) + at branch (*/test/fixtures/source-map/typescript-throw.ts:18:11) + at Object. (*/test/fixtures/source-map/typescript-throw.ts:24:1) Node.js * diff --git a/test/fixtures/source-map/output/source_map_throw_icu.snapshot b/test/fixtures/source-map/output/source_map_throw_icu.snapshot index 425495062e6423..4b2853479b9576 100644 --- a/test/fixtures/source-map/output/source_map_throw_icu.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_icu.snapshot @@ -1,10 +1,10 @@ -*icu.jsx:3 +*/test/fixtures/source-map/icu.jsx:3 ("あ 🐕 🐕", throw Error("an error")); ^ Error: an error - at Object.createElement (*icu.jsx:3:23) - at Object. (*icu.jsx:9:5) + at Object.createElement (*/test/fixtures/source-map/icu.jsx:3:23) + at Object. (*/test/fixtures/source-map/icu.jsx:9:5) Node.js * diff --git a/test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot b/test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot index ec9f1346ca5e0c..4cf4d52a16ea93 100644 --- a/test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot @@ -1,11 +1,11 @@ -*uglify-throw-original.js:5 +*/test/fixtures/source-map/uglify-throw-original.js:5 throw Error('goodbye'); ^ Error: goodbye - at Hello (*uglify-throw-original.js:5:9) - at Immediate. (*uglify-throw-original.js:9:3) + at Hello (*/test/fixtures/source-map/uglify-throw-original.js:5:9) + at Immediate. (*/test/fixtures/source-map/uglify-throw-original.js:9:3) * Node.js * diff --git a/test/fixtures/source-map/tabs-source-url.coffee b/test/fixtures/source-map/tabs-source-url.coffee new file mode 100644 index 00000000000000..7e73a605d32fc9 --- /dev/null +++ b/test/fixtures/source-map/tabs-source-url.coffee @@ -0,0 +1,34 @@ +# Assignment: +number = 42 +opposite = true + +# Conditions: +number = -42 if opposite + +# Functions: +square = (x) -> x * x + +# Arrays: +list = [1, 2, 3, 4, 5] + +# Objects: +math = + root: Math.sqrt + square: square + cube: (x) -> x * square x + +# Splats: +race = (winner, runners...) -> + print winner, runners + +# Existence: +if true + alert "I knew it!" + +# Array comprehensions: +cubes = (math.cube num for num in list) + +# To reproduce: +# cd test/fixtures/source-map +# npx --package=coffeescript@2.5.1 -- coffee -M --compile tabs-source-url.coffee +# sed -i -e "s/$(pwd | sed -e "s/\//\\\\\//g")/.\\/synthesized\\/workspace/g" tabs-source-url.js diff --git a/test/fixtures/source-map/tabs-source-url.js b/test/fixtures/source-map/tabs-source-url.js new file mode 100644 index 00000000000000..a4b43806a5f2f5 --- /dev/null +++ b/test/fixtures/source-map/tabs-source-url.js @@ -0,0 +1,61 @@ +// Generated by CoffeeScript 2.5.1 +(function() { + // Assignment: + var cubes, list, math, num, number, opposite, race, square; + + number = 42; + + opposite = true; + + if (opposite) { + // Conditions: + number = -42; + } + + // Functions: + square = function(x) { + return x * x; + }; + + // Arrays: + list = [1, 2, 3, 4, 5]; + + // Objects: + math = { + root: Math.sqrt, + square: square, + cube: function(x) { + return x * square(x); + } + }; + + // Splats: + race = function(winner, ...runners) { + return print(winner, runners); + }; + + // Existence: + if (true) { + alert("I knew it!"); + } + + // Array comprehensions: + cubes = (function() { + var i, len, results; + results = []; + for (i = 0, len = list.length; i < len; i++) { + num = list[i]; + results.push(math.cube(num)); + } + return results; + })(); + + // To reproduce: +// cd test/fixtures/source-map +// npx --package=coffeescript@2.5.1 -- coffee -M --compile tabs-source-url.coffee +// sed -i -e "s/$(pwd | sed -e "s/\//\\\\\//g")/.\\/synthesized\\/workspace/g" tabs-source-url.js + +}).call(this); + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy1zb3VyY2UtdXJsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidGFicy1zb3VyY2UtdXJsLmNvZmZlZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQWE7RUFBQTtBQUFBLE1BQUEsS0FBQSxFQUFBLElBQUEsRUFBQSxJQUFBLEVBQUEsR0FBQSxFQUFBLE1BQUEsRUFBQSxRQUFBLEVBQUEsSUFBQSxFQUFBOztFQUNiLE1BQUEsR0FBVzs7RUFDWCxRQUFBLEdBQVc7O0VBR1gsSUFBZ0IsUUFBaEI7O0lBQUEsTUFBQSxHQUFTLENBQUMsR0FBVjtHQUxhOzs7RUFRYixNQUFBLEdBQVMsUUFBQSxDQUFDLENBQUQsQ0FBQTtXQUFPLENBQUEsR0FBSTtFQUFYLEVBUkk7OztFQVdiLElBQUEsR0FBTyxDQUFDLENBQUQsRUFBSSxDQUFKLEVBQU8sQ0FBUCxFQUFVLENBQVYsRUFBYSxDQUFiLEVBWE07OztFQWNiLElBQUEsR0FDQztJQUFBLElBQUEsRUFBUSxJQUFJLENBQUMsSUFBYjtJQUNBLE1BQUEsRUFBUSxNQURSO0lBRUEsSUFBQSxFQUFRLFFBQUEsQ0FBQyxDQUFELENBQUE7YUFBTyxDQUFBLEdBQUksTUFBQSxDQUFPLENBQVA7SUFBWDtFQUZSLEVBZlk7OztFQW9CYixJQUFBLEdBQU8sUUFBQSxDQUFDLE1BQUQsRUFBQSxHQUFTLE9BQVQsQ0FBQTtXQUNOLEtBQUEsQ0FBTSxNQUFOLEVBQWMsT0FBZDtFQURNLEVBcEJNOzs7RUF3QmIsSUFBRyxJQUFIO0lBQ0MsS0FBQSxDQUFNLFlBQU4sRUFERDtHQXhCYTs7O0VBNEJiLEtBQUE7O0FBQVM7SUFBQSxLQUFBLHNDQUFBOzttQkFBQSxJQUFJLENBQUMsSUFBTCxDQUFVLEdBQVY7SUFBQSxDQUFBOzs7O0VBNUJJOzs7O0FBQUEiLCJzb3VyY2VzQ29udGVudCI6WyIjIEFzc2lnbm1lbnQ6XG5udW1iZXIgICA9IDQyXG5vcHBvc2l0ZSA9IHRydWVcblxuIyBDb25kaXRpb25zOlxubnVtYmVyID0gLTQyIGlmIG9wcG9zaXRlXG5cbiMgRnVuY3Rpb25zOlxuc3F1YXJlID0gKHgpIC0+IHggKiB4XG5cbiMgQXJyYXlzOlxubGlzdCA9IFsxLCAyLCAzLCA0LCA1XVxuXG4jIE9iamVjdHM6XG5tYXRoID1cblx0cm9vdDogICBNYXRoLnNxcnRcblx0c3F1YXJlOiBzcXVhcmVcblx0Y3ViZTogICAoeCkgLT4geCAqIHNxdWFyZSB4XG5cbiMgU3BsYXRzOlxucmFjZSA9ICh3aW5uZXIsIHJ1bm5lcnMuLi4pIC0+XG5cdHByaW50IHdpbm5lciwgcnVubmVyc1xuXG4jIEV4aXN0ZW5jZTpcbmlmIHRydWVcblx0YWxlcnQgXCJJIGtuZXcgaXQhXCJcblxuIyBBcnJheSBjb21wcmVoZW5zaW9uczpcbmN1YmVzID0gKG1hdGguY3ViZSBudW0gZm9yIG51bSBpbiBsaXN0KVxuXG4jIFRvIHJlcHJvZHVjZTpcbiMgY2QgdGVzdC9maXh0dXJlcy9zb3VyY2UtbWFwXG4jIG5weCAtLXBhY2thZ2U9Y29mZmVlc2NyaXB0QDIuNS4xIC0tIGNvZmZlZSAtTSAtLWNvbXBpbGUgdGFicy1zb3VyY2UtdXJsLmNvZmZlZVxuIyBzZWQgLWkgLWUgXCJzLyQocHdkIHwgc2VkIC1lIFwicy9cXC8vXFxcXFxcXFxcXC8vZ1wiKS8uXFxcXC9zeW50aGVzaXplZFxcXFwvd29ya3NwYWNlL2dcIiB0YWJzLXNvdXJjZS11cmwuanNcbiJdfQ== +//# sourceURL=./synthesized/workspace/tabs-source-url.coffee \ No newline at end of file diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index da4d33451375ad..ca6563e61c5e3a 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -23,7 +23,7 @@ Last update: - html/webappapis/microtask-queuing: https://github.com/web-platform-tests/wpt/tree/2c5c3c4c27/html/webappapis/microtask-queuing - html/webappapis/structured-clone: https://github.com/web-platform-tests/wpt/tree/47d3fb280c/html/webappapis/structured-clone - html/webappapis/timers: https://github.com/web-platform-tests/wpt/tree/5873f2d8f1/html/webappapis/timers -- interfaces: https://github.com/web-platform-tests/wpt/tree/e90ece61d6/interfaces +- interfaces: https://github.com/web-platform-tests/wpt/tree/e1b27be06b/interfaces - performance-timeline: https://github.com/web-platform-tests/wpt/tree/94caab7038/performance-timeline - resource-timing: https://github.com/web-platform-tests/wpt/tree/22d38586d0/resource-timing - resources: https://github.com/web-platform-tests/wpt/tree/1e140d63ec/resources @@ -33,7 +33,7 @@ Last update: - user-timing: https://github.com/web-platform-tests/wpt/tree/5ae85bf826/user-timing - wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/cde25e7e3c/wasm/jsapi - wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi -- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/b48efd681e/WebCryptoAPI +- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/591c95ce61/WebCryptoAPI - webidl/ecmascript-binding/es-exceptions: https://github.com/web-platform-tests/wpt/tree/a370aad338/webidl/ecmascript-binding/es-exceptions - webmessaging/broadcastchannel: https://github.com/web-platform-tests/wpt/tree/6495c91853/webmessaging/broadcastchannel - webstorage: https://github.com/web-platform-tests/wpt/tree/1291340aaa/webstorage diff --git a/test/fixtures/wpt/WebCryptoAPI/idlharness.https.any.js b/test/fixtures/wpt/WebCryptoAPI/idlharness.https.any.js index ae65eb49f2120e..5ddf7eab6dba21 100644 --- a/test/fixtures/wpt/WebCryptoAPI/idlharness.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/idlharness.https.any.js @@ -5,7 +5,7 @@ // https://w3c.github.io/webcrypto/Overview.html idl_test( - ['WebCryptoAPI'], + ['webcrypto'], ['html', 'dom'], idl_array => { idl_array.add_objects({ diff --git a/test/fixtures/wpt/interfaces/dom.idl b/test/fixtures/wpt/interfaces/dom.idl index 72d61f5cfd80ad..253e7bf913eba9 100644 --- a/test/fixtures/wpt/interfaces/dom.idl +++ b/test/fixtures/wpt/interfaces/dom.idl @@ -110,6 +110,7 @@ Document includes NonElementParentNode; DocumentFragment includes NonElementParentNode; interface mixin DocumentOrShadowRoot { + readonly attribute CustomElementRegistry? customElementRegistry; }; Document includes DocumentOrShadowRoot; ShadowRoot includes DocumentOrShadowRoot; @@ -120,9 +121,11 @@ interface mixin ParentNode { readonly attribute Element? lastElementChild; readonly attribute unsigned long childElementCount; - [CEReactions, Unscopable] undefined prepend((Node or TrustedScript or DOMString)... nodes); - [CEReactions, Unscopable] undefined append((Node or TrustedScript or DOMString)... nodes); - [CEReactions, Unscopable] undefined replaceChildren((Node or TrustedScript or DOMString)... nodes); + [CEReactions, Unscopable] undefined prepend((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined append((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined replaceChildren((Node or DOMString)... nodes); + + [CEReactions] undefined moveBefore(Node node, Node? child); Element? querySelector(DOMString selectors); [NewObject] NodeList querySelectorAll(DOMString selectors); @@ -139,9 +142,9 @@ Element includes NonDocumentTypeChildNode; CharacterData includes NonDocumentTypeChildNode; interface mixin ChildNode { - [CEReactions, Unscopable] undefined before((Node or TrustedScript or DOMString)... nodes); - [CEReactions, Unscopable] undefined after((Node or TrustedScript or DOMString)... nodes); - [CEReactions, Unscopable] undefined replaceWith((Node or TrustedScript or DOMString)... nodes); + [CEReactions, Unscopable] undefined before((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined after((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined replaceWith((Node or DOMString)... nodes); [CEReactions, Unscopable] undefined remove(); }; DocumentType includes ChildNode; @@ -237,7 +240,7 @@ interface Node : EventTarget { [CEReactions] attribute DOMString? textContent; [CEReactions] undefined normalize(); - [CEReactions, NewObject] Node cloneNode(optional boolean deep = false); + [CEReactions, NewObject] Node cloneNode(optional boolean subtree = false); boolean isEqualNode(Node? otherNode); boolean isSameNode(Node? otherNode); // legacy alias of === @@ -291,7 +294,7 @@ interface Document : Node { [NewObject] Comment createComment(DOMString data); [NewObject] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data); - [CEReactions, NewObject] Node importNode(Node node, optional boolean deep = false); + [CEReactions, NewObject] Node importNode(Node node, optional (boolean or ImportNodeOptions) options = false); [CEReactions] Node adoptNode(Node node); [NewObject] Attr createAttribute(DOMString localName); @@ -310,9 +313,15 @@ interface Document : Node { interface XMLDocument : Document {}; dictionary ElementCreationOptions { + CustomElementRegistry customElementRegistry; DOMString is; }; +dictionary ImportNodeOptions { + CustomElementRegistry customElementRegistry; + boolean selfOnly = false; +}; + [Exposed=Window] interface DOMImplementation { [NewObject] DocumentType createDocumentType(DOMString qualifiedName, DOMString publicId, DOMString systemId); @@ -342,6 +351,7 @@ interface ShadowRoot : DocumentFragment { readonly attribute boolean clonable; readonly attribute boolean serializable; readonly attribute Element host; + attribute EventHandler onslotchange; }; @@ -382,6 +392,8 @@ interface Element : Node { ShadowRoot attachShadow(ShadowRootInit init); readonly attribute ShadowRoot? shadowRoot; + readonly attribute CustomElementRegistry? customElementRegistry; + Element? closest(DOMString selectors); boolean matches(DOMString selectors); boolean webkitMatchesSelector(DOMString selectors); // legacy alias of .matches @@ -400,6 +412,7 @@ dictionary ShadowRootInit { SlotAssignmentMode slotAssignment = "named"; boolean clonable = false; boolean serializable = false; + CustomElementRegistry customElementRegistry; }; [Exposed=Window, diff --git a/test/fixtures/wpt/interfaces/html.idl b/test/fixtures/wpt/interfaces/html.idl index 4d6c0229bc1392..9c84e6a67efa4f 100644 --- a/test/fixtures/wpt/interfaces/html.idl +++ b/test/fixtures/wpt/interfaces/html.idl @@ -125,6 +125,7 @@ interface HTMLElement : Element { [CEReactions] attribute boolean spellcheck; [CEReactions] attribute DOMString writingSuggestions; [CEReactions] attribute DOMString autocapitalize; + [CEReactions] attribute boolean autocorrect; [CEReactions] attribute [LegacyNullToEmptyString] DOMString innerText; [CEReactions] attribute [LegacyNullToEmptyString] DOMString outerText; @@ -132,12 +133,20 @@ interface HTMLElement : Element { ElementInternals attachInternals(); // The popover API - undefined showPopover(); + undefined showPopover(optional ShowPopoverOptions options = {}); undefined hidePopover(); - boolean togglePopover(optional boolean force); + boolean togglePopover(optional (TogglePopoverOptions or boolean) options = {}); [CEReactions] attribute DOMString? popover; }; +dictionary ShowPopoverOptions { + HTMLElement source; +}; + +dictionary TogglePopoverOptions : ShowPopoverOptions { + boolean force; +}; + HTMLElement includes GlobalEventHandlers; HTMLElement includes ElementContentEditable; HTMLElement includes HTMLOrSVGElement; @@ -880,10 +889,12 @@ interface HTMLInputElement : HTMLElement { [HTMLConstructor] constructor(); [CEReactions] attribute DOMString accept; + [CEReactions] attribute boolean alpha; [CEReactions] attribute DOMString alt; [CEReactions] attribute DOMString autocomplete; [CEReactions] attribute boolean defaultChecked; attribute boolean checked; + [CEReactions] attribute DOMString colorSpace; [CEReactions] attribute DOMString dirName; [CEReactions] attribute boolean disabled; readonly attribute HTMLFormElement? form; @@ -946,6 +957,8 @@ HTMLInputElement includes PopoverInvokerElement; interface HTMLButtonElement : HTMLElement { [HTMLConstructor] constructor(); + [CEReactions] attribute DOMString command; + [CEReactions] attribute Element? commandForElement; [CEReactions] attribute boolean disabled; readonly attribute HTMLFormElement? form; [CEReactions] attribute USVString formAction; @@ -1211,9 +1224,11 @@ interface HTMLDialogElement : HTMLElement { [CEReactions] attribute boolean open; attribute DOMString returnValue; + [CEReactions] attribute DOMString closedBy; [CEReactions] undefined show(); [CEReactions] undefined showModal(); [CEReactions] undefined close(optional DOMString returnValue); + [CEReactions] undefined requestClose(optional DOMString returnValue); }; [Exposed=Window] @@ -1246,6 +1261,7 @@ interface HTMLTemplateElement : HTMLElement { [CEReactions] attribute boolean shadowRootDelegatesFocus; [CEReactions] attribute boolean shadowRootClonable; [CEReactions] attribute boolean shadowRootSerializable; + [CEReactions] attribute DOMString shadowRootCustomElementRegistry; }; [Exposed=Window] @@ -1292,12 +1308,15 @@ typedef (HTMLOrSVGImageElement or enum PredefinedColorSpace { "srgb", "display-p3" }; +enum CanvasColorType { "unorm8", "float16" }; + enum CanvasFillRule { "nonzero", "evenodd" }; dictionary CanvasRenderingContext2DSettings { boolean alpha = true; boolean desynchronized = false; PredefinedColorSpace colorSpace = "srgb"; + CanvasColorType colorType = "unorm8"; boolean willReadFrequently = false; }; @@ -1307,9 +1326,8 @@ enum ImageSmoothingQuality { "low", "medium", "high" }; interface CanvasRenderingContext2D { // back-reference to the canvas readonly attribute HTMLCanvasElement canvas; - - CanvasRenderingContext2DSettings getContextAttributes(); }; +CanvasRenderingContext2D includes CanvasSettings; CanvasRenderingContext2D includes CanvasState; CanvasRenderingContext2D includes CanvasTransform; CanvasRenderingContext2D includes CanvasCompositing; @@ -1327,6 +1345,11 @@ CanvasRenderingContext2D includes CanvasPathDrawingStyles; CanvasRenderingContext2D includes CanvasTextDrawingStyles; CanvasRenderingContext2D includes CanvasPath; +interface mixin CanvasSettings { + // settings + CanvasRenderingContext2DSettings getContextAttributes(); +}; + interface mixin CanvasState { // state undefined save(); // push state on state stack @@ -1411,8 +1434,6 @@ interface mixin CanvasDrawPath { interface mixin CanvasUserInterface { undefined drawFocusIfNeeded(Element element); undefined drawFocusIfNeeded(Path2D path, Element element); - undefined scrollPathIntoView(); - undefined scrollPathIntoView(Path2D path); }; interface mixin CanvasText { @@ -1432,10 +1453,10 @@ interface mixin CanvasDrawImage { interface mixin CanvasImageData { // pixel manipulation ImageData createImageData([EnforceRange] long sw, [EnforceRange] long sh, optional ImageDataSettings settings = {}); - ImageData createImageData(ImageData imagedata); + ImageData createImageData(ImageData imageData); ImageData getImageData([EnforceRange] long sx, [EnforceRange] long sy, [EnforceRange] long sw, [EnforceRange] long sh, optional ImageDataSettings settings = {}); - undefined putImageData(ImageData imagedata, [EnforceRange] long dx, [EnforceRange] long dy); - undefined putImageData(ImageData imagedata, [EnforceRange] long dx, [EnforceRange] long dy, [EnforceRange] long dirtyX, [EnforceRange] long dirtyY, [EnforceRange] long dirtyWidth, [EnforceRange] long dirtyHeight); + undefined putImageData(ImageData imageData, [EnforceRange] long dx, [EnforceRange] long dy); + undefined putImageData(ImageData imageData, [EnforceRange] long dx, [EnforceRange] long dy, [EnforceRange] long dirtyX, [EnforceRange] long dirtyY, [EnforceRange] long dirtyWidth, [EnforceRange] long dirtyHeight); }; enum CanvasLineCap { "butt", "round", "square" }; @@ -1463,6 +1484,7 @@ interface mixin CanvasPathDrawingStyles { interface mixin CanvasTextDrawingStyles { // text + attribute DOMString lang; // (default: "inherit") attribute DOMString font; // (default 10px sans-serif) attribute CanvasTextAlign textAlign; // (default: "start") attribute CanvasTextBaseline textBaseline; // (default: "alphabetic") @@ -1520,22 +1542,6 @@ interface TextMetrics { readonly attribute double ideographicBaseline; }; -dictionary ImageDataSettings { - PredefinedColorSpace colorSpace; -}; - -[Exposed=(Window,Worker), - Serializable] -interface ImageData { - constructor(unsigned long sw, unsigned long sh, optional ImageDataSettings settings = {}); - constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings = {}); - - readonly attribute unsigned long width; - readonly attribute unsigned long height; - readonly attribute Uint8ClampedArray data; - readonly attribute PredefinedColorSpace colorSpace; -}; - [Exposed=(Window,Worker)] interface Path2D { constructor(optional (Path2D or DOMString) path); @@ -1583,6 +1589,7 @@ interface OffscreenCanvasRenderingContext2D { readonly attribute OffscreenCanvas canvas; }; +OffscreenCanvasRenderingContext2D includes CanvasSettings; OffscreenCanvasRenderingContext2D includes CanvasState; OffscreenCanvasRenderingContext2D includes CanvasTransform; OffscreenCanvasRenderingContext2D includes CanvasCompositing; @@ -1601,11 +1608,14 @@ OffscreenCanvasRenderingContext2D includes CanvasPath; [Exposed=Window] interface CustomElementRegistry { + constructor(); + [CEReactions] undefined define(DOMString name, CustomElementConstructor constructor, optional ElementDefinitionOptions options = {}); (CustomElementConstructor or undefined) get(DOMString name); DOMString? getName(CustomElementConstructor constructor); Promise whenDefined(DOMString name); [CEReactions] undefined upgrade(Node root); + undefined initialize(Node root); }; callback CustomElementConstructor = HTMLElement (); @@ -1691,6 +1701,18 @@ dictionary ToggleEventInit : EventInit { DOMString newState = ""; }; +[Exposed=Window] +interface CommandEvent : Event { + constructor(DOMString type, optional CommandEventInit eventInitDict = {}); + readonly attribute Element? source; + readonly attribute DOMString command; +}; + +dictionary CommandEventInit : EventInit { + Element? source = null; + DOMString command = ""; +}; + dictionary FocusOptions { boolean preventScroll = false; boolean focusVisible; @@ -1976,6 +1998,7 @@ interface NavigateEvent : Event { readonly attribute DOMString? downloadRequest; readonly attribute any info; readonly attribute boolean hasUAVisualTransition; + readonly attribute Element? sourceElement; undefined intercept(optional NavigationInterceptOptions options = {}); undefined scroll(); @@ -1992,6 +2015,7 @@ dictionary NavigateEventInit : EventInit { DOMString? downloadRequest = null; any info; boolean hasUAVisualTransition = false; + Element? sourceElement = null; }; dictionary NavigationInterceptOptions { @@ -2108,10 +2132,10 @@ interface NotRestoredReasonDetails { [Exposed=Window] interface NotRestoredReasons { - readonly attribute DOMString? src; + readonly attribute USVString? src; readonly attribute DOMString? id; readonly attribute DOMString? name; - readonly attribute DOMString? url; + readonly attribute USVString? url; readonly attribute FrozenArray? reasons; readonly attribute FrozenArray? children; [Default] object toJSON(); @@ -2174,6 +2198,7 @@ interface mixin GlobalEventHandlers { attribute EventHandler onchange; attribute EventHandler onclick; attribute EventHandler onclose; + attribute EventHandler oncommand; attribute EventHandler oncontextlost; attribute EventHandler oncontextmenu; attribute EventHandler oncontextrestored; @@ -2332,6 +2357,13 @@ partial interface Range { [CEReactions, NewObject] DocumentFragment createContextualFragment((TrustedHTML or DOMString) string); }; +[Exposed=Window] +interface XMLSerializer { + constructor(); + + DOMString serializeToString(Node root); +}; + [Exposed=Window] interface Navigator { // objects implementing this interface also implement the interfaces given below @@ -2422,6 +2454,28 @@ interface MimeType { readonly attribute Plugin enabledPlugin; }; +typedef (Uint8ClampedArray or Float16Array) ImageDataArray; + +enum ImageDataPixelFormat { "rgba-unorm8", "rgba-float16" }; + +dictionary ImageDataSettings { + PredefinedColorSpace colorSpace; + ImageDataPixelFormat pixelFormat = "rgba-unorm8"; +}; + +[Exposed=(Window,Worker), + Serializable] +interface ImageData { + constructor(unsigned long sw, unsigned long sh, optional ImageDataSettings settings = {}); + constructor(ImageDataArray data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings = {}); + + readonly attribute unsigned long width; + readonly attribute unsigned long height; + readonly attribute ImageDataArray data; + readonly attribute ImageDataPixelFormat pixelFormat; + readonly attribute PredefinedColorSpace colorSpace; +}; + [Exposed=(Window,Worker), Serializable, Transferable] interface ImageBitmap { readonly attribute unsigned long width; @@ -2511,6 +2565,11 @@ interface MessageChannel { readonly attribute MessagePort port2; }; +interface mixin MessageEventTarget { + attribute EventHandler onmessage; + attribute EventHandler onmessageerror; +}; + [Exposed=(Window,Worker,AudioWorklet), Transferable] interface MessagePort : EventTarget { undefined postMessage(any message, sequence transfer); @@ -2519,11 +2578,11 @@ interface MessagePort : EventTarget { undefined close(); // event handlers - attribute EventHandler onmessage; - attribute EventHandler onmessageerror; attribute EventHandler onclose; }; +MessagePort includes MessageEventTarget; + dictionary StructuredSerializeOptions { sequence transfer = []; }; @@ -2562,11 +2621,10 @@ interface DedicatedWorkerGlobalScope : WorkerGlobalScope { undefined postMessage(any message, optional StructuredSerializeOptions options = {}); undefined close(); - - attribute EventHandler onmessage; - attribute EventHandler onmessageerror; }; +DedicatedWorkerGlobalScope includes MessageEventTarget; + [Global=(Worker,SharedWorker),Exposed=SharedWorker] interface SharedWorkerGlobalScope : WorkerGlobalScope { [Replaceable] readonly attribute DOMString name; @@ -2588,8 +2646,6 @@ interface Worker : EventTarget { undefined postMessage(any message, sequence transfer); undefined postMessage(any message, optional StructuredSerializeOptions options = {}); - attribute EventHandler onmessage; - attribute EventHandler onmessageerror; }; dictionary WorkerOptions { @@ -2601,6 +2657,7 @@ dictionary WorkerOptions { enum WorkerType { "classic", "module" }; Worker includes AbstractWorker; +Worker includes MessageEventTarget; [Exposed=Window] interface SharedWorker : EventTarget { diff --git a/test/fixtures/wpt/interfaces/resource-timing.idl b/test/fixtures/wpt/interfaces/resource-timing.idl index 33fed05b756838..66f2841d744af3 100644 --- a/test/fixtures/wpt/interfaces/resource-timing.idl +++ b/test/fixtures/wpt/interfaces/resource-timing.idl @@ -18,6 +18,7 @@ interface PerformanceResourceTiming : PerformanceEntry { readonly attribute DOMHighResTimeStamp connectEnd; readonly attribute DOMHighResTimeStamp secureConnectionStart; readonly attribute DOMHighResTimeStamp requestStart; + readonly attribute DOMHighResTimeStamp finalResponseHeadersStart; readonly attribute DOMHighResTimeStamp firstInterimResponseStart; readonly attribute DOMHighResTimeStamp responseStart; readonly attribute DOMHighResTimeStamp responseEnd; diff --git a/test/fixtures/wpt/interfaces/urlpattern.idl b/test/fixtures/wpt/interfaces/urlpattern.idl new file mode 100644 index 00000000000000..ca9fb979d22939 --- /dev/null +++ b/test/fixtures/wpt/interfaces/urlpattern.idl @@ -0,0 +1,63 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into webref +// (https://github.com/w3c/webref) +// Source: URL Pattern Standard (https://urlpattern.spec.whatwg.org/) + +typedef (USVString or URLPatternInit) URLPatternInput; + +[Exposed=(Window,Worker)] +interface URLPattern { + constructor(URLPatternInput input, USVString baseURL, optional URLPatternOptions options = {}); + constructor(optional URLPatternInput input = {}, optional URLPatternOptions options = {}); + + boolean test(optional URLPatternInput input = {}, optional USVString baseURL); + + URLPatternResult? exec(optional URLPatternInput input = {}, optional USVString baseURL); + + readonly attribute USVString protocol; + readonly attribute USVString username; + readonly attribute USVString password; + readonly attribute USVString hostname; + readonly attribute USVString port; + readonly attribute USVString pathname; + readonly attribute USVString search; + readonly attribute USVString hash; + + readonly attribute boolean hasRegExpGroups; +}; + +dictionary URLPatternInit { + USVString protocol; + USVString username; + USVString password; + USVString hostname; + USVString port; + USVString pathname; + USVString search; + USVString hash; + USVString baseURL; +}; + +dictionary URLPatternOptions { + boolean ignoreCase = false; +}; + +dictionary URLPatternResult { + sequence inputs; + + URLPatternComponentResult protocol; + URLPatternComponentResult username; + URLPatternComponentResult password; + URLPatternComponentResult hostname; + URLPatternComponentResult port; + URLPatternComponentResult pathname; + URLPatternComponentResult search; + URLPatternComponentResult hash; +}; + +dictionary URLPatternComponentResult { + USVString input; + record groups; +}; + +typedef (USVString or URLPatternInit or URLPattern) URLPatternCompatible; diff --git a/test/fixtures/wpt/interfaces/user-timing.idl b/test/fixtures/wpt/interfaces/user-timing.idl index 28ee8aac2b19a6..fc6d30822588b1 100644 --- a/test/fixtures/wpt/interfaces/user-timing.idl +++ b/test/fixtures/wpt/interfaces/user-timing.idl @@ -1,7 +1,7 @@ // GENERATED CONTENT - DO NOT EDIT // Content was automatically extracted by Reffy into webref // (https://github.com/w3c/webref) -// Source: User Timing Level 3 (https://w3c.github.io/user-timing/) +// Source: User Timing (https://w3c.github.io/user-timing/) dictionary PerformanceMarkOptions { any detail; diff --git a/test/fixtures/wpt/interfaces/WebCryptoAPI.idl b/test/fixtures/wpt/interfaces/webcrypto.idl similarity index 67% rename from test/fixtures/wpt/interfaces/WebCryptoAPI.idl rename to test/fixtures/wpt/interfaces/webcrypto.idl index ae85c1cfe4684f..ff7a89cd0d51be 100644 --- a/test/fixtures/wpt/interfaces/WebCryptoAPI.idl +++ b/test/fixtures/wpt/interfaces/webcrypto.idl @@ -42,52 +42,77 @@ enum KeyFormat { "raw", "spki", "pkcs8", "jwk" }; [SecureContext,Exposed=(Window,Worker)] interface SubtleCrypto { - Promise encrypt(AlgorithmIdentifier algorithm, - CryptoKey key, - BufferSource data); - Promise decrypt(AlgorithmIdentifier algorithm, - CryptoKey key, - BufferSource data); - Promise sign(AlgorithmIdentifier algorithm, - CryptoKey key, - BufferSource data); - Promise verify(AlgorithmIdentifier algorithm, - CryptoKey key, - BufferSource signature, - BufferSource data); - Promise digest(AlgorithmIdentifier algorithm, - BufferSource data); - - Promise generateKey(AlgorithmIdentifier algorithm, - boolean extractable, - sequence keyUsages ); - Promise deriveKey(AlgorithmIdentifier algorithm, - CryptoKey baseKey, - AlgorithmIdentifier derivedKeyType, - boolean extractable, - sequence keyUsages ); - Promise deriveBits(AlgorithmIdentifier algorithm, - CryptoKey baseKey, - optional unsigned long? length = null); - - Promise importKey(KeyFormat format, - (BufferSource or JsonWebKey) keyData, - AlgorithmIdentifier algorithm, - boolean extractable, - sequence keyUsages ); - Promise exportKey(KeyFormat format, CryptoKey key); - - Promise wrapKey(KeyFormat format, - CryptoKey key, - CryptoKey wrappingKey, - AlgorithmIdentifier wrapAlgorithm); - Promise unwrapKey(KeyFormat format, - BufferSource wrappedKey, - CryptoKey unwrappingKey, - AlgorithmIdentifier unwrapAlgorithm, - AlgorithmIdentifier unwrappedKeyAlgorithm, - boolean extractable, - sequence keyUsages ); + Promise encrypt( + AlgorithmIdentifier algorithm, + CryptoKey key, + BufferSource data + ); + Promise decrypt( + AlgorithmIdentifier algorithm, + CryptoKey key, + BufferSource data + ); + Promise sign( + AlgorithmIdentifier algorithm, + CryptoKey key, + BufferSource data + ); + Promise verify( + AlgorithmIdentifier algorithm, + CryptoKey key, + BufferSource signature, + BufferSource data + ); + Promise digest( + AlgorithmIdentifier algorithm, + BufferSource data + ); + + Promise<(CryptoKey or CryptoKeyPair)> generateKey( + AlgorithmIdentifier algorithm, + boolean extractable, + sequence keyUsages + ); + Promise deriveKey( + AlgorithmIdentifier algorithm, + CryptoKey baseKey, + AlgorithmIdentifier derivedKeyType, + boolean extractable, + sequence keyUsages + ); + Promise deriveBits( + AlgorithmIdentifier algorithm, + CryptoKey baseKey, + optional unsigned long? length = null + ); + + Promise importKey( + KeyFormat format, + (BufferSource or JsonWebKey) keyData, + AlgorithmIdentifier algorithm, + boolean extractable, + sequence keyUsages + ); + Promise<(ArrayBuffer or JsonWebKey)> exportKey( + KeyFormat format, + CryptoKey key + ); + + Promise wrapKey( + KeyFormat format, + CryptoKey key, + CryptoKey wrappingKey, + AlgorithmIdentifier wrapAlgorithm + ); + Promise unwrapKey( + KeyFormat format, + BufferSource wrappedKey, + CryptoKey unwrappingKey, + AlgorithmIdentifier unwrapAlgorithm, + AlgorithmIdentifier unwrappedKeyAlgorithm, + boolean extractable, + sequence keyUsages + ); }; dictionary RsaOtherPrimesInfo { diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index 518e343c935174..97b60395f4924f 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -52,7 +52,7 @@ "path": "html/webappapis/timers" }, "interfaces": { - "commit": "e90ece61d6e7ff84a0dc9c496588690e6a61cb17", + "commit": "e1b27be06b43787a001b7297c4e0fabdd276560f", "path": "interfaces" }, "performance-timeline": { @@ -92,7 +92,7 @@ "path": "wasm/webapi" }, "WebCryptoAPI": { - "commit": "b48efd681ea3a5b0daa6b866c3bb54bec895037b", + "commit": "591c95ce6174690b92833cd92859ce2807714591", "path": "WebCryptoAPI" }, "webidl/ecmascript-binding/es-exceptions": { diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status index 887a626a98b813..e612653d45c3c8 100644 --- a/test/parallel/parallel.status +++ b/test/parallel/parallel.status @@ -41,6 +41,10 @@ test-esm-loader-hooks-inspect-wait: PASS, FLAKY # https://github.com/nodejs/node/issues/54534 test-runner-run-watch: PASS, FLAKY +[$system==linux && $arch==s390x] +# https://github.com/nodejs/node/issues/58353 +test-http2-debug: PASS, FLAKY + [$system==linux || $system==win32] # https://github.com/nodejs/node/issues/49605 test-runner-watch-mode: PASS,FLAKY @@ -119,6 +123,14 @@ test-tls-client-mindhsize: PASS, FLAKY test-tls-write-error: PASS, FLAKY # https://github.com/nodejs/node/issues/48047 test-http-pipeline-flood: SKIP +# https://github.com/nodejs/node/issues/58582 +test-http-proxy-fetch: PASS, FLAKY +test-https-proxy-fetch: PASS, FLAKY +test-inspector-network-fetch: PASS, FLAKY +test-fetch: PASS, FLAKY +test-without-async-context-frame: PASS, FLAKY +test-process-cpuUsage: PASS, FLAKY + [$asan==on] # https://github.com/nodejs/node/issues/39655 diff --git a/test/parallel/test-binding-constants.js b/test/parallel/test-binding-constants.js index 4a96b7c7443fc6..d57899be50642b 100644 --- a/test/parallel/test-binding-constants.js +++ b/test/parallel/test-binding-constants.js @@ -7,7 +7,7 @@ const constants = internalBinding('constants'); const assert = require('assert'); assert.deepStrictEqual( - Object.keys(constants).sort(), ['crypto', 'fs', 'os', 'trace', 'zlib'] + Object.keys(constants).sort(), ['crypto', 'fs', 'internal', 'os', 'trace', 'zlib'] ); assert.deepStrictEqual( @@ -28,6 +28,6 @@ function test(obj) { } [ - constants, constants.crypto, constants.fs, constants.os, constants.trace, + constants, constants.crypto, constants.fs, constants.internal, constants.os, constants.trace, constants.zlib, constants.os.dlopen, constants.os.errno, constants.os.signals, ].forEach(test); diff --git a/test/parallel/test-buffer-tostring-4gb.js b/test/parallel/test-buffer-tostring-4gb.js new file mode 100644 index 00000000000000..8ab102e559dad9 --- /dev/null +++ b/test/parallel/test-buffer-tostring-4gb.js @@ -0,0 +1,20 @@ +'use strict'; + +// This tests that Buffer.prototype.toString() works with buffers over 4GB. +const common = require('../common'); + +// Must not throw when start and end are within kMaxLength +// Cannot test on 32bit machine as we are testing the case +// when start and end are above the threshold +common.skipIf32Bits(); +const threshold = 0xFFFFFFFF; // 2^32 - 1 +let largeBuffer; +try { + largeBuffer = Buffer.alloc(threshold + 20); +} catch (e) { + if (e.code === 'ERR_MEMORY_ALLOCATION_FAILED' || /Array buffer allocation failed/.test(e.message)) { + common.skip('insufficient space for Buffer.alloc'); + } + throw e; +} +largeBuffer.toString('utf8', threshold, threshold + 20); diff --git a/test/parallel/test-buffer-tostring-range.js b/test/parallel/test-buffer-tostring-range.js index d033cd204b3200..f4adf64c8d9129 100644 --- a/test/parallel/test-buffer-tostring-range.js +++ b/test/parallel/test-buffer-tostring-range.js @@ -1,6 +1,6 @@ 'use strict'; -const common = require('../common'); +require('../common'); const assert = require('assert'); const rangeBuffer = Buffer.from('abc'); @@ -98,11 +98,3 @@ assert.throws(() => { name: 'TypeError', message: 'Unknown encoding: null' }); - -// Must not throw when start and end are within kMaxLength -// Cannot test on 32bit machine as we are testing the case -// when start and end are above the threshold -common.skipIf32Bits(); -const threshold = 0xFFFFFFFF; -const largeBuffer = Buffer.alloc(threshold + 20); -largeBuffer.toString('utf8', threshold, threshold + 20); diff --git a/test/parallel/test-buffer-tostring-rangeerror.js b/test/parallel/test-buffer-tostring-rangeerror.js index 2c6094263547e1..52fd3ffa1d4959 100644 --- a/test/parallel/test-buffer-tostring-rangeerror.js +++ b/test/parallel/test-buffer-tostring-rangeerror.js @@ -23,8 +23,22 @@ const message = { code: 'ERR_STRING_TOO_LONG', name: 'Error', }; -assert.throws(() => Buffer(len).toString('utf8'), message); -assert.throws(() => SlowBuffer(len).toString('utf8'), message); -assert.throws(() => Buffer.alloc(len).toString('utf8'), message); -assert.throws(() => Buffer.allocUnsafe(len).toString('utf8'), message); -assert.throws(() => Buffer.allocUnsafeSlow(len).toString('utf8'), message); + +function test(getBuffer) { + let buf; + try { + buf = getBuffer(); + } catch (e) { + // If the buffer allocation fails, we skip the test. + if (e.code === 'ERR_MEMORY_ALLOCATION_FAILED' || /Array buffer allocation failed/.test(e.message)) { + return; + } + } + assert.throws(() => { buf.toString('utf8'); }, message); +} + +test(() => Buffer(len)); +test(() => SlowBuffer(len)); +test(() => Buffer.alloc(len)); +test(() => Buffer.allocUnsafe(len)); +test(() => Buffer.allocUnsafeSlow(len)); diff --git a/test/parallel/test-child-process-spawn-args.js b/test/parallel/test-child-process-spawn-args.js deleted file mode 100644 index ec56f409faf2a9..00000000000000 --- a/test/parallel/test-child-process-spawn-args.js +++ /dev/null @@ -1,55 +0,0 @@ -'use strict'; - -// This test confirms that `undefined`, `null`, and `[]` -// can be used as a placeholder for the second argument (`args`) of `spawn()`. -// Previously, there was a bug where using `undefined` for the second argument -// caused the third argument (`options`) to be ignored. -// See https://github.com/nodejs/node/issues/24912. - -const common = require('../common'); -const tmpdir = require('../common/tmpdir'); - -const assert = require('assert'); -const { spawn } = require('child_process'); - -tmpdir.refresh(); - -const command = common.isWindows ? 'cd' : 'pwd'; -const options = { cwd: tmpdir.path }; - -if (common.isWindows) { - // This test is not the case for Windows based systems - // unless the `shell` options equals to `true` - - options.shell = true; -} - -const testCases = [ - undefined, - null, - [], -]; - -const expectedResult = tmpdir.path.trim().toLowerCase(); - -(async () => { - const results = await Promise.all( - testCases.map((testCase) => { - return new Promise((resolve) => { - const subprocess = spawn(command, testCase, options); - - let accumulatedData = Buffer.alloc(0); - - subprocess.stdout.on('data', common.mustCall((data) => { - accumulatedData = Buffer.concat([accumulatedData, data]); - })); - - subprocess.stdout.on('end', () => { - resolve(accumulatedData.toString().trim().toLowerCase()); - }); - }); - }) - ); - - assert.deepStrictEqual([...new Set(results)], [expectedResult]); -})().then(common.mustCall()); diff --git a/test/parallel/test-child-process-spawn-args.mjs b/test/parallel/test-child-process-spawn-args.mjs new file mode 100644 index 00000000000000..6d0bc9056789dd --- /dev/null +++ b/test/parallel/test-child-process-spawn-args.mjs @@ -0,0 +1,50 @@ +// This test confirms that `undefined`, `null`, and `[]` +// can be used as a placeholder for the second argument (`args`) of `spawn()`. +// Previously, there was a bug where using `undefined` for the second argument +// caused the third argument (`options`) to be ignored. +// See https://github.com/nodejs/node/issues/24912. + +import * as common from '../common/index.mjs'; +import tmpdir from '../common/tmpdir.js'; + +import assert from 'node:assert'; +import { spawn } from 'node:child_process'; +import { once } from 'node:events'; + +tmpdir.refresh(); + +const command = common.isWindows ? 'cd' : 'pwd'; +const options = { cwd: tmpdir.path }; + +if (common.isWindows) { + // This test is not the case for Windows based systems + // unless the `shell` options equals to `true` + options.shell = true; +} + +const testCases = [ + undefined, + null, + [], +]; + +const expectedResult = new Set([tmpdir.path.trim().toLowerCase()]); + +const actualResults = new Set(); + +for (const testCase of testCases) { + const subprocess = spawn(command, testCase, options); + + let accumulatedData = ''; + + subprocess.stdout.setEncoding('utf8'); + subprocess.stdout.on('data', common.mustCall((data) => { + accumulatedData += data; + })); + + await once(subprocess.stdout, 'end'); + + actualResults.add(accumulatedData.trim().toLowerCase()); +} + +assert.deepStrictEqual(actualResults, expectedResult); diff --git a/test/parallel/test-config-file.js b/test/parallel/test-config-file.js index ac7f9edf3b4082..0e67d12f09a02b 100644 --- a/test/parallel/test-config-file.js +++ b/test/parallel/test-config-file.js @@ -3,8 +3,8 @@ const { spawnPromisified, skipIfSQLiteMissing } = require('../common'); skipIfSQLiteMissing(); const fixtures = require('../common/fixtures'); -const { match, strictEqual } = require('node:assert'); -const { test } = require('node:test'); +const { match, strictEqual, deepStrictEqual } = require('node:assert'); +const { test, it, describe } = require('node:test'); const { chmodSync, constants } = require('node:fs'); const common = require('../common'); @@ -55,18 +55,19 @@ test('should parse boolean flag', async () => { strictEqual(result.code, 0); }); -test('should not override a flag declared twice', async () => { +test('should throw an error when a flag is declared twice', async () => { const result = await spawnPromisified(process.execPath, [ '--no-warnings', '--experimental-config-file', fixtures.path('rc/override-property.json'), fixtures.path('typescript/ts/transformation/test-enum.ts'), ]); - strictEqual(result.stderr, ''); - strictEqual(result.stdout, 'Hello, TypeScript!\n'); - strictEqual(result.code, 0); + match(result.stderr, /Option --experimental-transform-types is already defined/); + strictEqual(result.stdout, ''); + strictEqual(result.code, 9); }); + test('should override env-file', async () => { const result = await spawnPromisified(process.execPath, [ '--no-warnings', @@ -97,7 +98,7 @@ test('should not override NODE_OPTIONS', async () => { strictEqual(result.code, 1); }); -test('should not ovverride CLI flags', async () => { +test('should not override CLI flags', async () => { const result = await spawnPromisified(process.execPath, [ '--no-warnings', '--no-experimental-transform-types', @@ -375,3 +376,147 @@ test('should throw an error when the file is non readable', { skip: common.isWin chmodSync(fixtures.path('rc/non-readable/node.config.json'), constants.S_IRWXU | constants.S_IRWXG | constants.S_IRWXO); }); + +describe('namespace-scoped options', () => { + it('should parse a namespace-scoped option correctly', async () => { + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--expose-internals', + '--experimental-config-file', + fixtures.path('rc/namespaced/node.config.json'), + '-p', 'require("internal/options").getOptionValue("--test-isolation")', + ]); + strictEqual(result.stderr, ''); + strictEqual(result.stdout, 'none\n'); + strictEqual(result.code, 0); + }); + + it('should throw an error when a namespace-scoped option is not recognised', async () => { + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--experimental-config-file', + fixtures.path('rc/unknown-flag-namespace.json'), + '-p', '"Hello, World!"', + ]); + match(result.stderr, /Unknown or not allowed option unknown-flag/); + strictEqual(result.stdout, ''); + strictEqual(result.code, 9); + }); + + it('should not throw an error when a namespace is not recognised', async () => { + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--experimental-config-file', + fixtures.path('rc/unknown-namespace.json'), + '-p', '"Hello, World!"', + ]); + strictEqual(result.stderr, ''); + strictEqual(result.stdout, 'Hello, World!\n'); + strictEqual(result.code, 0); + }); + + it('should handle an empty namespace valid namespace', async () => { + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--experimental-config-file', + fixtures.path('rc/empty-valid-namespace.json'), + '-p', '"Hello, World!"', + ]); + strictEqual(result.stderr, ''); + strictEqual(result.stdout, 'Hello, World!\n'); + strictEqual(result.code, 0); + }); + + it('should throw an error if a namespace-scoped option has already been set in node options', async () => { + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--expose-internals', + '--experimental-config-file', + fixtures.path('rc/override-node-option-with-namespace.json'), + '-p', 'require("internal/options").getOptionValue("--test-isolation")', + ]); + match(result.stderr, /Option --test-isolation is already defined/); + strictEqual(result.stdout, ''); + strictEqual(result.code, 9); + }); + + it('should throw an error if a node option has already been set in a namespace-scoped option', async () => { + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--expose-internals', + '--experimental-config-file', + fixtures.path('rc/override-namespace.json'), + '-p', 'require("internal/options").getOptionValue("--test-isolation")', + ]); + match(result.stderr, /Option --test-isolation is already defined/); + strictEqual(result.stdout, ''); + strictEqual(result.code, 9); + }); + + it('should prioritise CLI namespace-scoped options over config file options', async () => { + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--expose-internals', + '--test-isolation', 'process', + '--experimental-config-file', + fixtures.path('rc/namespaced/node.config.json'), + '-p', 'require("internal/options").getOptionValue("--test-isolation")', + ]); + strictEqual(result.stderr, ''); + strictEqual(result.stdout, 'process\n'); + strictEqual(result.code, 0); + }); + + it('should append namespace-scoped config file options with CLI options in case of array', async () => { + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--expose-internals', + '--test-coverage-exclude', 'cli-pattern1', + '--test-coverage-exclude', 'cli-pattern2', + '--experimental-config-file', + fixtures.path('rc/namespace-with-array.json'), + '-p', 'JSON.stringify(require("internal/options").getOptionValue("--test-coverage-exclude"))', + ]); + strictEqual(result.stderr, ''); + const excludePatterns = JSON.parse(result.stdout); + const expected = [ + 'config-pattern1', + 'config-pattern2', + 'cli-pattern1', + 'cli-pattern2', + ]; + deepStrictEqual(excludePatterns, expected); + strictEqual(result.code, 0); + }); + + it('should allow setting kDisallowedInEnvvar in the config file if part of a namespace', async () => { + // This test assumes that the --test-concurrency flag is configured as kDisallowedInEnvVar + // and that it is part of at least one namespace. + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--expose-internals', + '--experimental-config-file', + fixtures.path('rc/namespace-with-disallowed-envvar.json'), + '-p', 'require("internal/options").getOptionValue("--test-concurrency")', + ]); + strictEqual(result.stderr, ''); + strictEqual(result.stdout, '1\n'); + strictEqual(result.code, 0); + }); + + it('should override namespace-scoped config file options with CLI options', async () => { + // This test assumes that the --test-concurrency flag is configured as kDisallowedInEnvVar + // and that it is part of at least one namespace. + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--expose-internals', + '--test-concurrency', '2', + '--experimental-config-file', + fixtures.path('rc/namespace-with-disallowed-envvar.json'), + '-p', 'require("internal/options").getOptionValue("--test-concurrency")', + ]); + strictEqual(result.stderr, ''); + strictEqual(result.stdout, '2\n'); + strictEqual(result.code, 0); + }); +}); diff --git a/test/parallel/test-crypto-authenticated.js b/test/parallel/test-crypto-authenticated.js index 181ea732b91281..5f74f7c2611138 100644 --- a/test/parallel/test-crypto-authenticated.js +++ b/test/parallel/test-crypto-authenticated.js @@ -18,7 +18,7 @@ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -// Flags: --no-warnings + 'use strict'; const common = require('../common'); if (!common.hasCrypto) { @@ -245,7 +245,7 @@ for (const test of TEST_CASES) { assert.strictEqual(text.toString('utf8'), 'node'); } -// Test that create(De|C)ipher(iv)? throws if the mode is CCM and an invalid +// Test that create(De|C)ipheriv throws if the mode is CCM and an invalid // authentication tag length has been specified. { for (const authTagLength of [-1, true, false, NaN, 5.5]) { @@ -303,8 +303,8 @@ for (const test of TEST_CASES) { } } -// Test that create(De|C)ipher(iv)? throws if the mode is CCM or OCB and no -// authentication tag has been specified. +// Test that create(De|C)ipheriv throws if the mode is CCM or OCB and no +// authentication tag length has been specified. { for (const mode of ['ccm', 'ocb']) { assert.throws(() => { @@ -315,8 +315,8 @@ for (const test of TEST_CASES) { message: `authTagLength required for aes-256-${mode}` }); - // CCM decryption and create(De|C)ipher are unsupported in FIPS mode. - if (!isFipsEnabled) { + // CCM decryption is unsupported in FIPS mode. + if (!isFipsEnabled || mode !== 'ccm') { assert.throws(() => { crypto.createDecipheriv(`aes-256-${mode}`, 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', @@ -448,34 +448,65 @@ for (const test of TEST_CASES) { } // Test that the authentication tag can be set at any point before calling -// final() in GCM or OCB mode. +// final() in GCM mode, OCB mode, and for ChaCha20-Poly1305. { + const aad = Buffer.from('Shared', 'utf8'); const plain = Buffer.from('Hello world', 'utf8'); - const key = Buffer.from('0123456789abcdef', 'utf8'); + const key = Buffer.from('0123456789abcdefghijklmnopqrstuv', 'utf8'); const iv = Buffer.from('0123456789ab', 'utf8'); - for (const mode of ['gcm', 'ocb']) { - for (const authTagLength of mode === 'gcm' ? [undefined, 8] : [8]) { - const cipher = crypto.createCipheriv(`aes-128-${mode}`, key, iv, { + function testAllOrders({ alg, authTagLength, useAAD, useMessage }) { + // Encrypt the message first to obtain ciphertext and authTag. + const cipher = crypto.createCipheriv(alg, key, iv, { + authTagLength + }); + if (useAAD) { + cipher.setAAD(aad); + } + const ciphertext = useMessage ? Buffer.concat([cipher.update(plain), cipher.final()]) : cipher.final(); + const authTag = cipher.getAuthTag(); + assert.strictEqual(authTag.length, authTagLength ?? 16); + + // Test decryption with each possible order of operations. + for (const authTagTime of ['beforeAAD', 'beforeUpdate', 'afterUpdate']) { + const decipher = crypto.createDecipheriv(alg, key, iv, { authTagLength }); - const ciphertext = Buffer.concat([cipher.update(plain), cipher.final()]); - const authTag = cipher.getAuthTag(); + if (authTagTime === 'beforeAAD') { + decipher.setAuthTag(authTag); + } + if (useAAD) { + decipher.setAAD(aad); + } + if (authTagTime === 'beforeUpdate') { + decipher.setAuthTag(authTag); + } + const resultBuffers = []; + if (useMessage) { + resultBuffers.push(decipher.update(ciphertext)); + } + if (authTagTime === 'afterUpdate') { + decipher.setAuthTag(authTag); + } + resultBuffers.push(decipher.final()); + const result = Buffer.concat(resultBuffers); + if (useMessage) { + assert.deepStrictEqual(result, plain); + } else { + assert.strictEqual(result.length, 0); + } + } + } - for (const authTagBeforeUpdate of [true, false]) { - const decipher = crypto.createDecipheriv(`aes-128-${mode}`, key, iv, { - authTagLength - }); - if (authTagBeforeUpdate) { - decipher.setAuthTag(authTag); - } - const resultUpdate = decipher.update(ciphertext); - if (!authTagBeforeUpdate) { - decipher.setAuthTag(authTag); - } - const resultFinal = decipher.final(); - const result = Buffer.concat([resultUpdate, resultFinal]); - assert(result.equals(plain)); + for (const alg of ['aes-256-gcm', 'aes-256-ocb', 'chacha20-poly1305']) { + for (const authTagLength of alg === 'aes-256-gcm' ? [undefined, 8] : [8]) { + for (const [useAAD, useMessage] of [ + [false, false], // No AAD, no update. + [true, false], // Only AAD (e.g., GMAC). + [false, true], // No AAD, only message. + [true, true], // Both AAD and message. + ]) { + testAllOrders({ alg, authTagLength, useAAD, useMessage }); } } } @@ -561,17 +592,14 @@ for (const test of TEST_CASES) { const iv = Buffer.alloc(12); const opts = { authTagLength: 10 }; - for (const cipher of [ - crypto.createCipheriv(algo, key, iv, opts), - ]) { - assert.throws(() => { - cipher.final(); - }, hasOpenSSL3 ? { - code: 'ERR_OSSL_TAG_NOT_SET' - } : { - message: /Unsupported state/ - }); - } + const cipher = crypto.createCipheriv(algo, key, iv, opts); + assert.throws(() => { + cipher.final(); + }, hasOpenSSL3 ? { + code: 'ERR_OSSL_TAG_NOT_SET' + } : { + message: /Unsupported state/ + }); } { diff --git a/test/parallel/test-crypto-fips.js b/test/parallel/test-crypto-fips.js index de004b9a9e8f23..a5e25b8fd1073a 100644 --- a/test/parallel/test-crypto-fips.js +++ b/test/parallel/test-crypto-fips.js @@ -23,13 +23,16 @@ const FIPS_ENABLE_ERROR_STRING = 'OpenSSL error when trying to enable FIPS:'; const CNF_FIPS_ON = fixtures.path('openssl_fips_enabled.cnf'); const CNF_FIPS_OFF = fixtures.path('openssl_fips_disabled.cnf'); +const kNoFailure = 0; +const kGenericUserError = 1; + let num_children_ok = 0; function sharedOpenSSL() { return process.config.variables.node_shared_openssl; } -function testHelper(stream, args, expectedOutput, cmd, env) { +function testHelper(stream, args, expectedStatus, expectedOutput, cmd, env) { const fullArgs = args.concat(['-e', `console.log(${cmd})`]); const child = spawnSync(process.execPath, fullArgs, { cwd: path.dirname(process.execPath), @@ -56,6 +59,7 @@ function testHelper(stream, args, expectedOutput, cmd, env) { // Normal path where we expect either FIPS enabled or disabled. assert.strictEqual(getFipsValue, expectedOutput); } + assert.strictEqual(child.status, expectedStatus); childOk(child); } @@ -66,6 +70,7 @@ function testHelper(stream, args, expectedOutput, cmd, env) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--enable-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_ENABLE_ERROR_STRING, 'process.versions', process.env); @@ -74,6 +79,7 @@ testHelper( testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--force-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_ENABLE_ERROR_STRING, 'process.versions', process.env); @@ -85,6 +91,7 @@ if (!sharedOpenSSL()) { testHelper( 'stdout', [], + kNoFailure, FIPS_DISABLED, 'require("crypto").getFips()', { ...process.env, 'OPENSSL_CONF': ' ' }); @@ -94,6 +101,7 @@ if (!sharedOpenSSL()) { testHelper( 'stderr', [], + kGenericUserError, 'Calling crypto.setFips() is not supported in workers', 'new worker_threads.Worker(\'require("crypto").setFips(true);\', { eval: true })', process.env); @@ -120,6 +128,7 @@ if (!sharedOpenSSL() && !hasOpenSSL3) { testHelper( 'stdout', [`--openssl-config=${CNF_FIPS_ON}`], + kNoFailure, testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED, 'require("crypto").getFips()', process.env); @@ -128,6 +137,7 @@ if (!sharedOpenSSL() && !hasOpenSSL3) { testHelper( 'stdout', [], + kNoFailure, testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED, 'require("crypto").getFips()', Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON })); @@ -136,6 +146,7 @@ if (!sharedOpenSSL() && !hasOpenSSL3) { testHelper( 'stdout', [`--openssl-config=${CNF_FIPS_ON}`], + kNoFailure, testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED, 'require("crypto").getFips()', Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); @@ -149,6 +160,7 @@ if (!hasOpenSSL3) { testHelper( 'stdout', [`--openssl-config=${CNF_FIPS_OFF}`], + kNoFailure, FIPS_DISABLED, 'require("crypto").getFips()', Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON })); @@ -157,6 +169,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--enable-fips', `--openssl-config=${CNF_FIPS_OFF}`], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").getFips()', process.env); @@ -164,6 +177,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--force-fips', `--openssl-config=${CNF_FIPS_OFF}`], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").getFips()', process.env); @@ -171,6 +185,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--enable-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").getFips()', process.env); @@ -179,6 +194,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--force-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").getFips()', process.env); @@ -187,6 +203,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--enable-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").getFips()', Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); @@ -195,6 +212,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--force-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").getFips()', Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); @@ -203,6 +221,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', [], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, '(require("crypto").setFips(true),' + 'require("crypto").getFips())', @@ -212,6 +231,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', [], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING, '(require("crypto").setFips(true),' + 'require("crypto").setFips(false),' + @@ -222,6 +242,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', [`--openssl-config=${CNF_FIPS_OFF}`], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, '(require("crypto").setFips(true),' + 'require("crypto").getFips())', @@ -231,6 +252,7 @@ if (!hasOpenSSL3) { testHelper( 'stdout', [`--openssl-config=${CNF_FIPS_ON}`], + kNoFailure, FIPS_DISABLED, '(require("crypto").setFips(false),' + 'require("crypto").getFips())', @@ -240,6 +262,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--enable-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING, '(require("crypto").setFips(false),' + 'require("crypto").getFips())', @@ -249,6 +272,7 @@ if (!hasOpenSSL3) { testHelper( 'stderr', ['--force-fips'], + kGenericUserError, testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").setFips(false)', process.env); @@ -257,6 +281,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--force-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, '(require("crypto").setFips(true),' + 'require("crypto").getFips())', @@ -266,6 +291,7 @@ if (!hasOpenSSL3) { testHelper( 'stderr', ['--force-fips', '--enable-fips'], + kGenericUserError, testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").setFips(false)', process.env); @@ -274,6 +300,7 @@ if (!hasOpenSSL3) { testHelper( 'stderr', ['--enable-fips', '--force-fips'], + kGenericUserError, testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").setFips(false)', process.env); diff --git a/test/parallel/test-crypto-getcipherinfo.js b/test/parallel/test-crypto-getcipherinfo.js index 64b79fc36ccf4d..b0902908b5c454 100644 --- a/test/parallel/test-crypto-getcipherinfo.js +++ b/test/parallel/test-crypto-getcipherinfo.js @@ -62,9 +62,13 @@ assert(getCipherInfo('aes-128-cbc', { ivLength: 16 })); assert(!getCipherInfo('aes-128-ccm', { ivLength: 1 })); assert(!getCipherInfo('aes-128-ccm', { ivLength: 14 })); -for (let n = 7; n <= 13; n++) - assert(getCipherInfo('aes-128-ccm', { ivLength: n })); +if (!process.features.openssl_is_boringssl) { + for (let n = 7; n <= 13; n++) + assert(getCipherInfo('aes-128-ccm', { ivLength: n })); +} assert(!getCipherInfo('aes-128-ocb', { ivLength: 16 })); -for (let n = 1; n < 16; n++) - assert(getCipherInfo('aes-128-ocb', { ivLength: n })); +if (!process.features.openssl_is_boringssl) { + for (let n = 1; n < 16; n++) + assert(getCipherInfo('aes-128-ocb', { ivLength: n })); +} diff --git a/test/parallel/test-crypto-hkdf.js b/test/parallel/test-crypto-hkdf.js index 3f7e61e9b2ebc0..360ed52370fbe1 100644 --- a/test/parallel/test-crypto-hkdf.js +++ b/test/parallel/test-crypto-hkdf.js @@ -125,7 +125,7 @@ const algorithms = [ ['sha256', '', 'salt', '', 10], ['sha512', 'secret', 'salt', '', 15], ]; -if (!hasOpenSSL3) +if (!hasOpenSSL3 && !process.features.openssl_is_boringssl) algorithms.push(['whirlpool', 'secret', '', 'info', 20]); algorithms.forEach(([ hash, secret, salt, info, length ]) => { diff --git a/test/parallel/test-crypto-stream.js b/test/parallel/test-crypto-stream.js index 62be4eaf6edfb0..747af780469c22 100644 --- a/test/parallel/test-crypto-stream.js +++ b/test/parallel/test-crypto-stream.js @@ -74,14 +74,14 @@ const decipher = crypto.createDecipheriv('aes-128-cbc', badkey, iv); cipher.pipe(decipher) .on('error', common.expectsError(hasOpenSSL3 ? { - message: /bad decrypt/, + message: /bad[\s_]decrypt/, library: 'Provider routines', - reason: 'bad decrypt', + reason: /bad[\s_]decrypt/i, } : { - message: /bad decrypt/, + message: /bad[\s_]decrypt/i, function: 'EVP_DecryptFinal_ex', library: 'digital envelope routines', - reason: 'bad decrypt', + reason: /bad[\s_]decrypt/i, })); cipher.end('Papaya!'); // Should not cause an unhandled exception. diff --git a/test/parallel/test-crypto-x509.js b/test/parallel/test-crypto-x509.js index f75e1d63470bfb..4e32222ceed17f 100644 --- a/test/parallel/test-crypto-x509.js +++ b/test/parallel/test-crypto-x509.js @@ -97,8 +97,6 @@ const der = Buffer.from( assert.strictEqual(x509.infoAccess, infoAccessCheck); assert.strictEqual(x509.validFrom, 'Sep 3 21:40:37 2022 GMT'); assert.strictEqual(x509.validTo, 'Jun 17 21:40:37 2296 GMT'); - assert.deepStrictEqual(x509.validFromDate, new Date('2022-09-03T21:40:37Z')); - assert.deepStrictEqual(x509.validToDate, new Date('2296-06-17T21:40:37Z')); assert.strictEqual( x509.fingerprint, '8B:89:16:C4:99:87:D2:13:1A:64:94:36:38:A5:32:01:F0:95:3B:53'); @@ -118,6 +116,11 @@ const der = Buffer.from( assert.deepStrictEqual(x509.raw, der); + if (!process.features.openssl_is_boringssl) { + assert.deepStrictEqual(x509.validFromDate, new Date('2022-09-03T21:40:37Z')); + assert.deepStrictEqual(x509.validToDate, new Date('2296-06-17T21:40:37Z')); + } + assert(x509.publicKey); assert.strictEqual(x509.publicKey.type, 'public'); @@ -356,13 +359,15 @@ tAt3hIKFD1bJt6c6WtMH2Su3syosWxmdmGk5ihslB00lvLpfj/wed8i3bkcB1doq UcXd/5qu2GhokrKU2cPttU+XAN2Om6a0 -----END CERTIFICATE-----`; - const cert = new X509Certificate(certPem); - assert.throws(() => cert.publicKey, { - message: hasOpenSSL3 ? /decode error/ : /wrong tag/, - name: 'Error' - }); + if (!process.features.openssl_is_boringssl) { + const cert = new X509Certificate(certPem); + assert.throws(() => cert.publicKey, { + message: hasOpenSSL3 ? /decode error/ : /wrong tag/, + name: 'Error' + }); - assert.strictEqual(cert.checkIssued(cert), false); + assert.strictEqual(cert.checkIssued(cert), false); + } } { @@ -401,8 +406,10 @@ UidvpWWipVLZgK+oDks+bKTobcoXGW9oXobiIYqslXPy -----END CERTIFICATE-----`.trim(); const c1 = new X509Certificate(certPemUTCTime); - assert.deepStrictEqual(c1.validFromDate, new Date('1949-12-25T23:59:58Z')); - assert.deepStrictEqual(c1.validToDate, new Date('1950-01-01T23:59:58Z')); + if (!process.features.openssl_is_boringssl) { + assert.deepStrictEqual(c1.validFromDate, new Date('1949-12-25T23:59:58Z')); + assert.deepStrictEqual(c1.validToDate, new Date('1950-01-01T23:59:58Z')); + } // The GeneralizedTime format is used for dates in 2050 or later. const certPemGeneralizedTime = `-----BEGIN CERTIFICATE----- @@ -436,6 +443,8 @@ CWwQO8JZjJqFtqtuzy2n+gLCvqePgG/gmSqHOPm2ZbLW -----END CERTIFICATE-----`.trim(); const c2 = new X509Certificate(certPemGeneralizedTime); - assert.deepStrictEqual(c2.validFromDate, new Date('2049-12-26T00:00:01Z')); - assert.deepStrictEqual(c2.validToDate, new Date('2050-01-02T00:00:01Z')); + if (!process.features.openssl_is_boringssl) { + assert.deepStrictEqual(c2.validFromDate, new Date('2049-12-26T00:00:01Z')); + assert.deepStrictEqual(c2.validToDate, new Date('2050-01-02T00:00:01Z')); + } } diff --git a/test/parallel/test-crypto.js b/test/parallel/test-crypto.js index 93644e016de447..84111740cd9ef6 100644 --- a/test/parallel/test-crypto.js +++ b/test/parallel/test-crypto.js @@ -218,9 +218,9 @@ assert.throws(() => { } : { name: 'Error', message: /routines:RSA_sign:digest too big for rsa key$/, - library: 'rsa routines', + library: /rsa routines/i, function: 'RSA_sign', - reason: 'digest too big for rsa key', + reason: /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i, code: 'ERR_OSSL_RSA_DIGEST_TOO_BIG_FOR_RSA_KEY' }); return true; diff --git a/test/parallel/test-diagnostics-channel-http2-client-stream-close-error.js b/test/parallel/test-diagnostics-channel-http2-client-stream-close-error.js new file mode 100644 index 00000000000000..b7b201eeaf3874 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-client-stream-close-error.js @@ -0,0 +1,44 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.client.stream.close' channel when +// a ClientHttp2Stream is destroyed because of an error. + +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +dc.subscribe('http2.client.stream.close', common.mustCall(({ stream }) => { + // Since ClientHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ClientHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ClientHttp2Stream'); + assert.strictEqual(stream.closed, true); + assert.strictEqual(stream.destroyed, true); + + assert.strictEqual(stream.rstCode, http2.constants.NGHTTP2_CANCEL); +})); + +const server = http2.createServer(); +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const ac = new AbortController(); + const stream = client.request({}, { signal: ac.signal }); + ac.abort(); + + stream.on('error', common.mustCall((err) => { + assert.strictEqual(err.code, 'ABORT_ERR'); + assert.strictEqual(err.name, 'AbortError'); + + client.close(); + server.close(); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-client-stream-close.js b/test/parallel/test-diagnostics-channel-http2-client-stream-close.js new file mode 100644 index 00000000000000..72fbe91195c7f4 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-client-stream-close.js @@ -0,0 +1,63 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.client.stream.close' channel when +// ClientHttp2Streams created by these actions are closed: +// - the client calling ClientHttp2Session#request() +// - in response to an incoming 'push' event from the server + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +const clientHttp2StreamCloseCount = 2; + +dc.subscribe('http2.client.stream.close', common.mustCall(({ stream }) => { + // Since ClientHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ClientHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ClientHttp2Stream'); + assert.strictEqual(stream.closed, true); + assert.strictEqual(stream.destroyed, false); + + assert.strictEqual(stream.rstCode, http2.constants.NGHTTP2_NO_ERROR); +}, clientHttp2StreamCloseCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + })); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(clientHttp2StreamCloseCount, () => { + client.close(); + server.close(); + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + })); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-client-stream-error.js b/test/parallel/test-diagnostics-channel-http2-client-stream-error.js new file mode 100644 index 00000000000000..14e745c0b305c2 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-client-stream-error.js @@ -0,0 +1,46 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.client.stream.error' channel when +// an error occurs during the processing of a ClientHttp2Stream. + +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +dc.subscribe('http2.client.stream.error', common.mustCall(({ stream, error }) => { + // Since ClientHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ClientHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ClientHttp2Stream'); + assert.strictEqual(stream.closed, true); + assert.strictEqual(stream.destroyed, true); + + assert.ok(error); + assert.strictEqual(error.code, 'ABORT_ERR'); + assert.strictEqual(error.name, 'AbortError'); +})); + +const server = http2.createServer(); +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const ac = new AbortController(); + const stream = client.request({}, { signal: ac.signal }); + ac.abort(); + + stream.on('error', common.mustCall((err) => { + assert.strictEqual(err.code, 'ABORT_ERR'); + assert.strictEqual(err.name, 'AbortError'); + + client.close(); + server.close(); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-client-stream-finish.js b/test/parallel/test-diagnostics-channel-http2-client-stream-finish.js new file mode 100644 index 00000000000000..c8b26471e28209 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-client-stream-finish.js @@ -0,0 +1,63 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.client.stream.finish' channel when +// ClientHttp2Streams are received by both: +// - the 'response' event +// - the 'push' event + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +const clientHttp2StreamFinishCount = 2; + +dc.subscribe('http2.client.stream.finish', common.mustCall(({ stream, headers, flags }) => { + // Since ClientHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ClientHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ClientHttp2Stream'); + + assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object'); + + assert.strictEqual(typeof flags, 'number'); +}, clientHttp2StreamFinishCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + })); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(clientHttp2StreamFinishCount, () => { + client.close(); + server.close(); + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + })); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-server-stream-created-start-timing.js b/test/parallel/test-diagnostics-channel-http2-server-stream-created-start-timing.js new file mode 100644 index 00000000000000..976e2fb3f2eceb --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-server-stream-created-start-timing.js @@ -0,0 +1,65 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.server.stream.start' channel only +// after the 'http2.server.stream.created' channel. + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); + +const serverHttp2StreamCreationCount = 2; + +const map = {}; + +dc.subscribe('http2.server.stream.created', common.mustCall(({ stream, headers }) => { + map[stream.id] = { ...map[stream.id], 'createdTime': process.hrtime.bigint() }; +}, serverHttp2StreamCreationCount)); + +dc.subscribe('http2.server.stream.start', common.mustCall(({ stream, headers }) => { + map[stream.id] = { ...map[stream.id], 'startTime': process.hrtime.bigint() }; +}, serverHttp2StreamCreationCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + })); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(serverHttp2StreamCreationCount, () => { + client.close(); + server.close(); + + const timings = Object.values(map); + assert.strictEqual(timings.length, serverHttp2StreamCreationCount); + + for (const { createdTime, startTime } of timings) { + assert.ok(createdTime < startTime); + } + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + })); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-server-stream-created.js b/test/parallel/test-diagnostics-channel-http2-server-stream-created.js new file mode 100644 index 00000000000000..b3b5fcd90aebe6 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-server-stream-created.js @@ -0,0 +1,60 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.server.stream.created' channel when +// ServerHttp2Streams are created by both: +// - in response to an incoming 'stream' event from the client +// - the server calling ServerHttp2Stream#pushStream() + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +const serverHttp2StreamCreationCount = 2; + +dc.subscribe('http2.server.stream.created', common.mustCall(({ stream, headers }) => { + // Since ServerHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ServerHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream'); + assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object'); +}, serverHttp2StreamCreationCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + })); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(serverHttp2StreamCreationCount, () => { + client.close(); + server.close(); + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + })); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-server-stream-error.js b/test/parallel/test-diagnostics-channel-http2-server-stream-error.js new file mode 100644 index 00000000000000..ea4f49e200c88b --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-server-stream-error.js @@ -0,0 +1,53 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.server.stream.error' channel when +// an error occurs during the processing of a ServerHttp2Stream. + +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +let expectedError = null; + +dc.subscribe('http2.server.stream.error', common.mustCall(({ stream, error }) => { + // Since ServerHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ServerHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream'); + assert.strictEqual(stream.closed, true); + assert.strictEqual(stream.destroyed, true); + + assert.ok(error); + assert.strictEqual(error, expectedError); +})); + +const server = http2.createServer(); + +server.on('stream', common.mustCall((stream) => { + stream.on('error', common.mustCall((err) => { + assert.strictEqual(err, expectedError); + })); + + expectedError = new Error('HTTP/2 server stream error'); + stream.destroy(expectedError); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const stream = client.request({}); + stream.on('error', common.mustCall((err) => { + assert.strictEqual(err.code, 'ERR_HTTP2_STREAM_ERROR'); + + client.close(); + server.close(); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-server-stream-finish.js b/test/parallel/test-diagnostics-channel-http2-server-stream-finish.js new file mode 100644 index 00000000000000..6a27cc1408ad77 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-server-stream-finish.js @@ -0,0 +1,61 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.server.stream.finish' channel when +// ServerHttp2Streams#respond() sends a regular stream as well as a push stream. + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +const serverHttp2StreamFinishCount = 2; + +dc.subscribe('http2.server.stream.finish', common.mustCall(({ stream, headers, flags }) => { + // Since ServerHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ServerHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream'); + + assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object'); + + assert.strictEqual(typeof flags, 'number'); +}, serverHttp2StreamFinishCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + })); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(serverHttp2StreamFinishCount, () => { + client.close(); + server.close(); + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + })); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-server-stream-start.js b/test/parallel/test-diagnostics-channel-http2-server-stream-start.js new file mode 100644 index 00000000000000..b672037deb95a6 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-server-stream-start.js @@ -0,0 +1,60 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.server.stream.start' channel when +// ServerHttp2Streams are started by both: +// - in response to an incoming 'stream' event from the client +// - the server calling ServerHttp2Stream#pushStream() + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +const serverHttp2StreamCreationCount = 2; + +dc.subscribe('http2.server.stream.start', common.mustCall(({ stream, headers }) => { + // Since ServerHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ServerHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream'); + assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object'); +}, serverHttp2StreamCreationCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + })); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(serverHttp2StreamCreationCount, () => { + client.close(); + server.close(); + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + })); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-net-client-socket-tls.js b/test/parallel/test-diagnostics-channel-net-client-socket-tls.js new file mode 100644 index 00000000000000..c887376fd288c9 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-net-client-socket-tls.js @@ -0,0 +1,32 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the 'net.client.socket' diagnostics channel publishes +// a message when tls.connect() is used to create a socket connection. + +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const fixtures = require('../common/fixtures'); +const tls = require('tls'); + +const options = { + key: fixtures.readKey('agent1-key.pem'), + cert: fixtures.readKey('agent1-cert.pem'), + rejectUnauthorized: false, +}; + +dc.subscribe('net.client.socket', common.mustCall(({ socket }) => { + assert.strictEqual(socket instanceof tls.TLSSocket, true); +})); + +const server = tls.createServer(options, common.mustCall((socket) => { + socket.destroy(); + server.close(); +})); + +server.listen({ port: 0 }, common.mustCall(() => { + const { port } = server.address(); + tls.connect(port, options); +})); diff --git a/test/parallel/test-diagnostics-channel-net.js b/test/parallel/test-diagnostics-channel-net.js index dc84a5b4e1db60..4a959ece277e84 100644 --- a/test/parallel/test-diagnostics-channel-net.js +++ b/test/parallel/test-diagnostics-channel-net.js @@ -1,5 +1,6 @@ 'use strict'; const common = require('../common'); +const Countdown = require('../common/countdown'); const assert = require('assert'); const net = require('net'); const dc = require('diagnostics_channel'); @@ -18,19 +19,23 @@ function testDiagnosticChannel(subscribers, test, after) { const testSuccessfulListen = common.mustCall(() => { let cb; - const server = net.createServer(common.mustCall((socket) => { - socket.destroy(); + const netClientSocketCount = 3; + const countdown = new Countdown(netClientSocketCount, () => { server.close(); cb(); - })); + }); + const server = net.createServer(common.mustCall((socket) => { + socket.destroy(); + countdown.dec(); + }, netClientSocketCount)); dc.subscribe('net.client.socket', common.mustCall(({ socket }) => { assert.strictEqual(isNetSocket(socket), true); - })); + }, netClientSocketCount)); dc.subscribe('net.server.socket', common.mustCall(({ socket }) => { assert.strictEqual(isNetSocket(socket), true); - })); + }, netClientSocketCount)); testDiagnosticChannel( { @@ -48,8 +53,13 @@ const testSuccessfulListen = common.mustCall(() => { common.mustCall((callback) => { cb = callback; server.listen({ port: 0, customOption: true }, () => { + // All supported ways of creating a net client socket connection. const { port } = server.address(); net.connect(port); + + net.createConnection(port); + + new net.Socket().connect(port); }); }), testFailingListen diff --git a/test/parallel/test-dns.js b/test/parallel/test-dns.js index a6b3e459aa00a5..7d67b09d58fc5d 100644 --- a/test/parallel/test-dns.js +++ b/test/parallel/test-dns.js @@ -415,7 +415,7 @@ assert.throws(() => { (answer) => Object.assign({ domain }, answer) ), }), port, address); - }, cases.length * 2 - 1)); + }, cases.length * 2)); server.bind(0, common.mustCall(() => { const address = server.address(); diff --git a/test/parallel/test-filehandle-autoclose.mjs b/test/parallel/test-filehandle-autoclose.mjs new file mode 100644 index 00000000000000..11497c6ac2ec9a --- /dev/null +++ b/test/parallel/test-filehandle-autoclose.mjs @@ -0,0 +1,30 @@ +import '../common/index.mjs'; +import { open } from 'node:fs/promises'; +import { rejects } from 'node:assert'; + +{ + const fh = await open(new URL(import.meta.url)); + + // TODO: remove autoClose option when it becomes default + const readableStream = fh.readableWebStream({ autoClose: true }); + + // Consume the stream + await new Response(readableStream).text(); + + // If reading the FileHandle after the stream is consumed fails, + // then we assume the autoClose option worked as expected. + await rejects(fh.read(), { code: 'EBADF' }); +} + +{ + await using fh = await open(new URL(import.meta.url)); + + const readableStream = fh.readableWebStream({ autoClose: false }); + + // Consume the stream + await new Response(readableStream).text(); + + // Filehandle must be still open + await fh.read(); + await fh.close(); +} diff --git a/test/parallel/test-fs-constants.js b/test/parallel/test-fs-constants.js index 056ee637febf4a..740fa026e6c583 100644 --- a/test/parallel/test-fs-constants.js +++ b/test/parallel/test-fs-constants.js @@ -7,6 +7,75 @@ const assert = require('assert'); assert.notStrictEqual(fs.constants.S_IRUSR, undefined); assert.notStrictEqual(fs.constants.S_IWUSR, undefined); +// Check null prototype. +assert.strictEqual(Object.getPrototypeOf(fs.constants), null); + +const knownFsConstantNames = [ + 'UV_FS_SYMLINK_DIR', + 'UV_FS_SYMLINK_JUNCTION', + 'O_RDONLY', + 'O_WRONLY', + 'O_RDWR', + 'UV_DIRENT_UNKNOWN', + 'UV_DIRENT_FILE', + 'UV_DIRENT_DIR', + 'UV_DIRENT_LINK', + 'UV_DIRENT_FIFO', + 'UV_DIRENT_SOCKET', + 'UV_DIRENT_CHAR', + 'UV_DIRENT_BLOCK', + 'S_IFMT', + 'S_IFREG', + 'S_IFDIR', + 'S_IFCHR', + 'S_IFBLK', + 'S_IFIFO', + 'S_IFLNK', + 'S_IFSOCK', + 'O_CREAT', + 'O_EXCL', + 'UV_FS_O_FILEMAP', + 'O_NOCTTY', + 'O_TRUNC', + 'O_APPEND', + 'O_DIRECTORY', + 'O_EXCL', + 'O_NOATIME', + 'O_NOFOLLOW', + 'O_SYNC', + 'O_DSYNC', + 'O_SYMLINK', + 'O_DIRECT', + 'O_NONBLOCK', + 'S_IRWXU', + 'S_IRUSR', + 'S_IWUSR', + 'S_IXUSR', + 'S_IRWXG', + 'S_IRGRP', + 'S_IWGRP', + 'S_IXGRP', + 'S_IRWXO', + 'S_IROTH', + 'S_IWOTH', + 'S_IXOTH', + 'F_OK', + 'R_OK', + 'W_OK', + 'X_OK', + 'UV_FS_COPYFILE_EXCL', + 'COPYFILE_EXCL', + 'UV_FS_COPYFILE_FICLONE', + 'COPYFILE_FICLONE', + 'UV_FS_COPYFILE_FICLONE_FORCE', + 'COPYFILE_FICLONE_FORCE', +]; +const fsConstantNames = Object.keys(fs.constants); +const unknownFsConstantNames = fsConstantNames.filter((constant) => { + return !knownFsConstantNames.includes(constant); +}); +assert.deepStrictEqual(unknownFsConstantNames, [], `Unknown fs.constants: ${unknownFsConstantNames.join(', ')}`); + // Check for runtime deprecation warning, there should be no setter const { F_OK, R_OK, W_OK, X_OK } = fs.constants; diff --git a/test/parallel/test-fs-cp.mjs b/test/parallel/test-fs-cp.mjs index 260a1449d1a953..589d407d756b51 100644 --- a/test/parallel/test-fs-cp.mjs +++ b/test/parallel/test-fs-cp.mjs @@ -15,7 +15,7 @@ const { writeFileSync, } = fs; import net from 'net'; -import { join } from 'path'; +import { join, resolve } from 'path'; import { pathToFileURL } from 'url'; import { setTimeout } from 'timers/promises'; @@ -248,6 +248,34 @@ function nextdir(dirname) { ); } +// It allows cpSync copying symlinks in src to locations in dest with existing synlinks not pointing to a directory. +{ + const src = nextdir(); + const dest = nextdir(); + mkdirSync(src, mustNotMutateObjectDeep({ recursive: true })); + writeFileSync(`${src}/test.txt`, 'test'); + symlinkSync(resolve(`${src}/test.txt`), join(src, 'link.txt')); + cpSync(src, dest, mustNotMutateObjectDeep({ recursive: true })); + cpSync(src, dest, mustNotMutateObjectDeep({ recursive: true })); +} + +// It allows cp copying symlinks in src to locations in dest with existing synlinks not pointing to a directory. +{ + const src = nextdir(); + const dest = nextdir(); + mkdirSync(src, mustNotMutateObjectDeep({ recursive: true })); + writeFileSync(`${src}/test.txt`, 'test'); + symlinkSync(resolve(`${src}/test.txt`), join(src, 'link.txt')); + cp(src, dest, { recursive: true }, + mustCall((err) => { + assert.strictEqual(err, null); + + cp(src, dest, { recursive: true }, mustCall((err) => { + assert.strictEqual(err, null); + })); + })); +} + // It throws error if symlink in dest points to location in src. { const src = nextdir(); @@ -493,6 +521,9 @@ if (!isWindows && !isInsideDirWithUnusualChars) { const dest = nextdir(); mkdirSync(dest, mustNotMutateObjectDeep({ recursive: true })); writeFileSync(join(src, 'foo.txt'), 'foo', mustNotMutateObjectDeep({ mode: 0o444 })); + // Small wait to make sure that destStat.mtime.getTime() would produce a time + // different from srcStat.mtime.getTime() if preserveTimestamps wasn't set to true + await setTimeout(5); cpSync(src, dest, mustNotMutateObjectDeep({ preserveTimestamps: true, recursive: true })); assertDirEquivalent(src, dest); const srcStat = lstatSync(join(src, 'foo.txt')); diff --git a/test/parallel/test-fs-read-empty-buffer.js b/test/parallel/test-fs-read-empty-buffer.js index 6abfcb5aae69c2..65ed3ee0052c37 100644 --- a/test/parallel/test-fs-read-empty-buffer.js +++ b/test/parallel/test-fs-read-empty-buffer.js @@ -29,7 +29,7 @@ assert.throws( ); (async () => { - const filehandle = await fsPromises.open(filepath, 'r'); + await using filehandle = await fsPromises.open(filepath, 'r'); assert.rejects( () => filehandle.read(buffer, 0, 1, 0), { diff --git a/test/parallel/test-fs-read-offset-null.js b/test/parallel/test-fs-read-offset-null.js index 012c94e41e92c7..4104fe14113199 100644 --- a/test/parallel/test-fs-read-offset-null.js +++ b/test/parallel/test-fs-read-offset-null.js @@ -35,30 +35,25 @@ fs.open(filepath, 'r', common.mustSucceed((fd) => { })); })); -let filehandle = null; - // Tests for promises api (async () => { - filehandle = await fsPromises.open(filepath, 'r'); + await using filehandle = await fsPromises.open(filepath, 'r'); const readObject = await filehandle.read(buf, { offset: null }); assert.strictEqual(readObject.buffer[0], 120); })() -.finally(() => filehandle?.close()) .then(common.mustCall()); // Undocumented: omitted position works the same as position === null (async () => { - filehandle = await fsPromises.open(filepath, 'r'); + await using filehandle = await fsPromises.open(filepath, 'r'); const readObject = await filehandle.read(buf, null, buf.length); assert.strictEqual(readObject.buffer[0], 120); })() -.finally(() => filehandle?.close()) .then(common.mustCall()); (async () => { - filehandle = await fsPromises.open(filepath, 'r'); + await using filehandle = await fsPromises.open(filepath, 'r'); const readObject = await filehandle.read(buf, null, buf.length, 0); assert.strictEqual(readObject.buffer[0], 120); })() -.finally(() => filehandle?.close()) .then(common.mustCall()); diff --git a/test/parallel/test-http2-client-priority-before-connect.js b/test/parallel/test-http2-client-priority-before-connect.js index 7aa13a5e45418e..2620126585ec64 100644 --- a/test/parallel/test-http2-client-priority-before-connect.js +++ b/test/parallel/test-http2-client-priority-before-connect.js @@ -5,6 +5,11 @@ if (!common.hasCrypto) common.skip('missing crypto'); const h2 = require('http2'); +common.expectWarning( + 'DeprecationWarning', + 'http2Stream.priority is longer supported after priority signalling was deprecated in RFC 1993', + 'DEP0194'); + const server = h2.createServer(); // We use the lower-level API here diff --git a/test/parallel/test-http2-client-request-options-errors.js b/test/parallel/test-http2-client-request-options-errors.js index f3c0c57965cf97..48e76c7a2f22da 100644 --- a/test/parallel/test-http2-client-request-options-errors.js +++ b/test/parallel/test-http2-client-request-options-errors.js @@ -11,7 +11,6 @@ const http2 = require('http2'); const optionsToTest = { endStream: 'boolean', - weight: 'number', parent: 'number', exclusive: 'boolean', silent: 'boolean' diff --git a/test/parallel/test-http2-client-set-priority.js b/test/parallel/test-http2-client-set-priority.js index c41ec99031724a..7900c1173f7199 100644 --- a/test/parallel/test-http2-client-set-priority.js +++ b/test/parallel/test-http2-client-set-priority.js @@ -6,10 +6,16 @@ if (!common.hasCrypto) const assert = require('assert'); const http2 = require('http2'); +common.expectWarning( + 'DeprecationWarning', + 'Priority signaling has been deprecated as of RFC 1993.', + 'DEP0194'); + const checkWeight = (actual, expect) => { const server = http2.createServer(); server.on('stream', common.mustCall((stream, headers, flags) => { - assert.strictEqual(stream.state.weight, expect); + assert.strictEqual(stream.state.sumDependencyWeight, 0); + assert.strictEqual(stream.state.weight, 16); stream.respond(); stream.end('test'); })); diff --git a/test/parallel/test-http2-debug.js b/test/parallel/test-http2-debug.js index a465f74af24698..5f2f6c54da7cab 100644 --- a/test/parallel/test-http2-debug.js +++ b/test/parallel/test-http2-debug.js @@ -1,27 +1,31 @@ 'use strict'; + const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); const assert = require('assert'); -const child_process = require('child_process'); +const { spawnSyncAndAssert } = require('../common/child_process'); const path = require('path'); -process.env.NODE_DEBUG_NATIVE = 'http2'; -process.env.NODE_DEBUG = 'http2'; -const { stdout, stderr } = child_process.spawnSync(process.execPath, [ +spawnSyncAndAssert(process.execPath, [ path.resolve(__dirname, 'test-http2-ping.js'), -], { encoding: 'utf8' }); - -assert(stderr.match(/Setting the NODE_DEBUG environment variable to 'http2' can expose sensitive data \(such as passwords, tokens and authentication headers\) in the resulting log\.\r?\n/), - stderr); -assert(stderr.match(/Http2Session client \(\d+\) handling data frame for stream \d+\r?\n/), - stderr); -assert(stderr.match(/HttpStream \d+ \(\d+\) \[Http2Session client \(\d+\)\] reading starting\r?\n/), - stderr); -assert(stderr.match(/HttpStream \d+ \(\d+\) \[Http2Session client \(\d+\)\] closed with code 0\r?\n/), - stderr); -assert(stderr.match(/HttpStream \d+ \(\d+\) \[Http2Session server \(\d+\)\] closed with code 0\r?\n/), - stderr); -assert(stderr.match(/HttpStream \d+ \(\d+\) \[Http2Session server \(\d+\)\] tearing down stream\r?\n/), - stderr); -assert.strictEqual(stdout.trim(), ''); +], { + env: { + ...process.env, + NODE_DEBUG: 'http2', + NODE_DEBUG_NATIVE: 'http2', + }, +}, { + trim: true, + stderr(output) { + assert.match(output, + /Setting the NODE_DEBUG environment variable to 'http2' can expose sensitive data/); + assert.match(output, /\(such as passwords, tokens and authentication headers\) in the resulting log\.\r?\n/); + assert.match(output, /Http2Session client \(\d+\) handling data frame for stream \d+\r?\n/); + assert.match(output, /HttpStream \d+ \(\d+\) \[Http2Session client \(\d+\)\] reading starting\r?\n/); + assert.match(output, /HttpStream \d+ \(\d+\) \[Http2Session client \(\d+\)\] closed with code 0\r?\n/); + assert.match(output, /HttpStream \d+ \(\d+\) \[Http2Session server \(\d+\)\] closed with code 0\r?\n/); + assert.match(output, /HttpStream \d+ \(\d+\) \[Http2Session server \(\d+\)\] tearing down stream\r?\n/); + }, + stdout: '' +}); diff --git a/test/parallel/test-http2-priority-cycle-.js b/test/parallel/test-http2-priority-cycle-.js index af0d66d8343cbf..49a6de1029a167 100644 --- a/test/parallel/test-http2-priority-cycle-.js +++ b/test/parallel/test-http2-priority-cycle-.js @@ -7,6 +7,11 @@ const assert = require('assert'); const http2 = require('http2'); const Countdown = require('../common/countdown'); +common.expectWarning( + 'DeprecationWarning', + 'http2Stream.priority is longer supported after priority signalling was deprecated in RFC 1993', + 'DEP0194'); + const server = http2.createServer(); const largeBuffer = Buffer.alloc(1e4); diff --git a/test/parallel/test-http2-priority-event.js b/test/parallel/test-http2-priority-event.js index 41ec6534b2de53..dad943362019a5 100644 --- a/test/parallel/test-http2-priority-event.js +++ b/test/parallel/test-http2-priority-event.js @@ -3,21 +3,18 @@ const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); -const assert = require('assert'); const h2 = require('http2'); +common.expectWarning( + 'DeprecationWarning', + 'http2Stream.priority is longer supported after priority signalling was deprecated in RFC 1993', + 'DEP0194'); + const server = h2.createServer(); // We use the lower-level API here server.on('stream', common.mustCall(onStream)); -function onPriority(stream, parent, weight, exclusive) { - assert.strictEqual(stream, 1); - assert.strictEqual(parent, 0); - assert.strictEqual(weight, 1); - assert.strictEqual(exclusive, false); -} - function onStream(stream, headers, flags) { stream.priority({ parent: 0, @@ -33,7 +30,7 @@ function onStream(stream, headers, flags) { server.listen(0); -server.on('priority', common.mustCall(onPriority)); +server.on('priority', common.mustNotCall()); server.on('listening', common.mustCall(() => { @@ -48,7 +45,9 @@ server.on('listening', common.mustCall(() => { }); }); - req.on('priority', common.mustCall(onPriority)); + // The priority event is not supported anymore by nghttp2 + // since 1.65.0. + req.on('priority', common.mustNotCall()); req.on('response', common.mustCall()); req.resume(); diff --git a/test/parallel/test-http2-server-rfc-9113-client.js b/test/parallel/test-http2-server-rfc-9113-client.js new file mode 100644 index 00000000000000..caeb7e1fd74361 --- /dev/null +++ b/test/parallel/test-http2-server-rfc-9113-client.js @@ -0,0 +1,80 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const http2 = require('http2'); +const body = + '

    this is some data

    '; + +const server = http2.createServer((req, res) => { + res.setHeader('foobar', 'baz '); + res.setHeader('X-POWERED-BY', 'node-test\t'); + res.setHeader('x-h2-header', '\tconnection-test'); + res.setHeader('x-h2-header-2', ' connection-test'); + res.setHeader('x-h2-header-3', 'connection-test '); + res.end(body); +}); + +const server2 = http2.createServer((req, res) => { + res.setHeader('foobar', 'baz '); + res.setHeader('X-POWERED-BY', 'node-test\t'); + res.setHeader('x-h2-header', '\tconnection-test'); + res.setHeader('x-h2-header-2', ' connection-test'); + res.setHeader('x-h2-header-3', 'connection-test '); + res.end(body); +}); + +server.listen(0, common.mustCall(() => { + server2.listen(0, common.mustCall(() => { + const client = http2.connect(`http://localhost:${server.address().port}`); + const client2 = http2.connect(`http://localhost:${server2.address().port}`, { strictFieldWhitespaceValidation: false }); + const headers = { ':path': '/' }; + const req = client.request(headers); + + req.setEncoding('utf8'); + req.on('response', common.mustCall(function(headers) { + assert.strictEqual(headers.foobar, undefined); + assert.strictEqual(headers['x-powered-by'], undefined); + assert.strictEqual(headers['x-powered-by'], undefined); + assert.strictEqual(headers['x-h2-header'], undefined); + assert.strictEqual(headers['x-h2-header-2'], undefined); + assert.strictEqual(headers['x-h2-header-3'], undefined); + })); + + let data = ''; + req.on('data', (d) => data += d); + req.on('end', () => { + assert.strictEqual(body, data); + client.close(); + client.on('close', common.mustCall(() => { + server.close(); + })); + + const req2 = client2.request(headers); + let data2 = ''; + req2.setEncoding('utf8'); + req2.on('response', common.mustCall(function(headers) { + assert.strictEqual(headers.foobar, 'baz '); + assert.strictEqual(headers['x-powered-by'], 'node-test\t'); + assert.strictEqual(headers['x-h2-header'], '\tconnection-test'); + assert.strictEqual(headers['x-h2-header-2'], ' connection-test'); + assert.strictEqual(headers['x-h2-header-3'], 'connection-test '); + })); + req2.on('data', (d) => data2 += d); + req2.on('end', () => { + assert.strictEqual(body, data2); + client2.close(); + client2.on('close', common.mustCall(() => { + server2.close(); + })); + }); + req2.end(); + }); + + req.end(); + })); +})); + +server.on('error', common.mustNotCall()); diff --git a/test/parallel/test-http2-server-rfc-9113-server.js b/test/parallel/test-http2-server-rfc-9113-server.js new file mode 100644 index 00000000000000..b05bdb2f8cbc37 --- /dev/null +++ b/test/parallel/test-http2-server-rfc-9113-server.js @@ -0,0 +1,83 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const http2 = require('http2'); +const body = + '

    this is some data

    '; + +const server = http2.createServer((req, res) => { + assert.strictEqual(req.headers['x-powered-by'], undefined); + assert.strictEqual(req.headers.foobar, undefined); + assert.strictEqual(req.headers['x-h2-header'], undefined); + assert.strictEqual(req.headers['x-h2-header-2'], undefined); + assert.strictEqual(req.headers['x-h2-header-3'], undefined); + assert.strictEqual(req.headers['x-h2-header-4'], undefined); + res.writeHead(200); + res.end(body); +}); + +const server2 = http2.createServer({ strictFieldWhitespaceValidation: false }, (req, res) => { + assert.strictEqual(req.headers.foobar, 'baz '); + assert.strictEqual(req.headers['x-powered-by'], 'node-test\t'); + assert.strictEqual(req.headers['x-h2-header'], '\tconnection-test'); + assert.strictEqual(req.headers['x-h2-header-2'], ' connection-test'); + assert.strictEqual(req.headers['x-h2-header-3'], 'connection-test '); + assert.strictEqual(req.headers['x-h2-header-4'], 'connection-test\t'); + res.writeHead(200); + res.end(body); +}); + +server.listen(0, common.mustCall(() => { + server2.listen(0, common.mustCall(() => { + const client = http2.connect(`http://localhost:${server.address().port}`); + const client2 = http2.connect(`http://localhost:${server2.address().port}`); + const headers = { + 'foobar': 'baz ', + ':path': '/', + 'x-powered-by': 'node-test\t', + 'x-h2-header': '\tconnection-test', + 'x-h2-header-2': ' connection-test', + 'x-h2-header-3': 'connection-test ', + 'x-h2-header-4': 'connection-test\t' + }; + const req = client.request(headers); + + req.setEncoding('utf8'); + req.on('response', common.mustCall(function(headers) { + assert.strictEqual(headers[':status'], 200); + })); + + let data = ''; + req.on('data', (d) => data += d); + req.on('end', () => { + assert.strictEqual(body, data); + client.close(); + client.on('close', common.mustCall(() => { + server.close(); + })); + + const req2 = client2.request(headers); + let data2 = ''; + req2.setEncoding('utf8'); + req2.on('response', common.mustCall(function(headers) { + assert.strictEqual(headers[':status'], 200); + })); + req2.on('data', (d) => data2 += d); + req2.on('end', () => { + assert.strictEqual(body, data2); + client2.close(); + client2.on('close', common.mustCall(() => { + server2.close(); + })); + }); + req2.end(); + }); + + req.end(); + })); +})); + +server.on('error', common.mustNotCall()); diff --git a/test/parallel/test-http2-server-stream-session-destroy.js b/test/parallel/test-http2-server-stream-session-destroy.js index 34b22fdfbd1334..88fcb3b3cdd617 100644 --- a/test/parallel/test-http2-server-stream-session-destroy.js +++ b/test/parallel/test-http2-server-stream-session-destroy.js @@ -6,6 +6,11 @@ if (!common.hasCrypto) const assert = require('assert'); const h2 = require('http2'); +common.expectWarning( + 'DeprecationWarning', + 'http2Stream.priority is longer supported after priority signalling was deprecated in RFC 1993', + 'DEP0194'); + const server = h2.createServer(); server.on('stream', common.mustCall((stream) => { diff --git a/test/parallel/test-http2-util-update-options-buffer.js b/test/parallel/test-http2-util-update-options-buffer.js index c370fe50c07439..26e220e6b7b507 100644 --- a/test/parallel/test-http2-util-update-options-buffer.js +++ b/test/parallel/test-http2-util-update-options-buffer.js @@ -25,7 +25,8 @@ const IDX_OPTIONS_MAX_SESSION_MEMORY = 8; const IDX_OPTIONS_MAX_SETTINGS = 9; const IDX_OPTIONS_STREAM_RESET_RATE = 10; const IDX_OPTIONS_STREAM_RESET_BURST = 11; -const IDX_OPTIONS_FLAGS = 12; +const IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION = 12; +const IDX_OPTIONS_FLAGS = 13; { updateOptionsBuffer({ @@ -41,6 +42,7 @@ const IDX_OPTIONS_FLAGS = 12; maxSettings: 10, streamResetRate: 11, streamResetBurst: 12, + strictFieldWhitespaceValidation: false }); strictEqual(optionsBuffer[IDX_OPTIONS_MAX_DEFLATE_DYNAMIC_TABLE_SIZE], 1); @@ -55,6 +57,7 @@ const IDX_OPTIONS_FLAGS = 12; strictEqual(optionsBuffer[IDX_OPTIONS_MAX_SETTINGS], 10); strictEqual(optionsBuffer[IDX_OPTIONS_STREAM_RESET_RATE], 11); strictEqual(optionsBuffer[IDX_OPTIONS_STREAM_RESET_BURST], 12); + strictEqual(optionsBuffer[IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION], 1); const flags = optionsBuffer[IDX_OPTIONS_FLAGS]; @@ -69,6 +72,7 @@ const IDX_OPTIONS_FLAGS = 12; ok(flags & (1 << IDX_OPTIONS_MAX_SETTINGS)); ok(flags & (1 << IDX_OPTIONS_STREAM_RESET_RATE)); ok(flags & (1 << IDX_OPTIONS_STREAM_RESET_BURST)); + ok(flags & (1 << IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION)); } { diff --git a/test/parallel/test-https-agent-additional-options.js b/test/parallel/test-https-agent-additional-options.js index 543ee176fb6af3..000cb9d3d0c284 100644 --- a/test/parallel/test-https-agent-additional-options.js +++ b/test/parallel/test-https-agent-additional-options.js @@ -13,23 +13,31 @@ const options = { cert: fixtures.readKey('agent1-cert.pem'), ca: fixtures.readKey('ca1-cert.pem'), minVersion: 'TLSv1.1', - ciphers: 'ALL@SECLEVEL=0' }; +if (!process.features.openssl_is_boringssl) { + options.ciphers = 'ALL@SECLEVEL=0'; +} + const server = https.Server(options, (req, res) => { res.writeHead(200); res.end('hello world\n'); }); function getBaseOptions(port) { - return { + const baseOptions = { path: '/', port: port, ca: options.ca, rejectUnauthorized: true, servername: 'agent1', - ciphers: 'ALL@SECLEVEL=0' }; + + if (!process.features.openssl_is_boringssl) { + baseOptions.ciphers = 'ALL@SECLEVEL=0'; + } + + return baseOptions; } const updatedValues = new Map([ diff --git a/test/parallel/test-https-agent-session-eviction.js b/test/parallel/test-https-agent-session-eviction.js index 6f88e81e9ff29d..a3fd362b5c5ae8 100644 --- a/test/parallel/test-https-agent-session-eviction.js +++ b/test/parallel/test-https-agent-session-eviction.js @@ -17,9 +17,12 @@ const options = { key: readKey('agent1-key.pem'), cert: readKey('agent1-cert.pem'), secureOptions: SSL_OP_NO_TICKET, - ciphers: 'RSA@SECLEVEL=0' }; +if (!process.features.openssl_is_boringssl) { + options.ciphers = 'RSA@SECLEVEL=0'; +} + // Create TLS1.2 server https.createServer(options, function(req, res) { res.writeHead(200, { 'Connection': 'close' }); diff --git a/test/parallel/test-inspector-emit-protocol-event.js b/test/parallel/test-inspector-emit-protocol-event.js index e17e994ee520a3..b539831f4399b6 100644 --- a/test/parallel/test-inspector-emit-protocol-event.js +++ b/test/parallel/test-inspector-emit-protocol-event.js @@ -42,7 +42,9 @@ const EXPECTED_EVENTS = { url: 'https://nodejs.org/en', status: 200, statusText: '', - headers: { host: 'nodejs.org' } + headers: { host: 'nodejs.org' }, + mimeType: 'text/html', + charset: 'utf-8' } }, expected: { @@ -53,10 +55,17 @@ const EXPECTED_EVENTS = { url: 'https://nodejs.org/en', status: 200, statusText: '', - headers: { host: 'nodejs.org' } + headers: { host: 'nodejs.org' }, + mimeType: 'text/html', + charset: 'utf-8' } } }, + { + name: 'dataReceived', + // Network.dataReceived is buffered until Network.streamResourceContent is invoked. + skip: true, + }, { name: 'loadingFinished', params: { @@ -81,8 +90,8 @@ for (const [domain, events] of Object.entries(EXPECTED_EVENTS)) { if (!(domain in inspector)) { assert.fail(`Expected domain ${domain} to be present in inspector`); } - const actualEventNames = Object.keys(inspector[domain]); - const expectedEventNames = events.map((event) => event.name); + const actualEventNames = Object.keys(inspector[domain]).sort(); + const expectedEventNames = events.map((event) => event.name).sort(); assert.deepStrictEqual(actualEventNames, expectedEventNames, `Expected ${domain} to have events ${expectedEventNames}, but got ${actualEventNames}`); } @@ -105,6 +114,9 @@ const runAsyncTest = async () => { await session.post('Network.enable'); for (const [domain, events] of Object.entries(EXPECTED_EVENTS)) { for (const event of events) { + if (event.skip) { + continue; + } session.on(`${domain}.${event.name}`, common.mustCall(({ params }) => { if (event.name === 'requestWillBeSent') { // Initiator is automatically captured and contains caller info. diff --git a/test/parallel/test-inspector-network-content-type.js b/test/parallel/test-inspector-network-content-type.js new file mode 100644 index 00000000000000..c8744e521fc5ec --- /dev/null +++ b/test/parallel/test-inspector-network-content-type.js @@ -0,0 +1,170 @@ +// Flags: --inspect=0 --experimental-network-inspection +'use strict'; +const common = require('../common'); + +common.skipIfInspectorDisabled(); + +const assert = require('node:assert'); +const http = require('node:http'); +const inspector = require('node:inspector/promises'); + +const testNetworkInspection = async (session, port, assert) => { + let assertPromise = assert(session); + fetch(`http://127.0.0.1:${port}/hello-world`).then(common.mustCall()); + await assertPromise; + session.removeAllListeners(); + assertPromise = assert(session); + new Promise((resolve, reject) => { + const req = http.get( + { + host: '127.0.0.1', + port, + path: '/hello-world', + }, + common.mustCall((res) => { + res.on('data', () => {}); + res.on('end', () => {}); + resolve(res); + }) + ); + req.on('error', reject); + }); + await assertPromise; + session.removeAllListeners(); +}; + +const test = (handleRequest, testSessionFunc) => new Promise((resolve) => { + const session = new inspector.Session(); + session.connect(); + const httpServer = http.createServer(handleRequest); + httpServer.listen(0, async () => { + try { + await session.post('Network.enable'); + await testNetworkInspection( + session, + httpServer.address().port, + testSessionFunc + ); + await session.post('Network.disable'); + } catch (err) { + assert.fail(err); + } finally { + await session.disconnect(); + await httpServer.close(); + await inspector.close(); + resolve(); + } + }); +}); + +(async () => { + await test( + (req, res) => { + res.setHeader('Content-Type', 'text/plain; charset=utf-8'); + res.writeHead(200); + res.end('hello world\n'); + }, + common.mustCall( + (session) => + new Promise((resolve) => { + session.on( + 'Network.responseReceived', + common.mustCall(({ params }) => { + assert.strictEqual(params.response.mimeType, 'text/plain'); + assert.strictEqual(params.response.charset, 'utf-8'); + }) + ); + session.on( + 'Network.loadingFinished', + common.mustCall(({ params }) => { + assert.ok(params.requestId.startsWith('node-network-event-')); + assert.strictEqual(typeof params.timestamp, 'number'); + resolve(); + }) + ); + }), + 2 + ) + ); + + await test( + (req, res) => { + res.writeHead(200, {}); + res.end('hello world\n'); + }, + common.mustCall((session) => + new Promise((resolve) => { + session.on( + 'Network.responseReceived', + common.mustCall(({ params }) => { + assert.strictEqual(params.response.mimeType, ''); + assert.strictEqual(params.response.charset, ''); + }) + ); + session.on( + 'Network.loadingFinished', + common.mustCall(({ params }) => { + assert.ok(params.requestId.startsWith('node-network-event-')); + assert.strictEqual(typeof params.timestamp, 'number'); + resolve(); + }) + ); + }), 2 + ) + ); + + await test( + (req, res) => { + res.setHeader('Content-Type', 'invalid content-type'); + res.writeHead(200); + res.end('hello world\n'); + }, + common.mustCall((session) => + new Promise((resolve) => { + session.on( + 'Network.responseReceived', + common.mustCall(({ params }) => { + assert.strictEqual(params.response.mimeType, ''); + assert.strictEqual(params.response.charset, ''); + }) + ); + session.on( + 'Network.loadingFinished', + common.mustCall(({ params }) => { + assert.ok(params.requestId.startsWith('node-network-event-')); + assert.strictEqual(typeof params.timestamp, 'number'); + resolve(); + }) + ); + }), 2 + ) + ); + + await test( + (req, res) => { + res.setHeader('Content-Type', 'text/plain'); + res.writeHead(200); + res.end('hello world\n'); + }, + common.mustCall((session) => + new Promise((resolve) => { + session.on( + 'Network.responseReceived', + common.mustCall(({ params }) => { + assert.strictEqual(params.response.mimeType, 'text/plain'); + assert.strictEqual(params.response.charset, ''); + }) + ); + session.on( + 'Network.loadingFinished', + common.mustCall(({ params }) => { + assert.ok(params.requestId.startsWith('node-network-event-')); + assert.strictEqual(typeof params.timestamp, 'number'); + resolve(); + }) + ); + }), 2 + ) + ); + +})().then(common.mustCall()); diff --git a/test/parallel/test-inspector-network-data-received.js b/test/parallel/test-inspector-network-data-received.js new file mode 100644 index 00000000000000..fde584c885567a --- /dev/null +++ b/test/parallel/test-inspector-network-data-received.js @@ -0,0 +1,146 @@ +// Flags: --inspect=0 --experimental-network-inspection +'use strict'; +const common = require('../common'); + +common.skipIfInspectorDisabled(); + +const inspector = require('node:inspector/promises'); +const { Network } = require('node:inspector'); +const test = require('node:test'); +const assert = require('node:assert'); +const { waitUntil } = require('../common/inspector-helper'); +const { setTimeout } = require('node:timers/promises'); + +const session = new inspector.Session(); +session.connect(); +session.post('Network.enable'); + +async function triggerNetworkEvents(requestId) { + const url = 'https://example.com'; + Network.requestWillBeSent({ + requestId, + timestamp: 1, + wallTime: 1, + request: { + url, + method: 'GET', + headers: { + mKey: 'mValue', + }, + }, + }); + await setTimeout(1); + + Network.responseReceived({ + requestId, + timestamp: 2, + type: 'Fetch', + response: { + url, + status: 200, + statusText: 'OK', + headers: { + mKey: 'mValue', + }, + }, + }); + await setTimeout(1); + + const chunk1 = Buffer.from('Hello, '); + Network.dataReceived({ + requestId, + timestamp: 3, + dataLength: chunk1.byteLength, + encodedDataLength: chunk1.byteLength, + data: chunk1, + }); + await setTimeout(1); + + const chunk2 = Buffer.from('world'); + Network.dataReceived({ + requestId, + timestamp: 4, + dataLength: chunk2.byteLength, + encodedDataLength: chunk2.byteLength, + data: chunk2, + }); + await setTimeout(1); + + Network.loadingFinished({ + requestId, + timestamp: 5, + }); +} + +test('should stream Network.dataReceived with data chunks', async () => { + session.removeAllListeners(); + + const requestId = 'my-req-id-1'; + const chunks = []; + let totalDataLength = 0; + session.on('Network.requestWillBeSent', common.mustCall(({ params }) => { + assert.strictEqual(params.requestId, requestId); + })); + const responseReceivedFuture = waitUntil(session, 'Network.responseReceived') + .then(async ([{ params }]) => { + assert.strictEqual(params.requestId, requestId); + const { bufferedData } = await session.post('Network.streamResourceContent', { + requestId, + }); + const data = Buffer.from(bufferedData, 'base64'); + totalDataLength += data.byteLength; + chunks.push(data); + }); + const loadingFinishedFuture = waitUntil(session, 'Network.loadingFinished') + .then(([{ params }]) => { + assert.strictEqual(params.requestId, requestId); + }); + session.on('Network.dataReceived', ({ params }) => { + assert.strictEqual(params.requestId, requestId); + totalDataLength += params.dataLength; + chunks.push(Buffer.from(params.data, 'base64')); + }); + + await triggerNetworkEvents(requestId); + await responseReceivedFuture; + await loadingFinishedFuture; + + const data = Buffer.concat(chunks); + assert.strictEqual(data.byteLength, totalDataLength, data); + assert.strictEqual(data.toString('utf8'), 'Hello, world'); +}); + +test('Network.streamResourceContent should send all buffered chunks', async () => { + session.removeAllListeners(); + + const requestId = 'my-req-id-2'; + session.on('Network.requestWillBeSent', common.mustCall(({ params }) => { + assert.strictEqual(params.requestId, requestId); + })); + session.on('Network.responseReceived', common.mustCall(({ params }) => { + assert.strictEqual(params.requestId, requestId); + })); + const loadingFinishedFuture = waitUntil(session, 'Network.loadingFinished') + .then(async ([{ params }]) => { + assert.strictEqual(params.requestId, requestId); + }); + session.on('Network.dataReceived', common.mustNotCall()); + + await triggerNetworkEvents(requestId); + await loadingFinishedFuture; + const { bufferedData } = await session.post('Network.streamResourceContent', { + requestId, + }); + assert.strictEqual(Buffer.from(bufferedData, 'base64').toString('utf8'), 'Hello, world'); +}); + +test('Network.streamResourceContent should reject if request id not found', async () => { + session.removeAllListeners(); + + const requestId = 'unknown-request-id'; + await assert.rejects(session.post('Network.streamResourceContent', { + requestId, + }), { + code: 'ERR_INSPECTOR_COMMAND', + }); +}); diff --git a/test/parallel/test-inspector-network-fetch.js b/test/parallel/test-inspector-network-fetch.js index 88585ab72bac75..cc16667c54a02d 100644 --- a/test/parallel/test-inspector-network-fetch.js +++ b/test/parallel/test-inspector-network-fetch.js @@ -36,6 +36,7 @@ const setResponseHeaders = (res) => { res.setHeader('etag', 12345); res.setHeader('Set-Cookie', ['key1=value1', 'key2=value2']); res.setHeader('x-header2', ['value1', 'value2']); + res.setHeader('Content-Type', 'text/plain; charset=utf-8'); }; const handleRequest = (req, res) => { @@ -101,6 +102,8 @@ const testHttpGet = () => new Promise((resolve, reject) => { assert.strictEqual(params.response.headers.etag, '12345'); assert.strictEqual(params.response.headers['Set-Cookie'], 'key1=value1\nkey2=value2'); assert.strictEqual(params.response.headers['x-header2'], 'value1, value2'); + assert.strictEqual(params.response.mimeType, 'text/plain'); + assert.strictEqual(params.response.charset, 'utf-8'); })); session.on('Network.loadingFinished', common.mustCall(({ params }) => { assert.ok(params.requestId.startsWith('node-network-event-')); @@ -138,6 +141,8 @@ const testHttpsGet = () => new Promise((resolve, reject) => { assert.strictEqual(params.response.headers.etag, '12345'); assert.strictEqual(params.response.headers['Set-Cookie'], 'key1=value1\nkey2=value2'); assert.strictEqual(params.response.headers['x-header2'], 'value1, value2'); + assert.strictEqual(params.response.mimeType, 'text/plain'); + assert.strictEqual(params.response.charset, 'utf-8'); })); session.on('Network.loadingFinished', common.mustCall(({ params }) => { assert.ok(params.requestId.startsWith('node-network-event-')); diff --git a/test/parallel/test-inspector-network-http.js b/test/parallel/test-inspector-network-http.js index a02329891e1208..1dd4a65fc0dd72 100644 --- a/test/parallel/test-inspector-network-http.js +++ b/test/parallel/test-inspector-network-http.js @@ -27,6 +27,7 @@ const setResponseHeaders = (res) => { res.setHeader('etag', 12345); res.setHeader('Set-Cookie', ['key1=value1', 'key2=value2']); res.setHeader('x-header2', ['value1', 'value2']); + res.setHeader('Content-Type', 'text/plain; charset=utf-8'); }; const kTimeout = 1000; @@ -106,6 +107,8 @@ function verifyResponseReceived({ method, params }, expect) { assert.strictEqual(params.response.headers.etag, '12345'); assert.strictEqual(params.response.headers['set-cookie'], 'key1=value1\nkey2=value2'); assert.strictEqual(params.response.headers['x-header2'], 'value1, value2'); + assert.strictEqual(params.response.mimeType, 'text/plain'); + assert.strictEqual(params.response.charset, 'utf-8'); return params; } diff --git a/test/parallel/test-node-output-sourcemaps.mjs b/test/parallel/test-node-output-sourcemaps.mjs index 29cc5eb711f176..81c36934ba0f3e 100644 --- a/test/parallel/test-node-output-sourcemaps.mjs +++ b/test/parallel/test-node-output-sourcemaps.mjs @@ -1,29 +1,17 @@ -import * as common from '../common/index.mjs'; +import '../common/index.mjs'; import * as fixtures from '../common/fixtures.mjs'; import * as snapshot from '../common/assertSnapshot.js'; -import * as path from 'node:path'; import { describe, it } from 'node:test'; describe('sourcemaps output', { concurrency: !process.env.TEST_PARALLEL }, () => { - function normalize(str) { - const result = str - .replaceAll(snapshot.replaceWindowsPaths(process.cwd()), '') - .replaceAll('//', '*') - .replaceAll('/Users/bencoe/oss/coffee-script-test', '') - .replaceAll(/\/(\w)/g, '*$1') - .replaceAll('*test*', '*') - .replaceAll('*fixtures*source-map*', '*') - .replaceAll(/(\W+).*node:.*/g, '$1*'); - if (common.isWindows) { - const currentDeviceLetter = path.parse(process.cwd()).root.substring(0, 1).toLowerCase(); - const regex = new RegExp(`${currentDeviceLetter}:/?`, 'gi'); - return result.replaceAll(regex, ''); - } - return result; - } const defaultTransform = snapshot - .transform(snapshot.replaceWindowsLineEndings, snapshot.replaceWindowsPaths, - normalize, snapshot.replaceNodeVersion); + .transform( + snapshot.replaceWindowsLineEndings, + snapshot.transformProjectRoot('*'), + snapshot.replaceWindowsPaths, + snapshot.replaceInternalStackTrace, + snapshot.replaceNodeVersion + ); const tests = [ { name: 'source-map/output/source_map_disabled_by_api.js' }, diff --git a/test/parallel/test-path-resolve.js b/test/parallel/test-path-resolve.js index 6b1dfa7567d3d1..088ed4b3ff183f 100644 --- a/test/parallel/test-path-resolve.js +++ b/test/parallel/test-path-resolve.js @@ -24,6 +24,8 @@ const resolveTests = [ [['c:/ignore', 'd:\\a/b\\c/d', '\\e.exe'], 'd:\\e.exe'], [['c:/ignore', 'c:/some/file'], 'c:\\some\\file'], [['d:/ignore', 'd:some/dir//'], 'd:\\ignore\\some\\dir'], + [[], process.cwd()], + [[''], process.cwd()], [['.'], process.cwd()], [['//server/share', '..', 'relative\\'], '\\\\server\\share\\relative'], [['c:/', '//'], 'c:\\'], @@ -42,6 +44,8 @@ const resolveTests = [ [[['/var/lib', '../', 'file/'], '/var/file'], [['/var/lib', '/../', 'file/'], '/file'], [['a/b/c/', '../../..'], posixyCwd], + [[], posixyCwd], + [[''], posixyCwd], [['.'], posixyCwd], [['/some/dir', '.', '/absolute/'], '/absolute'], [['/foo/tmp.3/', '../tmp.3/cycles/root.js'], '/foo/tmp.3/cycles/root.js'], diff --git a/test/parallel/test-perf-hooks-histogram.js b/test/parallel/test-perf-hooks-histogram.js index 37fcdfb3fca06c..9e76cca2f4f479 100644 --- a/test/parallel/test-perf-hooks-histogram.js +++ b/test/parallel/test-perf-hooks-histogram.js @@ -97,6 +97,17 @@ const { inspect } = require('util'); }, 50); } +{ + // Tests that the ELD histogram is disposable + let histogram; + { + using hi = monitorEventLoopDelay(); + histogram = hi; + } + // The histogram should already be disabled. + strictEqual(histogram.disable(), false); +} + { const h = createHistogram(); ok(inspect(h, { depth: null }).startsWith('Histogram')); diff --git a/test/parallel/test-permission-fs-internal-module-stat.js b/test/parallel/test-permission-fs-internal-module-stat.js index 5b1dd6679c7019..db7129e8554f23 100644 --- a/test/parallel/test-permission-fs-internal-module-stat.js +++ b/test/parallel/test-permission-fs-internal-module-stat.js @@ -20,19 +20,3 @@ const blockedFile = fixtures.path('permission', 'deny', 'protected-file.md'); const internalFsBinding = internalBinding('fs'); strictEqual(internalFsBinding.internalModuleStat(blockedFile), 0); - -// Only javascript methods can be optimized through %OptimizeFunctionOnNextCall -// This is why we surround the C++ method we want to optimize with a JS function. -function testFastPaths(file) { - return internalFsBinding.internalModuleStat(file); -} - -eval('%PrepareFunctionForOptimization(testFastPaths)'); -testFastPaths(blockedFile); -eval('%OptimizeFunctionOnNextCall(testFastPaths)'); -strictEqual(testFastPaths(blockedFile), 0); - -if (common.isDebug) { - const { getV8FastApiCallCount } = internalBinding('debug'); - strictEqual(getV8FastApiCallCount('fs.internalModuleStat'), 1); -} diff --git a/test/parallel/test-permission-fs-read-entrypoint.js b/test/parallel/test-permission-fs-read-entrypoint.js new file mode 100644 index 00000000000000..631c793e1357f2 --- /dev/null +++ b/test/parallel/test-permission-fs-read-entrypoint.js @@ -0,0 +1,38 @@ +// Flags: --permission --allow-fs-read=* --allow-fs-write=* --allow-child-process +'use strict'; + +const common = require('../common'); +const { isMainThread } = require('worker_threads'); + +if (!isMainThread) { + common.skip('This test only works on a main thread'); +} + +if (!common.hasCrypto) { + common.skip('no crypto'); +} + +const assert = require('assert'); +const fixtures = require('../common/fixtures'); +const { spawnSync } = require('child_process'); + +const file = fixtures.path('permission', 'hello-world.js'); +const simpleLoader = fixtures.path('permission', 'simple-loader.js'); +const fsReadLoader = fixtures.path('permission', 'fs-read-loader.js'); + +[ + '', + simpleLoader, + fsReadLoader, +].forEach((arg0) => { + const { status, stderr } = spawnSync( + process.execPath, + [ + arg0 !== '' ? '-r' : '', + arg0, + '--permission', + file, + ], + ); + assert.strictEqual(status, 0, `${arg0} Error: ${stderr.toString()}`); +}); diff --git a/test/parallel/test-permission-fs-read.js b/test/parallel/test-permission-fs-read.js index b719207bdbd820..2388470a0b42ba 100644 --- a/test/parallel/test-permission-fs-read.js +++ b/test/parallel/test-permission-fs-read.js @@ -32,7 +32,11 @@ const commonPath = path.join(__filename, '../../common'); const { status, stderr } = spawnSync( process.execPath, [ - '--permission', `--allow-fs-read=${file}`, `--allow-fs-read=${commonPathWildcard}`, file, + '--permission', + // Do not uncomment this line + // `--allow-fs-read=${file}`, + `--allow-fs-read=${commonPathWildcard}`, + file, ], { env: { diff --git a/test/parallel/test-process-features.js b/test/parallel/test-process-features.js index 19b1c3a4f480e1..e4365b656df2f5 100644 --- a/test/parallel/test-process-features.js +++ b/test/parallel/test-process-features.js @@ -9,6 +9,7 @@ const expectedKeys = new Map([ ['debug', ['boolean']], ['uv', ['boolean']], ['ipv6', ['boolean']], + ['openssl_is_boringssl', ['boolean']], ['tls_alpn', ['boolean']], ['tls_sni', ['boolean']], ['tls_ocsp', ['boolean']], diff --git a/test/parallel/test-readline-interface.js b/test/parallel/test-readline-interface.js index 12ba0c709622e9..c640654a7c742d 100644 --- a/test/parallel/test-readline-interface.js +++ b/test/parallel/test-readline-interface.js @@ -1202,6 +1202,47 @@ for (let i = 0; i < 12; i++) { fi.emit('data', 'Node.js\n'); } + // Call write after close + { + const [rli, fi] = getInterface({ terminal }); + rli.question('What\'s your name?', common.mustCall((name) => { + assert.strictEqual(name, 'Node.js'); + rli.close(); + assert.throws(() => { + rli.write('I said Node.js'); + }, { + name: 'Error', + code: 'ERR_USE_AFTER_CLOSE' + }); + })); + fi.emit('data', 'Node.js\n'); + } + + // Call pause/resume after close + { + const [rli, fi] = getInterface({ terminal }); + rli.question('What\'s your name?', common.mustCall((name) => { + assert.strictEqual(name, 'Node.js'); + rli.close(); + // No 'resume' nor 'pause' event should be emitted after close + rli.on('resume', common.mustNotCall()); + rli.on('pause', common.mustNotCall()); + assert.throws(() => { + rli.pause(); + }, { + name: 'Error', + code: 'ERR_USE_AFTER_CLOSE' + }); + assert.throws(() => { + rli.resume(); + }, { + name: 'Error', + code: 'ERR_USE_AFTER_CLOSE' + }); + })); + fi.emit('data', 'Node.js\n'); + } + // Can create a new readline Interface with a null output argument { const [rli, fi] = getInterface({ output: null, terminal }); diff --git a/test/parallel/test-readline-promises-interface.js b/test/parallel/test-readline-promises-interface.js index 32aab1b60c2ee5..12d72f49735401 100644 --- a/test/parallel/test-readline-promises-interface.js +++ b/test/parallel/test-readline-promises-interface.js @@ -204,7 +204,7 @@ function assertCursorRowsAndCols(rli, rows, cols) { fi.emit('data', character); } fi.emit('data', '\n'); - rli.close(); + fi.end(); } // \t when there is no completer function should behave like an ordinary diff --git a/test/parallel/test-readline-promises-tab-complete.js b/test/parallel/test-readline-promises-tab-complete.js index d8b0ac30ee779d..602bdd9e7965bf 100644 --- a/test/parallel/test-readline-promises-tab-complete.js +++ b/test/parallel/test-readline-promises-tab-complete.js @@ -80,7 +80,7 @@ if (process.env.TERM === 'dumb') { output = ''; }); } - rli.close(); + fi.end(); }); }); }); @@ -114,5 +114,5 @@ if (process.env.TERM === 'dumb') { assert.match(output, /^Tab completion error: Error: message/); output = ''; }); - rli.close(); + fi.end(); } diff --git a/test/parallel/test-repl-close.js b/test/parallel/test-repl-close.js new file mode 100644 index 00000000000000..0e20ddfb0517fc --- /dev/null +++ b/test/parallel/test-repl-close.js @@ -0,0 +1,18 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const cp = require('child_process'); + +const child = cp.spawn(process.execPath, ['--interactive']); + +let output = ''; +child.stdout.on('data', (data) => { + output += data; +}); + +child.on('exit', common.mustCall(() => { + assert.doesNotMatch(output, /Uncaught Error/); +})); + +child.stdin.write('await null;\n'); +child.stdin.write('.exit\n'); diff --git a/test/parallel/test-repl-completion-on-getters-disabled.js b/test/parallel/test-repl-completion-on-getters-disabled.js new file mode 100644 index 00000000000000..17821bccd761b5 --- /dev/null +++ b/test/parallel/test-repl-completion-on-getters-disabled.js @@ -0,0 +1,119 @@ +'use strict'; + +const common = require('../common'); +const assert = require('node:assert'); +const { describe, test } = require('node:test'); + +const ArrayStream = require('../common/arraystream'); + +const repl = require('node:repl'); + +function runCompletionTests(replInit, tests) { + const stream = new ArrayStream(); + const testRepl = repl.start({ stream }); + + // Some errors are passed to the domain + testRepl._domain.on('error', assert.ifError); + + testRepl.write(replInit); + testRepl.write('\n'); + + tests.forEach(([query, expectedCompletions]) => { + testRepl.complete(query, common.mustCall((error, data) => { + const actualCompletions = data[0]; + if (expectedCompletions.length === 0) { + assert.deepStrictEqual(actualCompletions, []); + } else { + expectedCompletions.forEach((expectedCompletion) => + assert(actualCompletions.includes(expectedCompletion), `completion '${expectedCompletion}' not found`) + ); + } + })); + }); +} + +describe('REPL completion in relation of getters', () => { + describe('standard behavior without proxies/getters', () => { + test('completion of nested properties of an undeclared objects', () => { + runCompletionTests('', [ + ['nonExisting.', []], + ['nonExisting.f', []], + ['nonExisting.foo', []], + ['nonExisting.foo.', []], + ['nonExisting.foo.bar.b', []], + ]); + }); + + test('completion of nested properties on plain objects', () => { + runCompletionTests('const plainObj = { foo: { bar: { baz: {} } } };', [ + ['plainObj.', ['plainObj.foo']], + ['plainObj.f', ['plainObj.foo']], + ['plainObj.foo', ['plainObj.foo']], + ['plainObj.foo.', ['plainObj.foo.bar']], + ['plainObj.foo.bar.b', ['plainObj.foo.bar.baz']], + ['plainObj.fooBar.', []], + ['plainObj.fooBar.baz', []], + ]); + }); + }); + + describe('completions on an object with getters', () => { + test(`completions are generated for properties that don't trigger getters`, () => { + runCompletionTests( + ` + const objWithGetters = { + foo: { bar: { baz: {} }, get gBar() { return { baz: {} } } }, + get gFoo() { return { bar: { baz: {} } }; } + }; + `, [ + ['objWithGetters.', ['objWithGetters.foo']], + ['objWithGetters.f', ['objWithGetters.foo']], + ['objWithGetters.foo', ['objWithGetters.foo']], + ['objWithGetters.foo.', ['objWithGetters.foo.bar']], + ['objWithGetters.foo.bar.b', ['objWithGetters.foo.bar.baz']], + ['objWithGetters.gFo', ['objWithGetters.gFoo']], + ['objWithGetters.foo.gB', ['objWithGetters.foo.gBar']], + ]); + }); + + test('no completions are generated for properties that trigger getters', () => { + runCompletionTests( + ` + const objWithGetters = { + foo: { bar: { baz: {} }, get gBar() { return { baz: {} } } }, + get gFoo() { return { bar: { baz: {} } }; } + }; + `, + [ + ['objWithGetters.gFoo.', []], + ['objWithGetters.gFoo.b', []], + ['objWithGetters.gFoo.bar.b', []], + ['objWithGetters.foo.gBar.', []], + ['objWithGetters.foo.gBar.b', []], + ]); + }); + }); + + describe('completions on proxies', () => { + test('no completions are generated for a proxy object', () => { + runCompletionTests('const proxyObj = new Proxy({ foo: { bar: { baz: {} } } }, {});', [ + ['proxyObj.', []], + ['proxyObj.f', []], + ['proxyObj.foo', []], + ['proxyObj.foo.', []], + ['proxyObj.foo.bar.b', []], + ]); + }); + + test('no completions are generated for a proxy present in a standard object', () => { + runCompletionTests( + 'const objWithProxy = { foo: { bar: new Proxy({ baz: {} }, {}) } };', [ + ['objWithProxy.', ['objWithProxy.foo']], + ['objWithProxy.foo', ['objWithProxy.foo']], + ['objWithProxy.foo.', ['objWithProxy.foo.bar']], + ['objWithProxy.foo.b', ['objWithProxy.foo.bar']], + ['objWithProxy.foo.bar.', []], + ]); + }); + }); +}); diff --git a/test/parallel/test-repl-import-referrer.js b/test/parallel/test-repl-import-referrer.js index bc2cda49b496fb..8e242f01922d58 100644 --- a/test/parallel/test-repl-import-referrer.js +++ b/test/parallel/test-repl-import-referrer.js @@ -15,11 +15,11 @@ child.stdout.on('data', (data) => { }); child.on('exit', common.mustCall(() => { - const results = output.replace(/^> /mg, '').split('\n').slice(2); - assert.deepStrictEqual( - results, - ['[Module: null prototype] { message: \'A message\' }', ''] - ); + const result = output.replace(/^> /mg, '').split('\n').slice(2); + assert.deepStrictEqual(result, [ + '[Module: null prototype] { message: \'A message\' }', + '', + ]); })); child.stdin.write('await import(\'./message.mjs\');\n'); diff --git a/test/parallel/test-repl-no-terminal.js b/test/parallel/test-repl-no-terminal.js index 60f97b52e26942..f569adcc6322cf 100644 --- a/test/parallel/test-repl-no-terminal.js +++ b/test/parallel/test-repl-no-terminal.js @@ -1,7 +1,12 @@ 'use strict'; const common = require('../common'); - +const ArrayStream = require('../common/arraystream'); const repl = require('repl'); -const r = repl.start({ terminal: false }); -r.setupHistory('/nonexistent/file', common.mustSucceed()); -process.stdin.unref?.(); + +const stream = new ArrayStream(); + +const replServer = repl.start({ terminal: false, input: stream, output: stream }); + +replServer.setupHistory('/nonexistent/file', common.mustSucceed(() => { + replServer.close(); +})); diff --git a/test/parallel/test-repl-persistent-history.js b/test/parallel/test-repl-persistent-history.js index 2ec5a315c8a7c3..efd1aa141357c2 100644 --- a/test/parallel/test-repl-persistent-history.js +++ b/test/parallel/test-repl-persistent-history.js @@ -242,7 +242,7 @@ function runTest(assertCleaned) { } repl.once('close', () => { - if (repl._flushing) { + if (repl.historyManager.isFlushing) { repl.once('flushHistory', onClose); return; } diff --git a/test/parallel/test-repl-programmatic-history-setup-history.js b/test/parallel/test-repl-programmatic-history-setup-history.js new file mode 100644 index 00000000000000..038972b8566ba0 --- /dev/null +++ b/test/parallel/test-repl-programmatic-history-setup-history.js @@ -0,0 +1,281 @@ +'use strict'; + +const common = require('../common'); +const fixtures = require('../common/fixtures'); +const stream = require('stream'); +const REPL = require('repl'); +const assert = require('assert'); +const fs = require('fs'); +const os = require('os'); + +if (process.env.TERM === 'dumb') { + common.skip('skipping - dumb terminal'); +} + +const tmpdir = require('../common/tmpdir'); +tmpdir.refresh(); + +// Mock os.homedir() +os.homedir = function() { + return tmpdir.path; +}; + +// Create an input stream specialized for testing an array of actions +class ActionStream extends stream.Stream { + run(data) { + const _iter = data[Symbol.iterator](); + const doAction = () => { + const next = _iter.next(); + if (next.done) { + // Close the repl. Note that it must have a clean prompt to do so. + setImmediate(() => { + this.emit('keypress', '', { ctrl: true, name: 'd' }); + }); + return; + } + const action = next.value; + + if (typeof action === 'object') { + this.emit('keypress', '', action); + } else { + this.emit('data', action); + } + setImmediate(doAction); + }; + doAction(); + } + resume() {} + pause() {} +} +ActionStream.prototype.readable = true; + + +// Mock keys +const UP = { name: 'up' }; +const DOWN = { name: 'down' }; +const ENTER = { name: 'enter' }; +const CLEAR = { ctrl: true, name: 'u' }; + +// File paths +const historyFixturePath = fixtures.path('.node_repl_history'); +const historyPath = tmpdir.resolve('.fixture_copy_repl_history'); +const historyPathFail = fixtures.path('nonexistent_folder', 'filename'); +const defaultHistoryPath = tmpdir.resolve('.node_repl_history'); +const emptyHiddenHistoryPath = fixtures.path('.empty-hidden-repl-history-file'); +const devNullHistoryPath = tmpdir.resolve('.dev-null-repl-history-file'); +// Common message bits +const prompt = '> '; +const replDisabled = '\nPersistent history support disabled. Set the ' + + 'NODE_REPL_HISTORY environment\nvariable to a valid, ' + + 'user-writable path to enable.\n'; +const homedirErr = '\nError: Could not get the home directory.\n' + + 'REPL session history will not be persisted.\n'; +const replFailedRead = '\nError: Could not open history file.\n' + + 'REPL session history will not be persisted.\n'; + +const tests = [ + // Makes sure that, if the history file is empty, the history is disabled + { + env: { NODE_REPL_HISTORY: '' }, + test: [UP], + expected: [prompt, replDisabled, prompt] + }, + // Makes sure that, if the history file is empty (when trimmed), the history is disabled + { + env: { NODE_REPL_HISTORY: ' ' }, + test: [UP], + expected: [prompt, replDisabled, prompt] + }, + // Properly loads the history file + { + env: { NODE_REPL_HISTORY: historyPath }, + test: [UP, CLEAR], + expected: [prompt, `${prompt}'you look fabulous today'`, prompt] + }, + // Properly navigates newly added history items + { + env: {}, + test: [UP, '21', ENTER, "'42'", ENTER], + expected: [ + prompt, + '2', '1', '21\n', prompt, + "'", '4', '2', "'", "'42'\n", prompt, + ], + clean: false + }, + { // Requires the above test case, because navigating old history + env: {}, + test: [UP, UP, UP, DOWN, ENTER], + expected: [ + prompt, + `${prompt}'42'`, + `${prompt}21`, + prompt, + `${prompt}21`, + '21\n', + prompt, + ] + }, + // Making sure that only the configured number of history items are kept + { + env: { NODE_REPL_HISTORY: historyPath, + NODE_REPL_HISTORY_SIZE: 1 }, + test: [UP, UP, DOWN, CLEAR], + expected: [ + prompt, + `${prompt}'you look fabulous today'`, + prompt, + `${prompt}'you look fabulous today'`, + prompt, + ] + }, + // Making sure that the history file is not written to if it is not writable + { + env: { NODE_REPL_HISTORY: historyPathFail, + NODE_REPL_HISTORY_SIZE: 1 }, + test: [UP], + expected: [prompt, replFailedRead, prompt, replDisabled, prompt] + }, + // Checking the history file permissions + { + before: function before() { + if (common.isWindows) { + const execSync = require('child_process').execSync; + execSync(`ATTRIB +H "${emptyHiddenHistoryPath}"`, (err) => { + assert.ifError(err); + }); + } + }, + env: { NODE_REPL_HISTORY: emptyHiddenHistoryPath }, + test: [UP], + expected: [prompt] + }, + // Checking failures when os.homedir() fails + { + before: function before() { + // Mock os.homedir() failure + os.homedir = function() { + throw new Error('os.homedir() failure'); + }; + }, + env: {}, + test: [UP], + expected: [prompt, homedirErr, prompt, replDisabled, prompt] + }, + // Checking that the history file can be set to /dev/null + { + before: function before() { + if (!common.isWindows) + fs.symlinkSync('/dev/null', devNullHistoryPath); + }, + env: { NODE_REPL_HISTORY: devNullHistoryPath }, + test: [UP], + expected: [prompt] + }, +]; +const numtests = tests.length; + + +function cleanupTmpFile() { + try { + // Write over the file, clearing any history + fs.writeFileSync(defaultHistoryPath, ''); + } catch (err) { + if (err.code === 'ENOENT') return true; + throw err; + } + return true; +} + +// Copy our fixture to the tmp directory +fs.createReadStream(historyFixturePath) + .pipe(fs.createWriteStream(historyPath)).on('unpipe', () => runTest()); + +const runTestWrap = common.mustCall(runTest, numtests); + +function runTest(assertCleaned) { + const opts = tests.shift(); + if (!opts) return; // All done + + if (assertCleaned) { + try { + assert.strictEqual(fs.readFileSync(defaultHistoryPath, 'utf8'), ''); + } catch (e) { + if (e.code !== 'ENOENT') { + console.error(`Failed test # ${numtests - tests.length}`); + throw e; + } + } + } + + const test = opts.test; + const expected = opts.expected; + const clean = opts.clean; + const before = opts.before; + const size = opts.env.NODE_REPL_HISTORY_SIZE; + const filePath = opts.env.NODE_REPL_HISTORY; + + if (before) before(); + + const repl = REPL.start({ + input: new ActionStream(), + output: new stream.Writable({ + write(chunk, _, next) { + const output = chunk.toString(); + + // Ignore escapes and blank lines + if (output.charCodeAt(0) === 27 || /^[\r\n]+$/.test(output)) + return next(); + + try { + assert.strictEqual(output, expected.shift()); + } catch (err) { + console.error(`Failed test # ${numtests - tests.length}`); + throw err; + } + next(); + } + }), + prompt: prompt, + useColors: false, + terminal: true, + }); + + repl.setupHistory({ + size, + filePath, + onHistoryFileLoaded, + removeHistoryDuplicates: false + }); + + function onHistoryFileLoaded(err, repl) { + if (err) { + console.error(`Failed test # ${numtests - tests.length}`); + throw err; + } + + repl.once('close', () => { + if (repl.historyManager.isFlushing) { + repl.once('flushHistory', onClose); + return; + } + + onClose(); + }); + + function onClose() { + const cleaned = clean === false ? false : cleanupTmpFile(); + + try { + // Ensure everything that we expected was output + assert.strictEqual(expected.length, 0); + setImmediate(runTestWrap, cleaned); + } catch (err) { + console.error(`Failed test # ${numtests - tests.length}`); + throw err; + } + } + + repl.inputStream.run(test); + } +} diff --git a/test/parallel/test-repl-programmatic-history.js b/test/parallel/test-repl-programmatic-history.js index 4e8887e0e08d56..c762e83840e41c 100644 --- a/test/parallel/test-repl-programmatic-history.js +++ b/test/parallel/test-repl-programmatic-history.js @@ -204,7 +204,7 @@ function runTest(assertCleaned) { const clean = opts.clean; const before = opts.before; const historySize = opts.env.NODE_REPL_HISTORY_SIZE; - const historyFile = opts.env.NODE_REPL_HISTORY; + const file = opts.env.NODE_REPL_HISTORY; if (before) before(); @@ -230,17 +230,17 @@ function runTest(assertCleaned) { prompt: prompt, useColors: false, terminal: true, - historySize: historySize + historySize }); - repl.setupHistory(historyFile, function(err, repl) { + repl.setupHistory(file, function(err, repl) { if (err) { console.error(`Failed test # ${numtests - tests.length}`); throw err; } repl.once('close', () => { - if (repl._flushing) { + if (repl.historyManager.isFlushing) { repl.once('flushHistory', onClose); return; } diff --git a/test/parallel/test-repl-save-load.js b/test/parallel/test-repl-save-load.js index bb5130d1d71bbf..dd4eaccefff705 100644 --- a/test/parallel/test-repl-save-load.js +++ b/test/parallel/test-repl-save-load.js @@ -27,138 +27,155 @@ const fs = require('fs'); const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); -const repl = require('repl'); - -const works = [['inner.one'], 'inner.o']; - -const putIn = new ArrayStream(); -const testMe = repl.start('', putIn); - -// Some errors might be passed to the domain. -testMe._domain.on('error', function(reason) { - const err = new Error('Test failed'); - err.reason = reason; - throw err; -}); - -const testFile = [ - 'let inner = (function() {', - ' return {one:1};', - '})()', -]; -const saveFileName = tmpdir.resolve('test.save.js'); - -// Add some data. -putIn.run(testFile); - -// Save it to a file. -putIn.run([`.save ${saveFileName}`]); - -// The file should have what I wrote. -assert.strictEqual(fs.readFileSync(saveFileName, 'utf8'), - testFile.join('\n')); - -// Make sure that the REPL data is "correct". -testMe.complete('inner.o', common.mustSucceed((data) => { - assert.deepStrictEqual(data, works); -})); - -// Clear the REPL. -putIn.run(['.clear']); - -testMe._sawKeyPress = true; -// Load the file back in. -putIn.run([`.load ${saveFileName}`]); - -// Make sure loading doesn't insert extra indentation -// https://github.com/nodejs/node/issues/47673 -assert.strictEqual(testMe.line, ''); - -// Make sure that the REPL data is "correct". -testMe.complete('inner.o', common.mustSucceed((data) => { - assert.deepStrictEqual(data, works); -})); - -// Clear the REPL. -putIn.run(['.clear']); - -let loadFile = tmpdir.resolve('file.does.not.exist'); - -// Should not break. -putIn.write = common.mustCall(function(data) { - // Make sure I get a failed to load message and not some crazy error. - assert.strictEqual(data, `Failed to load: ${loadFile}\n`); - // Eat me to avoid work. - putIn.write = () => {}; -}); -putIn.run([`.load ${loadFile}`]); - -// Throw error on loading directory. -loadFile = tmpdir.path; -putIn.write = common.mustCall(function(data) { - assert.strictEqual(data, `Failed to load: ${loadFile} is not a valid file\n`); - putIn.write = () => {}; -}); -putIn.run([`.load ${loadFile}`]); - -// Clear the REPL. -putIn.run(['.clear']); - -// NUL (\0) is disallowed in filenames in UNIX-like operating systems and -// Windows so we can use that to test failed saves. -const invalidFileName = tmpdir.resolve('\0\0\0\0\0'); - -// Should not break. -putIn.write = common.mustCall(function(data) { - // Make sure I get a failed to save message and not some other error. - assert.strictEqual(data, `Failed to save: ${invalidFileName}\n`); - // Reset to no-op. - putIn.write = () => {}; -}); - -// Save it to a file. -putIn.run([`.save ${invalidFileName}`]); - -{ - // Save .editor mode code. - const cmds = [ - 'function testSave() {', - 'return "saved";', - '}', - ]; - const putIn = new ArrayStream(); - const replServer = repl.start({ terminal: true, stream: putIn }); - - putIn.run(['.editor']); - putIn.run(cmds); - replServer.write('', { ctrl: true, name: 'd' }); - - putIn.run([`.save ${saveFileName}`]); - replServer.close(); - assert.strictEqual(fs.readFileSync(saveFileName, 'utf8'), - `${cmds.join('\n')}\n`); -} +// TODO: the following async IIFE and the completePromise function are necessary because +// the reply tests are all run against the same repl instance (testMe) and thus coordination +// needs to be in place for the tests not to interfere with each other, this is really +// not ideal, the tests in this file should be refactored so that each use its own isolated +// repl instance, making sure that no special coordination needs to be in place for them +// and also allowing the tests to all be run in parallel +(async () => { + const repl = require('repl'); -// Check if the file is present when using save + const works = [['inner.one'], 'inner.o']; -// Clear the REPL. -putIn.run(['.clear']); - -// Error message when using save without a file -putIn.write = common.mustCall(function(data) { - assert.strictEqual(data, 'The "file" argument must be specified\n'); - putIn.write = () => {}; -}); -putIn.run(['.save']); + const putIn = new ArrayStream(); + const testMe = repl.start('', putIn); + + // Some errors might be passed to the domain. + testMe._domain.on('error', function(reason) { + const err = new Error('Test failed'); + err.reason = reason; + throw err; + }); + + async function completePromise(query, callback) { + return new Promise((resolve) => { + testMe.complete(query, (...args) => { + callback(...args); + resolve(); + }); + }); + } + + const testFile = [ + 'let inner = (function() {', + ' return {one:1};', + '})()', + ]; + const saveFileName = tmpdir.resolve('test.save.js'); -// Check if the file is present when using load + // Add some data. + putIn.run(testFile); -// Clear the REPL. -putIn.run(['.clear']); + // Save it to a file. + putIn.run([`.save ${saveFileName}`]); -// Error message when using load without a file -putIn.write = common.mustCall(function(data) { - assert.strictEqual(data, 'The "file" argument must be specified\n'); - putIn.write = () => {}; -}); -putIn.run(['.load']); + // The file should have what I wrote. + assert.strictEqual(fs.readFileSync(saveFileName, 'utf8'), + testFile.join('\n')); + + // Make sure that the REPL data is "correct". + await completePromise('inner.o', common.mustSucceed((data) => { + assert.deepStrictEqual(data, works); + })); + + // Clear the REPL. + putIn.run(['.clear']); + + testMe._sawKeyPress = true; + // Load the file back in. + putIn.run([`.load ${saveFileName}`]); + + // Make sure loading doesn't insert extra indentation + // https://github.com/nodejs/node/issues/47673 + assert.strictEqual(testMe.line, ''); + + // Make sure that the REPL data is "correct". + await completePromise('inner.o', common.mustSucceed((data) => { + assert.deepStrictEqual(data, works); + })); + + // Clear the REPL. + putIn.run(['.clear']); + + let loadFile = tmpdir.resolve('file.does.not.exist'); + + // Should not break. + putIn.write = common.mustCall(function(data) { + // Make sure I get a failed to load message and not some crazy error. + assert.strictEqual(data, `Failed to load: ${loadFile}\n`); + // Eat me to avoid work. + putIn.write = () => {}; + }); + putIn.run([`.load ${loadFile}`]); + + // Throw error on loading directory. + loadFile = tmpdir.path; + putIn.write = common.mustCall(function(data) { + assert.strictEqual(data, `Failed to load: ${loadFile} is not a valid file\n`); + putIn.write = () => {}; + }); + putIn.run([`.load ${loadFile}`]); + + // Clear the REPL. + putIn.run(['.clear']); + + // NUL (\0) is disallowed in filenames in UNIX-like operating systems and + // Windows so we can use that to test failed saves. + const invalidFileName = tmpdir.resolve('\0\0\0\0\0'); + + // Should not break. + putIn.write = common.mustCall(function(data) { + // Make sure I get a failed to save message and not some other error. + assert.strictEqual(data, `Failed to save: ${invalidFileName}\n`); + // Reset to no-op. + putIn.write = () => {}; + }); + + // Save it to a file. + putIn.run([`.save ${invalidFileName}`]); + + { + // Save .editor mode code. + const cmds = [ + 'function testSave() {', + 'return "saved";', + '}', + ]; + const putIn = new ArrayStream(); + const replServer = repl.start({ terminal: true, stream: putIn }); + + putIn.run(['.editor']); + putIn.run(cmds); + replServer.write('', { ctrl: true, name: 'd' }); + + putIn.run([`.save ${saveFileName}`]); + replServer.close(); + assert.strictEqual(fs.readFileSync(saveFileName, 'utf8'), + `${cmds.join('\n')}\n`); + } + + // Check if the file is present when using save + + // Clear the REPL. + putIn.run(['.clear']); + + // Error message when using save without a file + putIn.write = common.mustCall(function(data) { + assert.strictEqual(data, 'The "file" argument must be specified\n'); + putIn.write = () => {}; + }); + putIn.run(['.save']); + + // Check if the file is present when using load + + // Clear the REPL. + putIn.run(['.clear']); + + // Error message when using load without a file + putIn.write = common.mustCall(function(data) { + assert.strictEqual(data, 'The "file" argument must be specified\n'); + putIn.write = () => {}; + }); + putIn.run(['.load']); +})().then(common.mustCall()); diff --git a/test/parallel/test-repl-tab-complete.js b/test/parallel/test-repl-tab-complete.js index c79162129bd69b..cbc82e5bf0296e 100644 --- a/test/parallel/test-repl-tab-complete.js +++ b/test/parallel/test-repl-tab-complete.js @@ -53,568 +53,589 @@ function getNoResultsFunction() { }); } -const works = [['inner.one'], 'inner.o']; -const putIn = new ArrayStream(); -const testMe = repl.start({ - prompt: '', - input: putIn, - output: process.stdout, - allowBlockingCompletions: true -}); +// TODO: the following async IIFE and the completePromise function are necessary because +// the reply tests are all run against the same repl instance (testMe) and thus coordination +// needs to be in place for the tests not to interfere with each other, this is really +// not ideal, the tests in this file should be refactored so that each use its own isolated +// repl instance, making sure that no special coordination needs to be in place for them +// and also allowing the tests to all be run in parallel +(async () => { + const works = [['inner.one'], 'inner.o']; + const putIn = new ArrayStream(); + const testMe = repl.start({ + prompt: '', + input: putIn, + output: process.stdout, + allowBlockingCompletions: true + }); -// Some errors are passed to the domain, but do not callback -testMe._domain.on('error', assert.ifError); + async function completePromise(query, callback) { + return new Promise((resolve) => { + testMe.complete(query, (...args) => { + callback(...args); + resolve(); + }); + }); + } -// Tab Complete will not break in an object literal -putIn.run([ - 'var inner = {', - 'one:1', -]); -testMe.complete('inner.o', getNoResultsFunction()); + // Some errors are passed to the domain, but do not callback + testMe._domain.on('error', assert.ifError); -testMe.complete('console.lo', common.mustCall(function(error, data) { - assert.deepStrictEqual(data, [['console.log'], 'console.lo']); -})); + // Tab Complete will not break in an object literal + putIn.run([ + 'var inner = {', + 'one:1', + ]); + await completePromise('inner.o', getNoResultsFunction()); -testMe.complete('console?.lo', common.mustCall((error, data) => { - assert.deepStrictEqual(data, [['console?.log'], 'console?.lo']); -})); + await completePromise('console.lo', common.mustCall(function(error, data) { + assert.deepStrictEqual(data, [['console.log'], 'console.lo']); + })); -testMe.complete('console?.zzz', common.mustCall((error, data) => { - assert.deepStrictEqual(data, [[], 'console?.zzz']); -})); + await completePromise('console?.lo', common.mustCall((error, data) => { + assert.deepStrictEqual(data, [['console?.log'], 'console?.lo']); + })); -testMe.complete('console?.', common.mustCall((error, data) => { - assert(data[0].includes('console?.log')); - assert.strictEqual(data[1], 'console?.'); -})); + await completePromise('console?.zzz', common.mustCall((error, data) => { + assert.deepStrictEqual(data, [[], 'console?.zzz']); + })); -// Tab Complete will return globally scoped variables -putIn.run(['};']); -testMe.complete('inner.o', common.mustCall(function(error, data) { - assert.deepStrictEqual(data, works); -})); + await completePromise('console?.', common.mustCall((error, data) => { + assert(data[0].includes('console?.log')); + assert.strictEqual(data[1], 'console?.'); + })); -putIn.run(['.clear']); - -// Tab Complete will not break in an ternary operator with () -putIn.run([ - 'var inner = ( true ', - '?', - '{one: 1} : ', -]); -testMe.complete('inner.o', getNoResultsFunction()); - -putIn.run(['.clear']); - -// Tab Complete will return a simple local variable -putIn.run([ - 'var top = function() {', - 'var inner = {one:1};', -]); -testMe.complete('inner.o', getNoResultsFunction()); - -// When you close the function scope tab complete will not return the -// locally scoped variable -putIn.run(['};']); -testMe.complete('inner.o', getNoResultsFunction()); - -putIn.run(['.clear']); - -// Tab Complete will return a complex local variable -putIn.run([ - 'var top = function() {', - 'var inner = {', - ' one:1', - '};', -]); -testMe.complete('inner.o', getNoResultsFunction()); - -putIn.run(['.clear']); - -// Tab Complete will return a complex local variable even if the function -// has parameters -putIn.run([ - 'var top = function(one, two) {', - 'var inner = {', - ' one:1', - '};', -]); -testMe.complete('inner.o', getNoResultsFunction()); - -putIn.run(['.clear']); - -// Tab Complete will return a complex local variable even if the -// scope is nested inside an immediately executed function -putIn.run([ - 'var top = function() {', - '(function test () {', - 'var inner = {', - ' one:1', - '};', -]); -testMe.complete('inner.o', getNoResultsFunction()); - -putIn.run(['.clear']); - -// The definition has the params and { on a separate line. -putIn.run([ - 'var top = function() {', - 'r = function test (', - ' one, two) {', - 'var inner = {', - ' one:1', - '};', -]); -testMe.complete('inner.o', getNoResultsFunction()); - -putIn.run(['.clear']); - -// Currently does not work, but should not break, not the { -putIn.run([ - 'var top = function() {', - 'r = function test ()', - '{', - 'var inner = {', - ' one:1', - '};', -]); -testMe.complete('inner.o', getNoResultsFunction()); - -putIn.run(['.clear']); - -// Currently does not work, but should not break -putIn.run([ - 'var top = function() {', - 'r = function test (', - ')', - '{', - 'var inner = {', - ' one:1', - '};', -]); -testMe.complete('inner.o', getNoResultsFunction()); - -putIn.run(['.clear']); - -// Make sure tab completion works on non-Objects -putIn.run([ - 'var str = "test";', -]); -testMe.complete('str.len', common.mustCall(function(error, data) { - assert.deepStrictEqual(data, [['str.length'], 'str.len']); -})); + // Tab Complete will return globally scoped variables + putIn.run(['};']); + await completePromise('inner.o', common.mustCall(function(error, data) { + assert.deepStrictEqual(data, works); + })); -putIn.run(['.clear']); - -// Tab completion should be case-insensitive if member part is lower-case -putIn.run([ - 'var foo = { barBar: 1, BARbuz: 2, barBLA: 3 };', -]); -testMe.complete( - 'foo.b', - common.mustCall(function(error, data) { - assert.deepStrictEqual(data, [ - ['foo.BARbuz', 'foo.barBLA', 'foo.barBar'], - 'foo.b', - ]); - }) -); - -putIn.run(['.clear']); - -// Tab completion should be case-insensitive if member part is upper-case -putIn.run([ - 'var foo = { barBar: 1, BARbuz: 2, barBLA: 3 };', -]); -testMe.complete( - 'foo.B', - common.mustCall(function(error, data) { - assert.deepStrictEqual(data, [ - ['foo.BARbuz', 'foo.barBLA', 'foo.barBar'], - 'foo.B', - ]); - }) -); - -putIn.run(['.clear']); - -// Tab completion should not break on spaces -const spaceTimeout = setTimeout(function() { - throw new Error('timeout'); -}, 1000); - -testMe.complete(' ', common.mustSucceed((data) => { - assert.strictEqual(data[1], ''); - assert.ok(data[0].includes('globalThis')); - clearTimeout(spaceTimeout); -})); + putIn.run(['.clear']); -// Tab completion should pick up the global "toString" object, and -// any other properties up the "global" object's prototype chain -testMe.complete('toSt', common.mustCall(function(error, data) { - assert.deepStrictEqual(data, [['toString'], 'toSt']); -})); + // Tab Complete will not break in an ternary operator with () + putIn.run([ + 'var inner = ( true ', + '?', + '{one: 1} : ', + ]); + await completePromise('inner.o', getNoResultsFunction()); -// Own properties should shadow properties on the prototype -putIn.run(['.clear']); -putIn.run([ - 'var x = Object.create(null);', - 'x.a = 1;', - 'x.b = 2;', - 'var y = Object.create(x);', - 'y.a = 3;', - 'y.c = 4;', -]); -testMe.complete('y.', common.mustCall(function(error, data) { - assert.deepStrictEqual(data, [['y.b', '', 'y.a', 'y.c'], 'y.']); -})); + putIn.run(['.clear']); -// Tab complete provides built in libs for require() -putIn.run(['.clear']); + // Tab Complete will return a simple local variable + putIn.run([ + 'var top = function() {', + 'var inner = {one:1};', + ]); + await completePromise('inner.o', getNoResultsFunction()); -testMe.complete('require(\'', common.mustCall(function(error, data) { - assert.strictEqual(error, null); - publicModules.forEach((lib) => { - assert( - data[0].includes(lib) && (lib.startsWith('node:') || data[0].includes(`node:${lib}`)), - `${lib} not found` - ); - }); - const newModule = 'foobar'; - assert(!builtinModules.includes(newModule)); - repl.builtinModules.push(newModule); - testMe.complete('require(\'', common.mustCall((_, [modules]) => { - assert.strictEqual(data[0].length + 1, modules.length); - assert(modules.includes(newModule)); + // When you close the function scope tab complete will not return the + // locally scoped variable + putIn.run(['};']); + await completePromise('inner.o', getNoResultsFunction()); + + putIn.run(['.clear']); + + // Tab Complete will return a complex local variable + putIn.run([ + 'var top = function() {', + 'var inner = {', + ' one:1', + '};', + ]); + await completePromise('inner.o', getNoResultsFunction()); + + putIn.run(['.clear']); + + // Tab Complete will return a complex local variable even if the function + // has parameters + putIn.run([ + 'var top = function(one, two) {', + 'var inner = {', + ' one:1', + '};', + ]); + await completePromise('inner.o', getNoResultsFunction()); + + putIn.run(['.clear']); + + // Tab Complete will return a complex local variable even if the + // scope is nested inside an immediately executed function + putIn.run([ + 'var top = function() {', + '(function test () {', + 'var inner = {', + ' one:1', + '};', + ]); + await completePromise('inner.o', getNoResultsFunction()); + + putIn.run(['.clear']); + + // The definition has the params and { on a separate line. + putIn.run([ + 'var top = function() {', + 'r = function test (', + ' one, two) {', + 'var inner = {', + ' one:1', + '};', + ]); + await completePromise('inner.o', getNoResultsFunction()); + + putIn.run(['.clear']); + + // Currently does not work, but should not break, not the { + putIn.run([ + 'var top = function() {', + 'r = function test ()', + '{', + 'var inner = {', + ' one:1', + '};', + ]); + await completePromise('inner.o', getNoResultsFunction()); + + putIn.run(['.clear']); + + // Currently does not work, but should not break + putIn.run([ + 'var top = function() {', + 'r = function test (', + ')', + '{', + 'var inner = {', + ' one:1', + '};', + ]); + await completePromise('inner.o', getNoResultsFunction()); + + putIn.run(['.clear']); + + // Make sure tab completion works on non-Objects + putIn.run([ + 'var str = "test";', + ]); + // TODO + await completePromise('str.len', common.mustCall(function(error, data) { + assert.deepStrictEqual(data, [['str.length'], 'str.len']); })); -})); -testMe.complete("require\t( 'n", common.mustCall(function(error, data) { - assert.strictEqual(error, null); - assert.strictEqual(data.length, 2); - assert.strictEqual(data[1], 'n'); - // require(...) completions include `node:`-prefixed modules: - let lastIndex = -1; + putIn.run(['.clear']); - publicModules.filter((lib) => !lib.startsWith('node:')).forEach((lib, index) => { - lastIndex = data[0].indexOf(`node:${lib}`); - assert.notStrictEqual(lastIndex, -1); - }); - assert.strictEqual(data[0][lastIndex + 1], ''); - // There is only one Node.js module that starts with n: - assert.strictEqual(data[0][lastIndex + 2], 'net'); - assert.strictEqual(data[0][lastIndex + 3], ''); - // It's possible to pick up non-core modules too - data[0].slice(lastIndex + 4).forEach((completion) => { - assert.match(completion, /^n/); - }); -})); + // Tab completion should be case-insensitive if member part is lower-case + putIn.run([ + 'var foo = { barBar: 1, BARbuz: 2, barBLA: 3 };', + ]); + await completePromise( + 'foo.b', + common.mustCall(function(error, data) { + assert.deepStrictEqual(data, [ + ['foo.BARbuz', 'foo.barBLA', 'foo.barBar'], + 'foo.b', + ]); + }) + ); -{ - const expected = ['@nodejsscope', '@nodejsscope/']; - // Require calls should handle all types of quotation marks. - for (const quotationMark of ["'", '"', '`']) { - putIn.run(['.clear']); - testMe.complete('require(`@nodejs', common.mustCall((err, data) => { - assert.strictEqual(err, null); - assert.deepStrictEqual(data, [expected, '@nodejs']); - })); + putIn.run(['.clear']); - putIn.run(['.clear']); - // Completions should not be greedy in case the quotation ends. - const input = `require(${quotationMark}@nodejsscope${quotationMark}`; - testMe.complete(input, common.mustCall((err, data) => { - assert.strictEqual(err, null); - assert.deepStrictEqual(data, [[], undefined]); - })); - } -} + // Tab completion should be case-insensitive if member part is upper-case + putIn.run([ + 'var foo = { barBar: 1, BARbuz: 2, barBLA: 3 };', + ]); + await completePromise( + 'foo.B', + common.mustCall(function(error, data) { + assert.deepStrictEqual(data, [ + ['foo.BARbuz', 'foo.barBLA', 'foo.barBar'], + 'foo.B', + ]); + }) + ); -{ putIn.run(['.clear']); - // Completions should find modules and handle whitespace after the opening - // bracket. - testMe.complete('require \t("no_ind', common.mustCall((err, data) => { - assert.strictEqual(err, null); - assert.deepStrictEqual(data, [['no_index', 'no_index/'], 'no_ind']); + + // Tab completion should not break on spaces + const spaceTimeout = setTimeout(function() { + throw new Error('timeout'); + }, 1000); + + await completePromise(' ', common.mustSucceed((data) => { + assert.strictEqual(data[1], ''); + assert.ok(data[0].includes('globalThis')); + clearTimeout(spaceTimeout); })); -} -// Test tab completion for require() relative to the current directory -{ + // Tab completion should pick up the global "toString" object, and + // any other properties up the "global" object's prototype chain + await completePromise('toSt', common.mustCall(function(error, data) { + assert.deepStrictEqual(data, [['toString'], 'toSt']); + })); + + // Own properties should shadow properties on the prototype putIn.run(['.clear']); + putIn.run([ + 'var x = Object.create(null);', + 'x.a = 1;', + 'x.b = 2;', + 'var y = Object.create(x);', + 'y.a = 3;', + 'y.c = 4;', + ]); + await completePromise('y.', common.mustCall(function(error, data) { + assert.deepStrictEqual(data, [['y.b', '', 'y.a', 'y.c'], 'y.']); + })); - const cwd = process.cwd(); - process.chdir(__dirname); + // Tab complete provides built in libs for require() + putIn.run(['.clear']); - ['require(\'.', 'require(".'].forEach((input) => { - testMe.complete(input, common.mustCall((err, data) => { - assert.strictEqual(err, null); - assert.strictEqual(data.length, 2); - assert.strictEqual(data[1], '.'); - assert.strictEqual(data[0].length, 2); - assert.ok(data[0].includes('./')); - assert.ok(data[0].includes('../')); + await completePromise('require(\'', common.mustCall(async function(error, data) { + assert.strictEqual(error, null); + publicModules.forEach((lib) => { + assert( + data[0].includes(lib) && (lib.startsWith('node:') || data[0].includes(`node:${lib}`)), + `${lib} not found` + ); + }); + const newModule = 'foobar'; + assert(!builtinModules.includes(newModule)); + repl.builtinModules.push(newModule); + await completePromise('require(\'', common.mustCall((_, [modules]) => { + assert.strictEqual(data[0].length + 1, modules.length); + assert(modules.includes(newModule)); })); - }); + })); - ['require(\'..', 'require("..'].forEach((input) => { - testMe.complete(input, common.mustCall((err, data) => { + await completePromise("require\t( 'n", common.mustCall(function(error, data) { + assert.strictEqual(error, null); + assert.strictEqual(data.length, 2); + assert.strictEqual(data[1], 'n'); + // require(...) completions include `node:`-prefixed modules: + let lastIndex = -1; + + publicModules.filter((lib) => !lib.startsWith('node:')).forEach((lib, index) => { + lastIndex = data[0].indexOf(`node:${lib}`); + assert.notStrictEqual(lastIndex, -1); + }); + assert.strictEqual(data[0][lastIndex + 1], ''); + // There is only one Node.js module that starts with n: + assert.strictEqual(data[0][lastIndex + 2], 'net'); + assert.strictEqual(data[0][lastIndex + 3], ''); + // It's possible to pick up non-core modules too + data[0].slice(lastIndex + 4).forEach((completion) => { + assert.match(completion, /^n/); + }); + })); + + { + const expected = ['@nodejsscope', '@nodejsscope/']; + // Require calls should handle all types of quotation marks. + for (const quotationMark of ["'", '"', '`']) { + putIn.run(['.clear']); + await completePromise('require(`@nodejs', common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.deepStrictEqual(data, [expected, '@nodejs']); + })); + + putIn.run(['.clear']); + // Completions should not be greedy in case the quotation ends. + const input = `require(${quotationMark}@nodejsscope${quotationMark}`; + testMe.complete(input, common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.deepStrictEqual(data, [[], undefined]); + })); + } + } + + { + putIn.run(['.clear']); + // Completions should find modules and handle whitespace after the opening + // bracket. + testMe.complete('require \t("no_ind', common.mustCall((err, data) => { assert.strictEqual(err, null); - assert.deepStrictEqual(data, [['../'], '..']); + assert.deepStrictEqual(data, [['no_index', 'no_index/'], 'no_ind']); })); - }); + } + + // Test tab completion for require() relative to the current directory + { + putIn.run(['.clear']); + + const cwd = process.cwd(); + process.chdir(__dirname); - ['./', './test-'].forEach((path) => { - [`require('${path}`, `require("${path}`].forEach((input) => { + ['require(\'.', 'require(".'].forEach((input) => { testMe.complete(input, common.mustCall((err, data) => { assert.strictEqual(err, null); assert.strictEqual(data.length, 2); - assert.strictEqual(data[1], path); - assert.ok(data[0].includes('./test-repl-tab-complete')); + assert.strictEqual(data[1], '.'); + assert.strictEqual(data[0].length, 2); + assert.ok(data[0].includes('./')); + assert.ok(data[0].includes('../')); })); }); - }); - ['../parallel/', '../parallel/test-'].forEach((path) => { - [`require('${path}`, `require("${path}`].forEach((input) => { + ['require(\'..', 'require("..'].forEach((input) => { testMe.complete(input, common.mustCall((err, data) => { assert.strictEqual(err, null); - assert.strictEqual(data.length, 2); - assert.strictEqual(data[1], path); - assert.ok(data[0].includes('../parallel/test-repl-tab-complete')); + assert.deepStrictEqual(data, [['../'], '..']); })); }); - }); - - { - const path = '../fixtures/repl-folder-extensions/f'; - testMe.complete(`require('${path}`, common.mustSucceed((data) => { - assert.strictEqual(data.length, 2); - assert.strictEqual(data[1], path); - assert.ok(data[0].includes('../fixtures/repl-folder-extensions/foo.js')); - })); - } - process.chdir(cwd); -} - -// Make sure tab completion works on context properties -putIn.run(['.clear']); + ['./', './test-'].forEach((path) => { + [`require('${path}`, `require("${path}`].forEach((input) => { + testMe.complete(input, common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.strictEqual(data.length, 2); + assert.strictEqual(data[1], path); + assert.ok(data[0].includes('./test-repl-tab-complete')); + })); + }); + }); -putIn.run([ - 'var custom = "test";', -]); -testMe.complete('cus', common.mustCall(function(error, data) { - assert.deepStrictEqual(data, [['CustomEvent', 'custom'], 'cus']); -})); + ['../parallel/', '../parallel/test-'].forEach((path) => { + [`require('${path}`, `require("${path}`].forEach((input) => { + testMe.complete(input, common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.strictEqual(data.length, 2); + assert.strictEqual(data[1], path); + assert.ok(data[0].includes('../parallel/test-repl-tab-complete')); + })); + }); + }); -// Make sure tab completion doesn't crash REPL with half-baked proxy objects. -// See: https://github.com/nodejs/node/issues/2119 -putIn.run(['.clear']); + { + const path = '../fixtures/repl-folder-extensions/f'; + testMe.complete(`require('${path}`, common.mustSucceed((data) => { + assert.strictEqual(data.length, 2); + assert.strictEqual(data[1], path); + assert.ok(data[0].includes('../fixtures/repl-folder-extensions/foo.js')); + })); + } -putIn.run([ - 'var proxy = new Proxy({}, {ownKeys: () => { throw new Error(); }});', -]); + process.chdir(cwd); + } -testMe.complete('proxy.', common.mustCall(function(error, data) { - assert.strictEqual(error, null); - assert(Array.isArray(data)); -})); + // Make sure tab completion works on context properties + putIn.run(['.clear']); -// Make sure tab completion does not include integer members of an Array -putIn.run(['.clear']); + putIn.run([ + 'var custom = "test";', + ]); + await completePromise('cus', common.mustCall(function(error, data) { + assert.deepStrictEqual(data, [['CustomEvent', 'custom'], 'cus']); + })); -putIn.run(['var ary = [1,2,3];']); -testMe.complete('ary.', common.mustCall(function(error, data) { - assert.strictEqual(data[0].includes('ary.0'), false); - assert.strictEqual(data[0].includes('ary.1'), false); - assert.strictEqual(data[0].includes('ary.2'), false); -})); + // Make sure tab completion doesn't crash REPL with half-baked proxy objects. + // See: https://github.com/nodejs/node/issues/2119 + putIn.run(['.clear']); -// Make sure tab completion does not include integer keys in an object -putIn.run(['.clear']); -putIn.run(['var obj = {1:"a","1a":"b",a:"b"};']); + putIn.run([ + 'var proxy = new Proxy({}, {ownKeys: () => { throw new Error(); }});', + ]); -testMe.complete('obj.', common.mustCall(function(error, data) { - assert.strictEqual(data[0].includes('obj.1'), false); - assert.strictEqual(data[0].includes('obj.1a'), false); - assert(data[0].includes('obj.a')); -})); + await completePromise('proxy.', common.mustCall(function(error, data) { + assert.strictEqual(error, null); + assert(Array.isArray(data)); + })); -// Don't try to complete results of non-simple expressions -putIn.run(['.clear']); -putIn.run(['function a() {}']); + // Make sure tab completion does not include integer members of an Array + putIn.run(['.clear']); -testMe.complete('a().b.', getNoResultsFunction()); + putIn.run(['var ary = [1,2,3];']); + await completePromise('ary.', common.mustCall(function(error, data) { + assert.strictEqual(data[0].includes('ary.0'), false); + assert.strictEqual(data[0].includes('ary.1'), false); + assert.strictEqual(data[0].includes('ary.2'), false); + })); -// Works when prefixed with spaces -putIn.run(['.clear']); -putIn.run(['var obj = {1:"a","1a":"b",a:"b"};']); + // Make sure tab completion does not include integer keys in an object + putIn.run(['.clear']); + putIn.run(['var obj = {1:"a","1a":"b",a:"b"};']); -testMe.complete(' obj.', common.mustCall((error, data) => { - assert.strictEqual(data[0].includes('obj.1'), false); - assert.strictEqual(data[0].includes('obj.1a'), false); - assert(data[0].includes('obj.a')); -})); + await completePromise('obj.', common.mustCall(function(error, data) { + assert.strictEqual(data[0].includes('obj.1'), false); + assert.strictEqual(data[0].includes('obj.1a'), false); + assert(data[0].includes('obj.a')); + })); -// Works inside assignments -putIn.run(['.clear']); + // Don't try to complete results of non-simple expressions + putIn.run(['.clear']); + putIn.run(['function a() {}']); -testMe.complete('var log = console.lo', common.mustCall((error, data) => { - assert.deepStrictEqual(data, [['console.log'], 'console.lo']); -})); + await completePromise('a().b.', getNoResultsFunction()); -// Tab completion for defined commands -putIn.run(['.clear']); + // Works when prefixed with spaces + putIn.run(['.clear']); + putIn.run(['var obj = {1:"a","1a":"b",a:"b"};']); -testMe.complete('.b', common.mustCall((error, data) => { - assert.deepStrictEqual(data, [['break'], 'b']); -})); -putIn.run(['.clear']); -putIn.run(['var obj = {"hello, world!": "some string", "key": 123}']); -testMe.complete('obj.', common.mustCall((error, data) => { - assert.strictEqual(data[0].includes('obj.hello, world!'), false); - assert(data[0].includes('obj.key')); -})); + await completePromise(' obj.', common.mustCall((error, data) => { + assert.strictEqual(data[0].includes('obj.1'), false); + assert.strictEqual(data[0].includes('obj.1a'), false); + assert(data[0].includes('obj.a')); + })); -// Make sure tab completion does not include __defineSetter__ and friends. -putIn.run(['.clear']); + // Works inside assignments + putIn.run(['.clear']); -putIn.run(['var obj = {};']); -testMe.complete('obj.', common.mustCall(function(error, data) { - assert.strictEqual(data[0].includes('obj.__defineGetter__'), false); - assert.strictEqual(data[0].includes('obj.__defineSetter__'), false); - assert.strictEqual(data[0].includes('obj.__lookupGetter__'), false); - assert.strictEqual(data[0].includes('obj.__lookupSetter__'), false); - assert.strictEqual(data[0].includes('obj.__proto__'), true); -})); + await completePromise('var log = console.lo', common.mustCall((error, data) => { + assert.deepStrictEqual(data, [['console.log'], 'console.lo']); + })); -// Tab completion for files/directories -{ + // Tab completion for defined commands putIn.run(['.clear']); - process.chdir(__dirname); - const readFileSyncs = ['fs.readFileSync("', 'fs.promises.readFileSync("']; - if (!common.isWindows) { - readFileSyncs.forEach((readFileSync) => { - const fixturePath = `${readFileSync}../fixtures/test-repl-tab-completion`; - testMe.complete(fixturePath, common.mustCall((err, data) => { - assert.strictEqual(err, null); - assert.ok(data[0][0].includes('.hiddenfiles')); - assert.ok(data[0][1].includes('hellorandom.txt')); - assert.ok(data[0][2].includes('helloworld.js')); - })); + await completePromise('.b', common.mustCall((error, data) => { + assert.deepStrictEqual(data, [['break'], 'b']); + })); + putIn.run(['.clear']); + putIn.run(['var obj = {"hello, world!": "some string", "key": 123}']); + await completePromise('obj.', common.mustCall((error, data) => { + assert.strictEqual(data[0].includes('obj.hello, world!'), false); + assert(data[0].includes('obj.key')); + })); - testMe.complete(`${fixturePath}/hello`, - common.mustCall((err, data) => { - assert.strictEqual(err, null); - assert.ok(data[0][0].includes('hellorandom.txt')); - assert.ok(data[0][1].includes('helloworld.js')); - }) - ); + // Make sure tab completion does not include __defineSetter__ and friends. + putIn.run(['.clear']); - testMe.complete(`${fixturePath}/.h`, - common.mustCall((err, data) => { - assert.strictEqual(err, null); - assert.ok(data[0][0].includes('.hiddenfiles')); - }) - ); + putIn.run(['var obj = {};']); + await completePromise('obj.', common.mustCall(function(error, data) { + assert.strictEqual(data[0].includes('obj.__defineGetter__'), false); + assert.strictEqual(data[0].includes('obj.__defineSetter__'), false); + assert.strictEqual(data[0].includes('obj.__lookupGetter__'), false); + assert.strictEqual(data[0].includes('obj.__lookupSetter__'), false); + assert.strictEqual(data[0].includes('obj.__proto__'), true); + })); - testMe.complete(`${readFileSync}./xxxRandom/random`, - common.mustCall((err, data) => { - assert.strictEqual(err, null); - assert.strictEqual(data[0].length, 0); - }) - ); + // Tab completion for files/directories + { + putIn.run(['.clear']); + process.chdir(__dirname); + + const readFileSyncs = ['fs.readFileSync("', 'fs.promises.readFileSync("']; + if (!common.isWindows) { + readFileSyncs.forEach((readFileSync) => { + const fixturePath = `${readFileSync}../fixtures/test-repl-tab-completion`; + testMe.complete(fixturePath, common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.ok(data[0][0].includes('.hiddenfiles')); + assert.ok(data[0][1].includes('hellorandom.txt')); + assert.ok(data[0][2].includes('helloworld.js')); + })); + + testMe.complete(`${fixturePath}/hello`, + common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.ok(data[0][0].includes('hellorandom.txt')); + assert.ok(data[0][1].includes('helloworld.js')); + }) + ); - const testPath = fixturePath.slice(0, -1); - testMe.complete(testPath, common.mustCall((err, data) => { - assert.strictEqual(err, null); - assert.ok(data[0][0].includes('test-repl-tab-completion')); - assert.strictEqual( - data[1], - path.basename(testPath) + testMe.complete(`${fixturePath}/.h`, + common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.ok(data[0][0].includes('.hiddenfiles')); + }) ); - })); - }); - } -} -[ - Array, - Buffer, - - Uint8Array, - Uint16Array, - Uint32Array, - - Uint8ClampedArray, - Int8Array, - Int16Array, - Int32Array, - Float32Array, - Float64Array, -].forEach((type) => { - putIn.run(['.clear']); + testMe.complete(`${readFileSync}./xxxRandom/random`, + common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.strictEqual(data[0].length, 0); + }) + ); - if (type === Array) { - putIn.run([ - 'var ele = [];', - 'for (let i = 0; i < 1e6 + 1; i++) ele[i] = 0;', - 'ele.biu = 1;', - ]); - } else if (type === Buffer) { - putIn.run(['var ele = Buffer.alloc(1e6 + 1); ele.biu = 1;']); - } else { - putIn.run([`var ele = new ${type.name}(1e6 + 1); ele.biu = 1;`]); + const testPath = fixturePath.slice(0, -1); + testMe.complete(testPath, common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.ok(data[0][0].includes('test-repl-tab-completion')); + assert.strictEqual( + data[1], + path.basename(testPath) + ); + })); + }); + } } - hijackStderr(common.mustNotCall()); - testMe.complete('ele.', common.mustCall((err, data) => { - restoreStderr(); - assert.ifError(err); + for (const type of [ + Array, + Buffer, + + Uint8Array, + Uint16Array, + Uint32Array, + + Uint8ClampedArray, + Int8Array, + Int16Array, + Int32Array, + Float32Array, + Float64Array, + ]) { + putIn.run(['.clear']); - const ele = (type === Array) ? - [] : - (type === Buffer ? - Buffer.alloc(0) : - new type(0)); + if (type === Array) { + putIn.run([ + 'var ele = [];', + 'for (let i = 0; i < 1e6 + 1; i++) ele[i] = 0;', + 'ele.biu = 1;', + ]); + } else if (type === Buffer) { + putIn.run(['var ele = Buffer.alloc(1e6 + 1); ele.biu = 1;']); + } else { + putIn.run([`var ele = new ${type.name}(1e6 + 1); ele.biu = 1;`]); + } + + hijackStderr(common.mustNotCall()); + await completePromise('ele.', common.mustCall((err, data) => { + restoreStderr(); + assert.ifError(err); + + const ele = (type === Array) ? + [] : + (type === Buffer ? + Buffer.alloc(0) : + new type(0)); + + assert.strictEqual(data[0].includes('ele.biu'), true); + + data[0].forEach((key) => { + if (!key || key === 'ele.biu') return; + assert.notStrictEqual(ele[key.slice(4)], undefined); + }); + })); + }; - assert.strictEqual(data[0].includes('ele.biu'), true); + // check Buffer.prototype.length not crashing. + // Refs: https://github.com/nodejs/node/pull/11961 + putIn.run(['.clear']); + await completePromise('Buffer.prototype.', common.mustCall()); - data[0].forEach((key) => { - if (!key || key === 'ele.biu') return; - assert.notStrictEqual(ele[key.slice(4)], undefined); - }); + // Make sure repl gives correct autocomplete on literals + await completePromise('``.a', common.mustCall((err, data) => { + assert.strictEqual(data[0].includes('``.at'), true); + })); + await completePromise('\'\'.a', common.mustCall((err, data) => { + assert.strictEqual(data[0].includes('\'\'.at'), true); + })); + await completePromise('"".a', common.mustCall((err, data) => { + assert.strictEqual(data[0].includes('"".at'), true); + })); + await completePromise('("").a', common.mustCall((err, data) => { + assert.strictEqual(data[0].includes('("").at'), true); + })); + await completePromise('[].a', common.mustCall((err, data) => { + assert.strictEqual(data[0].includes('[].at'), true); + })); + await completePromise('{}.a', common.mustCall((err, data) => { + assert.deepStrictEqual(data[0], []); })); -}); -// check Buffer.prototype.length not crashing. -// Refs: https://github.com/nodejs/node/pull/11961 -putIn.run(['.clear']); -testMe.complete('Buffer.prototype.', common.mustCall()); +})().then(common.mustCall()); -// Make sure repl gives correct autocomplete on literals -testMe.complete('``.a', common.mustCall((err, data) => { - assert.strictEqual(data[0].includes('``.at'), true); -})); -testMe.complete('\'\'.a', common.mustCall((err, data) => { - assert.strictEqual(data[0].includes('\'\'.at'), true); -})); -testMe.complete('"".a', common.mustCall((err, data) => { - assert.strictEqual(data[0].includes('"".at'), true); -})); -testMe.complete('("").a', common.mustCall((err, data) => { - assert.strictEqual(data[0].includes('("").at'), true); -})); -testMe.complete('[].a', common.mustCall((err, data) => { - assert.strictEqual(data[0].includes('[].at'), true); -})); -testMe.complete('{}.a', common.mustCall((err, data) => { - assert.deepStrictEqual(data[0], []); -})); +const putIn = new ArrayStream(); const testNonGlobal = repl.start({ input: putIn, diff --git a/test/parallel/test-repl-uncaught-exception-async.js b/test/parallel/test-repl-uncaught-exception-async.js index 366a4e6f2968af..24710e062e0b75 100644 --- a/test/parallel/test-repl-uncaught-exception-async.js +++ b/test/parallel/test-repl-uncaught-exception-async.js @@ -34,9 +34,9 @@ r.write( ' throw new RangeError("abc");\n' + '}, 1);console.log()\n' ); -r.close(); setTimeout(() => { + r.close(); const len = process.listenerCount('uncaughtException'); process.removeAllListeners('uncaughtException'); assert.strictEqual(len, 0); diff --git a/test/parallel/test-runner-coverage-thresholds.js b/test/parallel/test-runner-coverage-thresholds.js index 61066f80a39cc0..e45e1191299ca7 100644 --- a/test/parallel/test-runner-coverage-thresholds.js +++ b/test/parallel/test-runner-coverage-thresholds.js @@ -90,6 +90,26 @@ for (const coverage of coverages) { assert(!findCoverageFileForPid(result.pid)); }); + test(`test failing ${coverage.flag} with red color`, () => { + const result = spawnSync(process.execPath, [ + '--test', + '--experimental-test-coverage', + '--test-coverage-exclude=!test/**', + `${coverage.flag}=99`, + '--test-reporter', 'spec', + fixture, + ], { + env: { ...process.env, FORCE_COLOR: '3' }, + }); + + const stdout = result.stdout.toString(); + // eslint-disable-next-line no-control-regex + const redColorRegex = /\u001b\[31mℹ Error: \d{2}\.\d{2}% \w+ coverage does not meet threshold of 99%/; + assert.match(stdout, redColorRegex, 'Expected red color code not found in diagnostic message'); + assert.strictEqual(result.status, 1); + assert(!findCoverageFileForPid(result.pid)); + }); + test(`test failing ${coverage.flag}`, () => { const result = spawnSync(process.execPath, [ '--test', diff --git a/test/parallel/test-runner-output.mjs b/test/parallel/test-runner-output.mjs index 081d4673ed313d..a9ee2e36eef3fc 100644 --- a/test/parallel/test-runner-output.mjs +++ b/test/parallel/test-runner-output.mjs @@ -70,7 +70,7 @@ const defaultTransform = snapshot.transform( snapshot.replaceWindowsLineEndings, snapshot.replaceStackTrace, removeWindowsPathEscaping, - snapshot.replaceFullPaths, + snapshot.transformProjectRoot(), snapshot.replaceWindowsPaths, replaceTestDuration, replaceTestLocationLine, @@ -90,7 +90,7 @@ const junitTransform = snapshot.transform( const lcovTransform = snapshot.transform( snapshot.replaceWindowsLineEndings, snapshot.replaceStackTrace, - snapshot.replaceFullPaths, + snapshot.transformProjectRoot(), snapshot.replaceWindowsPaths, pickTestFileFromLcov ); diff --git a/test/parallel/test-runner-run-watch.mjs b/test/parallel/test-runner-run-watch.mjs index 739cc29db6365e..c0c5c0b676108e 100644 --- a/test/parallel/test-runner-run-watch.mjs +++ b/test/parallel/test-runner-run-watch.mjs @@ -257,6 +257,56 @@ describe('test runner watch mode', () => { assert.notDeepStrictEqual(durations[0][1], durations[1][1]); }); + it('should emit test:watch:restarted when file is updated', async () => { + let alreadyDrained = false; + const events = []; + const testWatchRestarted = common.mustCall(1); + + const controller = new AbortController(); + const stream = run({ + cwd: tmpdir.path, + watch: true, + signal: controller.signal, + }).on('data', function({ type }) { + events.push(type); + if (type === 'test:watch:restarted') { + testWatchRestarted(); + } + if (type === 'test:watch:drained') { + if (alreadyDrained) { + controller.abort(); + } + alreadyDrained = true; + } + }); + + await once(stream, 'test:watch:drained'); + + writeFileSync(join(tmpdir.path, 'test.js'), fixtureContent['test.js']); + + // eslint-disable-next-line no-unused-vars + for await (const _ of stream); + + assert.partialDeepStrictEqual(events, [ + 'test:watch:drained', + 'test:watch:restarted', + 'test:watch:drained', + ]); + }); + + it('should not emit test:watch:restarted since watch mode is disabled', async () => { + const stream = run({ + cwd: tmpdir.path, + watch: false, + }); + + stream.on('test:watch:restarted', common.mustNotCall()); + writeFileSync(join(tmpdir.path, 'test.js'), fixtureContent['test.js']); + + // eslint-disable-next-line no-unused-vars + for await (const _ of stream); + }); + describe('test runner watch mode with different cwd', () => { it( 'should execute run using a different cwd for the runner than the process cwd', diff --git a/test/parallel/test-runner-run.mjs b/test/parallel/test-runner-run.mjs index 2028aa11cc0e36..06ccf0643eba46 100644 --- a/test/parallel/test-runner-run.mjs +++ b/test/parallel/test-runner-run.mjs @@ -33,6 +33,24 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { for await (const _ of stream); }); + it('should emit diagnostic events with level parameter', async () => { + const diagnosticEvents = []; + + const stream = run({ + files: [join(testFixtures, 'coverage.js')], + reporter: 'spec', + }); + + stream.on('test:diagnostic', (event) => { + diagnosticEvents.push(event); + }); + // eslint-disable-next-line no-unused-vars + for await (const _ of stream); + assert(diagnosticEvents.length > 0, 'No diagnostic events were emitted'); + const infoEvent = diagnosticEvents.find((e) => e.level === 'info'); + assert(infoEvent, 'No diagnostic events with level "info" were emitted'); + }); + const argPrintingFile = join(testFixtures, 'print-arguments.js'); it('should allow custom arguments via execArgv', async () => { const result = await run({ files: [argPrintingFile], execArgv: ['-p', '"Printed"'] }).compose(spec).toArray(); diff --git a/test/parallel/test-source-map-enable.js b/test/parallel/test-source-map-enable.js index 64f4254fcddbc6..a41170f17a91d6 100644 --- a/test/parallel/test-source-map-enable.js +++ b/test/parallel/test-source-map-enable.js @@ -273,7 +273,7 @@ function nextdir() { // Does not attempt to apply path resolution logic to absolute URLs // with schemes. // Refs: https://github.com/webpack/webpack/issues/9601 -// Refs: https://sourcemaps.info/spec.html#h.75yo6yoyk7x5 +// Refs: https://tc39.es/ecma426/#sec-sources { const output = spawnSync(process.execPath, [ '--enable-source-maps', diff --git a/test/parallel/test-sqlite-aggregate-function.mjs b/test/parallel/test-sqlite-aggregate-function.mjs index 3db7494daf12ef..050705c771e6af 100644 --- a/test/parallel/test-sqlite-aggregate-function.mjs +++ b/test/parallel/test-sqlite-aggregate-function.mjs @@ -309,6 +309,27 @@ describe('step', () => { }); describe('result', () => { + test('throws if result throws an error', (t) => { + const db = new DatabaseSync(':memory:'); + t.after(() => db.close()); + db.exec('CREATE TABLE data (value INTEGER)'); + db.exec('INSERT INTO data VALUES (1), (2), (3)'); + db.aggregate('sum_int', { + start: 0, + step: (acc, value) => { + return acc + value; + }, + result: () => { + throw new Error('result error'); + }, + }); + t.assert.throws(() => { + db.prepare('SELECT sum_int(value) as result FROM data').get(); + }, { + message: 'result error' + }); + }); + test('executes once when options.inverse is not present', (t) => { const db = new DatabaseSync(':memory:'); t.after(() => db.close()); diff --git a/test/parallel/test-sqlite-database-sync.js b/test/parallel/test-sqlite-database-sync.js index 98a9f106041c46..b7a6718cd99a34 100644 --- a/test/parallel/test-sqlite-database-sync.js +++ b/test/parallel/test-sqlite-database-sync.js @@ -164,7 +164,7 @@ suite('DatabaseSync() constructor', () => { db.exec('SELECT "foo";'); }, { code: 'ERR_SQLITE_ERROR', - message: /no such column: "foo"/, + message: /no such column: "?foo"?/, }); }); diff --git a/test/parallel/test-stream-duplex-destroy.js b/test/parallel/test-stream-duplex-destroy.js index 52867384057f59..5c9e1882095c9a 100644 --- a/test/parallel/test-stream-duplex-destroy.js +++ b/test/parallel/test-stream-duplex-destroy.js @@ -284,3 +284,17 @@ const assert = require('assert'); duplex.on('close', common.mustCall()); duplex[Symbol.asyncDispose]().then(common.mustCall()); } + +(async () => { + // Check Symbol.asyncDispose implicitly + await using duplex = new Duplex({ + write(chunk, enc, cb) { cb(); }, + read() {}, + }); + duplex.on('error', common.mustCall(function(e) { + assert.strictEqual(e.name, 'AbortError'); + assert.strictEqual(this.destroyed, true); + assert.strictEqual(this.errored.name, 'AbortError'); + })); + duplex.on('close', common.mustCall()); +})().then(common.mustCall()); diff --git a/test/parallel/test-stream-readable-dispose.js b/test/parallel/test-stream-readable-dispose.js index e940bf1688f2bf..118c83b1fb2543 100644 --- a/test/parallel/test-stream-readable-dispose.js +++ b/test/parallel/test-stream-readable-dispose.js @@ -21,3 +21,18 @@ const assert = require('assert'); assert.strictEqual(read.destroyed, true); })); } + +(async () => { + await using read = new Readable({ + read() {} + }); + read.resume(); + + read.on('end', common.mustNotCall('no end event')); + read.on('close', common.mustCall()); + read.on('error', common.mustCall(function(err) { + assert.strictEqual(err.name, 'AbortError'); + assert.strictEqual(this.errored.name, 'AbortError'); + assert.strictEqual(this.destroyed, true); + })); +})().then(common.mustCall()); diff --git a/test/parallel/test-stream-transform-destroy.js b/test/parallel/test-stream-transform-destroy.js index 428bab9ce33fcf..e4410e34c26fc4 100644 --- a/test/parallel/test-stream-transform-destroy.js +++ b/test/parallel/test-stream-transform-destroy.js @@ -152,3 +152,15 @@ const assert = require('assert'); transform.on('close', common.mustCall()); transform[Symbol.asyncDispose]().then(common.mustCall()); } + +(async () => { + await using transform = new Transform({ + transform(chunk, enc, cb) {} + }); + transform.on('error', common.mustCall(function(err) { + assert.strictEqual(err.name, 'AbortError'); + assert.strictEqual(this.destroyed, true); + assert.strictEqual(this.errored.name, 'AbortError'); + })); + transform.on('close', common.mustCall()); +})().then(common.mustCall()); diff --git a/test/parallel/test-stream-writable-destroy.js b/test/parallel/test-stream-writable-destroy.js index 05d7932b88c182..99981a20345fdc 100644 --- a/test/parallel/test-stream-writable-destroy.js +++ b/test/parallel/test-stream-writable-destroy.js @@ -499,3 +499,17 @@ const assert = require('assert'); })); write[Symbol.asyncDispose]().then(common.mustCall()); } + +(async () => { + await using write = new Writable({ + write(chunk, enc, cb) { cb(); } + }); + + write.on('error', common.mustCall(function(e) { + assert.strictEqual(e.name, 'AbortError'); + assert.strictEqual(this.destroyed, true); + assert.strictEqual(this.errored.name, 'AbortError'); + })); + write.on('close', common.mustCall()); + write.on('finish', common.mustNotCall('no finish event')); +})().then(common.mustCall()); diff --git a/test/parallel/test-tls-alert-handling.js b/test/parallel/test-tls-alert-handling.js index cba5bebaa29b6f..7bd42bbe721c4c 100644 --- a/test/parallel/test-tls-alert-handling.js +++ b/test/parallel/test-tls-alert-handling.js @@ -35,16 +35,16 @@ let iter = 0; const errorHandler = common.mustCall((err) => { let expectedErrorCode = 'ERR_SSL_WRONG_VERSION_NUMBER'; - let expectedErrorReason = 'wrong version number'; + let expectedErrorReason = /wrong[\s_]version[\s_]number/i; if (hasOpenSSL(3, 2)) { expectedErrorCode = 'ERR_SSL_PACKET_LENGTH_TOO_LONG'; - expectedErrorReason = 'packet length too long'; + expectedErrorReason = /packet[\s_]length[\s_]too[\s_]long/i; }; assert.strictEqual(err.code, expectedErrorCode); assert.strictEqual(err.library, 'SSL routines'); if (!hasOpenSSL3) assert.strictEqual(err.function, 'ssl3_get_record'); - assert.strictEqual(err.reason, expectedErrorReason); + assert.match(err.reason, expectedErrorReason); errorReceived = true; if (canCloseServer()) server.close(); @@ -98,15 +98,15 @@ function sendBADTLSRecord() { })); client.on('error', common.mustCall((err) => { let expectedErrorCode = 'ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION'; - let expectedErrorReason = 'tlsv1 alert protocol version'; + let expectedErrorReason = /tlsv1[\s_]alert[\s_]protocol[\s_]version/i; if (hasOpenSSL(3, 2)) { expectedErrorCode = 'ERR_SSL_TLSV1_ALERT_RECORD_OVERFLOW'; - expectedErrorReason = 'tlsv1 alert record overflow'; + expectedErrorReason = /tlsv1[\s_]alert[\s_]record[\s_]overflow/i; } assert.strictEqual(err.code, expectedErrorCode); assert.strictEqual(err.library, 'SSL routines'); if (!hasOpenSSL3) assert.strictEqual(err.function, 'ssl3_read_bytes'); - assert.strictEqual(err.reason, expectedErrorReason); + assert.match(err.reason, expectedErrorReason); })); } diff --git a/test/parallel/test-tls-getprotocol.js b/test/parallel/test-tls-getprotocol.js index b1eab88fd6517e..c28b329ba7b642 100644 --- a/test/parallel/test-tls-getprotocol.js +++ b/test/parallel/test-tls-getprotocol.js @@ -29,11 +29,14 @@ const clientConfigs = [ const serverConfig = { secureProtocol: 'TLS_method', - ciphers: 'RSA@SECLEVEL=0', key: fixtures.readKey('agent2-key.pem'), cert: fixtures.readKey('agent2-cert.pem') }; +if (!process.features.openssl_is_boringssl) { + serverConfig.ciphers = 'RSA@SECLEVEL=0'; +} + const server = tls.createServer(serverConfig, common.mustCall(clientConfigs.length)) .listen(0, common.localhostIPv4, function() { let connected = 0; diff --git a/test/parallel/test-tls-write-error.js b/test/parallel/test-tls-write-error.js index b06f2fa2c53ea7..8a8d820a09cca9 100644 --- a/test/parallel/test-tls-write-error.js +++ b/test/parallel/test-tls-write-error.js @@ -17,9 +17,12 @@ const server_cert = fixtures.readKey('agent1-cert.pem'); const opts = { key: server_key, cert: server_cert, - ciphers: 'ALL@SECLEVEL=0' }; +if (!process.features.openssl_is_boringssl) { + opts.ciphers = 'ALL@SECLEVEL=0'; +} + const server = https.createServer(opts, (req, res) => { res.write('hello'); }).listen(0, common.mustCall(() => { diff --git a/test/parallel/test-util-styletext.js b/test/parallel/test-util-styletext.js index 68c31eef2e07c8..df2334651cc869 100644 --- a/test/parallel/test-util-styletext.js +++ b/test/parallel/test-util-styletext.js @@ -75,6 +75,8 @@ assert.strictEqual( styled, ); +assert.strictEqual(util.styleText('none', 'test'), 'test'); + const fd = common.getTTYfd(); if (fd !== -1) { const writeStream = new WriteStream(fd); diff --git a/test/parallel/test-vm-module-dynamic-import-promise.js b/test/parallel/test-vm-module-dynamic-import-promise.js new file mode 100644 index 00000000000000..63493212cd3585 --- /dev/null +++ b/test/parallel/test-vm-module-dynamic-import-promise.js @@ -0,0 +1,135 @@ +// Flags: --experimental-vm-modules +'use strict'; + +const common = require('../common'); + +const assert = require('assert'); +const { createContext, Script, SourceTextModule } = require('vm'); + +// Verifies that a `import` call returns a promise created in the context +// where the `import` was called, not the context of `importModuleDynamically` +// callback. + +async function testScript() { + const ctx = createContext(); + + const mod1 = new SourceTextModule('export const a = 1;', { + context: ctx, + }); + // No import statements, so must not link statically. + await mod1.link(common.mustNotCall()); + + const script2 = new Script(` + const promise = import("mod1"); + if (Object.getPrototypeOf(promise) !== Promise.prototype) { + throw new Error('Expected promise to be created in the current context'); + } + globalThis.__result = promise; + `, { + importModuleDynamically: common.mustCall((specifier, referrer) => { + assert.strictEqual(specifier, 'mod1'); + assert.strictEqual(referrer, script2); + return mod1; + }), + }); + script2.runInContext(ctx); + + // Wait for the promise to resolve. + await ctx.__result; +} + +async function testScriptImportFailed() { + const ctx = createContext(); + + const mod1 = new SourceTextModule('export const a = 1;', { + context: ctx, + }); + // No import statements, so must not link statically. + await mod1.link(common.mustNotCall()); + + const err = new Error('import failed'); + const script2 = new Script(` + const promise = import("mod1"); + if (Object.getPrototypeOf(promise) !== Promise.prototype) { + throw new Error('Expected promise to be created in the current context'); + } + globalThis.__result = promise; + `, { + importModuleDynamically: common.mustCall((specifier, referrer) => { + throw err; + }), + }); + script2.runInContext(ctx); + + // Wait for the promise to reject. + await assert.rejects(ctx.__result, err); +} + +async function testModule() { + const ctx = createContext(); + + const mod1 = new SourceTextModule('export const a = 1;', { + context: ctx, + }); + // No import statements, so must not link statically. + await mod1.link(common.mustNotCall()); + + const mod2 = new SourceTextModule(` + const promise = import("mod1"); + if (Object.getPrototypeOf(promise) !== Promise.prototype) { + throw new Error('Expected promise to be created in the current context'); + } + await promise; + `, { + context: ctx, + importModuleDynamically: common.mustCall((specifier, referrer) => { + assert.strictEqual(specifier, 'mod1'); + assert.strictEqual(referrer, mod2); + return mod1; + }), + }); + // No import statements, so must not link statically. + await mod2.link(common.mustNotCall()); + await mod2.evaluate(); +} + +async function testModuleImportFailed() { + const ctx = createContext(); + + const mod1 = new SourceTextModule('export const a = 1;', { + context: ctx, + }); + // No import statements, so must not link statically. + await mod1.link(common.mustNotCall()); + + const err = new Error('import failed'); + ctx.__err = err; + const mod2 = new SourceTextModule(` + const promise = import("mod1"); + if (Object.getPrototypeOf(promise) !== Promise.prototype) { + throw new Error('Expected promise to be created in the current context'); + } + await promise.then(() => { + throw new Error('Expected promise to be rejected'); + }, (e) => { + if (e !== globalThis.__err) { + throw new Error('Expected promise to be rejected with "import failed"'); + } + }); + `, { + context: ctx, + importModuleDynamically: common.mustCall((specifier, referrer) => { + throw err; + }), + }); + // No import statements, so must not link statically. + await mod2.link(common.mustNotCall()); + await mod2.evaluate(); +} + +Promise.all([ + testScript(), + testScriptImportFailed(), + testModule(), + testModuleImportFailed(), +]).then(common.mustCall()); diff --git a/test/parallel/test-webcrypto-derivebits.js b/test/parallel/test-webcrypto-derivebits.js index eb09bc24f0cb82..0db467b852283a 100644 --- a/test/parallel/test-webcrypto-derivebits.js +++ b/test/parallel/test-webcrypto-derivebits.js @@ -123,6 +123,8 @@ const { subtle } = globalThis.crypto; assert.deepStrictEqual(secret1, secret2); } - test('X25519').then(common.mustCall()); - test('X448').then(common.mustCall()); + if (!process.features.openssl_is_boringssl) { + test('X25519').then(common.mustCall()); + test('X448').then(common.mustCall()); + } } diff --git a/test/parallel/test-webcrypto-derivekey.js b/test/parallel/test-webcrypto-derivekey.js index 558d37d90d5796..90f76839474e16 100644 --- a/test/parallel/test-webcrypto-derivekey.js +++ b/test/parallel/test-webcrypto-derivekey.js @@ -206,6 +206,8 @@ const { KeyObject } = require('crypto'); assert.deepStrictEqual(raw1, raw2); } - test('X25519').then(common.mustCall()); - test('X448').then(common.mustCall()); + if (!process.features.openssl_is_boringssl) { + test('X25519').then(common.mustCall()); + test('X448').then(common.mustCall()); + } } diff --git a/test/parallel/test-webcrypto-sign-verify.js b/test/parallel/test-webcrypto-sign-verify.js index de736102bdcb71..1b2b40152f88d2 100644 --- a/test/parallel/test-webcrypto-sign-verify.js +++ b/test/parallel/test-webcrypto-sign-verify.js @@ -121,8 +121,9 @@ const { subtle } = globalThis.crypto; name: 'Ed25519', }, publicKey, signature, ec.encode(data))); } - - test('hello world').then(common.mustCall()); + if (!process.features.openssl_is_boringssl) { + test('hello world').then(common.mustCall()); + } } // Test Sign/Verify Ed448 @@ -142,5 +143,7 @@ const { subtle } = globalThis.crypto; }, publicKey, signature, ec.encode(data))); } - test('hello world').then(common.mustCall()); + if (!process.features.openssl_is_boringssl) { + test('hello world').then(common.mustCall()); + } } diff --git a/test/parallel/test-worker-dispose.mjs b/test/parallel/test-worker-dispose.mjs new file mode 100644 index 00000000000000..770c91d51ca7ba --- /dev/null +++ b/test/parallel/test-worker-dispose.mjs @@ -0,0 +1,8 @@ +import * as common from '../common/index.mjs'; +import { Worker } from 'node:worker_threads'; + +{ + // Verifies that the worker is async disposable + await using worker = new Worker('for(;;) {}', { eval: true }); + worker.on('exit', common.mustCall()); +} diff --git a/test/parallel/test-worker-internal-modules.mjs b/test/parallel/test-worker-internal-modules.mjs new file mode 100644 index 00000000000000..607eade85c5d45 --- /dev/null +++ b/test/parallel/test-worker-internal-modules.mjs @@ -0,0 +1,36 @@ +import '../common/index.mjs'; +import tmpdir from '../common/tmpdir.js'; +import assert from 'node:assert/strict'; +import { once } from 'node:events'; +import fs from 'node:fs/promises'; +import { describe, test, before } from 'node:test'; +import { Worker } from 'node:worker_threads'; + +const accessInternalsSource = ` +import 'node:internal/freelist'; +`; + +function convertScriptSourceToDataUrl(script) { + return new URL(`data:text/javascript,${encodeURIComponent(script)}`); +} + +describe('Worker threads should not be able to access internal modules', () => { + before(() => tmpdir.refresh()); + + test('worker instantiated with module file path', async () => { + const moduleFilepath = tmpdir.resolve('test-worker-internal-modules.mjs'); + await fs.writeFile(moduleFilepath, accessInternalsSource); + const w = new Worker(moduleFilepath); + await assert.rejects(once(w, 'exit'), { code: 'ERR_UNKNOWN_BUILTIN_MODULE' }); + }); + + test('worker instantiated with module source', async () => { + const w = new Worker(accessInternalsSource, { eval: true }); + await assert.rejects(once(w, 'exit'), { code: 'ERR_UNKNOWN_BUILTIN_MODULE' }); + }); + + test('worker instantiated with data: URL', async () => { + const w = new Worker(convertScriptSourceToDataUrl(accessInternalsSource)); + await assert.rejects(once(w, 'exit'), { code: 'ERR_UNKNOWN_BUILTIN_MODULE' }); + }); +}); diff --git a/test/parallel/test-zlib-type-error.js b/test/parallel/test-zlib-type-error.js new file mode 100644 index 00000000000000..3432d75e346ef1 --- /dev/null +++ b/test/parallel/test-zlib-type-error.js @@ -0,0 +1,46 @@ +'use strict'; +require('../common'); +const assert = require('assert').strict; +const test = require('node:test'); +const { DecompressionStream } = require('stream/web'); + +async function expectTypeError(promise) { + let threw = false; + try { + await promise; + } catch (err) { + threw = true; + assert(err instanceof TypeError, `Expected TypeError, got ${err}`); + } + assert(threw, 'Expected promise to reject'); +} + +test('DecompressStream deflat emits error on trailing data', async () => { + const valid = new Uint8Array([120, 156, 75, 4, 0, 0, 98, 0, 98]); // deflate('a') + const empty = new Uint8Array(1); + const invalid = new Uint8Array([...valid, ...empty]); + const double = new Uint8Array([...valid, ...valid]); + + for (const chunk of [[invalid], [valid, empty], [valid, valid], [valid, double]]) { + await expectTypeError( + Array.fromAsync( + new Blob([chunk]).stream().pipeThrough(new DecompressionStream('deflate')) + ) + ); + } +}); + +test('DecompressStream gzip emits error on trailing data', async () => { + const valid = new Uint8Array([31, 139, 8, 0, 0, 0, 0, 0, 0, 19, 75, 4, + 0, 67, 190, 183, 232, 1, 0, 0, 0]); // gzip('a') + const empty = new Uint8Array(1); + const invalid = new Uint8Array([...valid, ...empty]); + const double = new Uint8Array([...valid, ...valid]); + for (const chunk of [[invalid], [valid, empty], [valid, valid], [double]]) { + await expectTypeError( + Array.fromAsync( + new Blob([chunk]).stream().pipeThrough(new DecompressionStream('gzip')) + ) + ); + } +}); diff --git a/test/pseudo-tty/test-tty-color-support.js b/test/pseudo-tty/test-tty-color-support.js index f846842ee015d8..6b122d85789951 100644 --- a/test/pseudo-tty/test-tty-color-support.js +++ b/test/pseudo-tty/test-tty-color-support.js @@ -37,13 +37,18 @@ const writeStream = new WriteStream(fd); [{ COLORTERM: '1' }, 4], [{ COLORTERM: 'truecolor' }, 24], [{ COLORTERM: '24bit' }, 24], - [{ TMUX: '1' }, 8], + [{ TMUX: '1' }, 24], [{ CI: '1' }, 1], - [{ CI: '1', TRAVIS: '1' }, 8], - [{ CI: '1', CIRCLECI: '1' }, 8], - [{ CI: '1', APPVEYOR: '1' }, 8], - [{ CI: '1', GITLAB_CI: '1' }, 8], + [{ CI: '', APPVEYOR: '1' }, 8], + [{ CI: '1', BUILDKITE: '' }, 8], [{ CI: '1', CI_NAME: 'codeship' }, 8], + [{ CI: '1', CIRCLECI: '1' }, 24], + [{ CI: '1', DRONE: '' }, 8], + [{ CI: '1', GITEA_ACTIONS: '' }, 24], + [{ CI: '1', GITHUB_ACTIONS: '' }, 24], + [{ CI: '1', GITLAB_CI: '1' }, 8], + [{ CI: '1', TRAVIS: '1' }, 8], + [{ CI: '', TRAVIS: '' }, 8], [{ TEAMCITY_VERSION: '1.0.0' }, 1], [{ TEAMCITY_VERSION: '9.11.0' }, 4], [{ TERM_PROGRAM: 'iTerm.app' }, 8], @@ -53,17 +58,22 @@ const writeStream = new WriteStream(fd); [{ TERM_PROGRAM: 'Hyper' }, 1], [{ TERM_PROGRAM: 'MacTerm' }, 24], [{ TERM_PROGRAM: 'Apple_Terminal' }, 8], - [{ TERM: 'xterm-256' }, 8], [{ TERM: 'ansi' }, 4], [{ TERM: 'ANSI' }, 4], [{ TERM: 'color' }, 4], - [{ TERM: 'linux' }, 4], - [{ TERM: 'fail' }, 1], [{ TERM: 'color', NODE_DISABLE_COLORS: '1' }, 1], + [{ TERM: 'console' }, 4], + [{ TERM: 'direct' }, 4], [{ TERM: 'dumb' }, 1], [{ TERM: 'dumb', COLORTERM: '1' }, 1], + [{ TERM: 'fail' }, 1], + [{ TERM: 'linux' }, 4], [{ TERM: 'terminator' }, 24], - [{ TERM: 'console' }, 4], + [{ TERM: 'vt100' }, 4], + [{ TERM: 'vt220' }, 4], + [{ TERM: 'xterm-256' }, 8], + [{ TERM: 'xterm-kitty' }, 24], + [{ TERM: 'xterm-truecolor' }, 24], [{ COLORTERM: '24bit', FORCE_COLOR: '' }, 4], [{ NO_COLOR: '1', FORCE_COLOR: '2' }, 8], [{ NODE_DISABLE_COLORS: '1', FORCE_COLOR: '3' }, 24], @@ -72,6 +82,7 @@ const writeStream = new WriteStream(fd); [{ TMUX: '1', FORCE_COLOR: 0 }, 1], [{ NO_COLOR: 'true', FORCE_COLOR: 0, COLORTERM: 'truecolor' }, 1], [{ TERM: 'xterm-256color', COLORTERM: 'truecolor' }, 24], + [{ TF_BUILD: '', AGENT_NAME: '' }, 4], ].forEach(([env, depth], i) => { const actual = writeStream.getColorDepth(env); assert.strictEqual( diff --git a/test/pummel/test-blob-slice-with-large-size.js b/test/pummel/test-blob-slice-with-large-size.js index 639c2217db79e3..af38d6d5760740 100644 --- a/test/pummel/test-blob-slice-with-large-size.js +++ b/test/pummel/test-blob-slice-with-large-size.js @@ -1,4 +1,7 @@ 'use strict'; + +// This tests that Blob.prototype.slice() works correctly when the size of the +// Blob is outside the range of 32-bit signed integers. const common = require('../common'); // Buffer with size > INT32_MAX @@ -14,8 +17,11 @@ try { const slicedBlob = blob.slice(size - 1, size); assert.strictEqual(slicedBlob.size, 1); } catch (e) { - if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') { - throw e; + if (e.code === 'ERR_MEMORY_ALLOCATION_FAILED') { + common.skip('insufficient space for Buffer.allocUnsafe'); + } + if (/Array buffer allocation failed/.test(e.message)) { + common.skip('insufficient space for Blob.prototype.slice()'); } - common.skip('insufficient space for Buffer.allocUnsafe'); + throw e; } diff --git a/test/report/report.status b/test/report/report.status index 7ef99b5c8ed145..3832cb760db735 100644 --- a/test/report/report.status +++ b/test/report/report.status @@ -9,3 +9,7 @@ prefix report [$system==solaris] # Also applies to SmartOS # https://github.com/nodejs/node/issues/43457 test-report-fatal-error: PASS, FLAKY + +[$system==ibmi] +# https://github.com/nodejs/node/issues/58582 +test-report-exclude-network: PASS,FLAKY diff --git a/test/wasm-allocation/wasm-allocation.status b/test/wasm-allocation/wasm-allocation.status index cf67fe9d67f20f..4663809cbd327a 100644 --- a/test/wasm-allocation/wasm-allocation.status +++ b/test/wasm-allocation/wasm-allocation.status @@ -6,5 +6,5 @@ prefix wasm-allocation [true] # This section applies to all platforms -[$system!=linux || $asan==on] +[$system!=linux || $asan==on || $pointer_compression==on] test-wasm-allocation: SKIP diff --git a/test/wpt/status/compression.json b/test/wpt/status/compression.json index 0cae222832e823..be073427810f0d 100644 --- a/test/wpt/status/compression.json +++ b/test/wpt/status/compression.json @@ -11,14 +11,6 @@ "compression-with-detach.tentative.window.js": { "requires": ["crypto"] }, - "decompression-corrupt-input.tentative.any.js": { - "fail": { - "expected": [ - "trailing junk for 'deflate' should give an error", - "trailing junk for 'gzip' should give an error" - ] - } - }, "idlharness-shadowrealm.window.js": { "skip": "ShadowRealm support is not enabled" }, diff --git a/test/wpt/status/resource-timing.json b/test/wpt/status/resource-timing.json index f40f8fe51da117..6406b88d3266f5 100644 --- a/test/wpt/status/resource-timing.json +++ b/test/wpt/status/resource-timing.json @@ -24,6 +24,8 @@ "fail": { "expected": [ "PerformanceResourceTiming interface: attribute firstInterimResponseStart", + "PerformanceResourceTiming interface: attribute finalResponseHeadersStart", + "PerformanceResourceTiming interface: resource must inherit property \"finalResponseHeadersStart\" with the proper type", "PerformanceResourceTiming interface: attribute renderBlockingStatus", "PerformanceResourceTiming interface: attribute contentType", "PerformanceResourceTiming interface: resource must inherit property \"firstInterimResponseStart\" with the proper type", diff --git a/tools/eslint/package-lock.json b/tools/eslint/package-lock.json index 2447e83cf532c6..bbd44da4ea88e2 100644 --- a/tools/eslint/package-lock.json +++ b/tools/eslint/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@babel/core": "^7.27.1", "@babel/eslint-parser": "^7.27.1", + "@babel/plugin-proposal-explicit-resource-management": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-import-source": "^7.27.1", "@stylistic/eslint-plugin-js": "^4.2.0", @@ -48,30 +49,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.1.tgz", - "integrity": "sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.3.tgz", + "integrity": "sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", - "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz", + "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.1", - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helpers": "^7.27.1", - "@babel/parser": "^7.27.1", - "@babel/template": "^7.27.1", - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1", + "@babel/generator": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.4", + "@babel/parser": "^7.27.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.27.4", + "@babel/types": "^7.27.3", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -105,13 +106,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", - "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.3.tgz", + "integrity": "sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.1", - "@babel/types": "^7.27.1", + "@babel/parser": "^7.27.3", + "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -121,12 +122,12 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.1.tgz", - "integrity": "sha512-2YaDd/Rd9E598B5+WIc8wJPmWETiiJXFYVE60oX8FDohv7rAUU3CQj+A1MgeEmcsk2+dQuEjIe/GDvig0SqL4g==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.1", + "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -150,14 +151,14 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", - "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.27.3" }, "engines": { "node": ">=6.9.0" @@ -203,25 +204,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", - "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.4.tgz", + "integrity": "sha512-Y+bO6U+I7ZKaM5G5rDUZiYfUvQPUibYmAFe7EnKdnKBbVXDZxvp+MWOH5gYciY0EPk4EScsuFMQBbEfpdRKSCQ==", "license": "MIT", "dependencies": { - "@babel/template": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.3" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.1.tgz", - "integrity": "sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==", + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.4.tgz", + "integrity": "sha512-BRmLHGwpUqLFR2jzx9orBuX/ABDkj2jLKOXrHDTN2aOKL+jFDDKaRNo9nyYsIl9h/UE/7lMKdDjKQQyxKKDZ7g==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "@babel/types": "^7.27.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -230,6 +231,22 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-proposal-explicit-resource-management": { + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-explicit-resource-management/-/plugin-proposal-explicit-resource-management-7.27.4.tgz", + "integrity": "sha512-1SwtCDdZWQvUU1i7wt/ihP7W38WjC3CSTOHAl+Xnbze8+bbMNjRvRQydnj0k9J1jPqCAZctBFp6NHJXkrVVmEA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", @@ -260,14 +277,29 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.3.tgz", + "integrity": "sha512-s4Jrok82JpiaIprtY2nHsYmrThKvvwgHwjgd7UMiYhZaN0asdXNLr0y+NjTfkA7SyQE5i2Fb7eawUOZmLvyqOA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/template": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.1.tgz", - "integrity": "sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.1", + "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" }, "engines": { @@ -275,16 +307,16 @@ } }, "node_modules/@babel/traverse": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", - "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.4.tgz", + "integrity": "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.1", - "@babel/parser": "^7.27.1", - "@babel/template": "^7.27.1", - "@babel/types": "^7.27.1", + "@babel/generator": "^7.27.3", + "@babel/parser": "^7.27.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.3", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -302,9 +334,9 @@ } }, "node_modules/@babel/types": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", - "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.3.tgz", + "integrity": "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -315,29 +347,35 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.49.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.49.0.tgz", - "integrity": "sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==", + "version": "0.50.2", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.2.tgz", + "integrity": "sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==", + "license": "MIT", "dependencies": { + "@types/estree": "^1.0.6", + "@typescript-eslint/types": "^8.11.0", "comment-parser": "1.4.1", "esquery": "^1.6.0", "jsdoc-type-pratt-parser": "~4.1.0" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } @@ -358,6 +396,7 @@ "version": "4.12.1", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -386,9 +425,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -433,12 +472,15 @@ } }, "node_modules/@eslint/js": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", - "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz", + "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { @@ -451,12 +493,12 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", + "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.13.0", + "@eslint/core": "^0.14.0", "levn": "^0.4.1" }, "engines": { @@ -467,6 +509,7 @@ "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "license": "Apache-2.0", "engines": { "node": ">=18.18.0" } @@ -475,6 +518,7 @@ "version": "0.16.6", "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" @@ -487,6 +531,7 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -509,9 +554,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -522,9 +567,9 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -579,9 +624,9 @@ } }, "node_modules/@stylistic/eslint-plugin-js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-4.2.0.tgz", - "integrity": "sha512-MiJr6wvyzMYl/wElmj8Jns8zH7Q1w8XoVtm+WM6yDaTrfxryMyb8n0CMxt82fo42RoLIfxAEtM6tmQVxqhk0/A==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-4.4.0.tgz", + "integrity": "sha512-UeeQNRF73zJXnNGGbvwgUgzS+vzVGQoRuQKR6RhQCRHQmaBaVHxDDQVmN9RPLCnRxVjO/v8cqq/yMDqC7DikSQ==", "license": "MIT", "dependencies": { "eslint-visitor-keys": "^4.2.0", @@ -598,6 +643,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -606,9 +652,10 @@ } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", @@ -626,15 +673,29 @@ } }, "node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, + "node_modules/@typescript-eslint/types": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.0.tgz", + "integrity": "sha512-DKuXOKpM5IDT1FA2g9x9x1Ug81YuKrzf4mYX8FAVSNu5Wo/LELHWQyM1pQaDkI42bX15PWl0vNPt1uGiIFUOpg==", + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -714,9 +775,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", + "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", "funding": [ { "type": "opencollective", @@ -733,10 +794,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", + "caniuse-lite": "^1.0.30001718", + "electron-to-chromium": "^1.5.160", "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -755,9 +816,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001716", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001716.tgz", - "integrity": "sha512-49/c1+x3Kwz7ZIWt+4DvK3aMJy9oYXXG6/97JKsnjdCk/6n9vVyWL8NAwVt95Lwt9eigI10Hl782kDfZUUlRXw==", + "version": "1.0.30001720", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz", + "integrity": "sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g==", "funding": [ { "type": "opencollective", @@ -774,6 +835,22 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/character-entities": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", @@ -826,6 +903,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "license": "MIT", "engines": { "node": ">= 12.0.0" } @@ -846,6 +924,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -856,12 +935,12 @@ } }, "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -879,9 +958,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.148", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.148.tgz", - "integrity": "sha512-8uc1QXwwqayD4mblcsQYZqoi+cOc97A2XmKSBOIRbEAvbp6vrqmSYs4dHD2qVygUgn7Mi0qdKgPaJ9WC8cv63A==", + "version": "1.5.161", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.161.tgz", + "integrity": "sha512-hwtetwfKNZo/UlwHIVBlKZVdy7o8bIZxxKs0Mv/ROPiQQQmDgdm5a+KvKtBsxM8ZjFzTaCeLoodZ8jiBE3o9rA==", "license": "ISC" }, "node_modules/escalade": { @@ -893,20 +972,32 @@ "node": ">=6" } }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", - "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz", + "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.1", - "@eslint/core": "^0.13.0", + "@eslint/core": "^0.14.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.25.1", - "@eslint/plugin-kit": "^0.2.8", + "@eslint/js": "9.28.0", + "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -966,20 +1057,20 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "50.6.11", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.6.11.tgz", - "integrity": "sha512-k4+MnBCGR8cuIB5MZ++FGd4gbXxjob2rX1Nq0q3nWFF4xSGZENTgTLZSjb+u9B8SAnP6lpGV2FJrBjllV3pVSg==", + "version": "50.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.7.1.tgz", + "integrity": "sha512-XBnVA5g2kUVokTNUiE1McEPse5n9/mNUmuJcx52psT6zBs2eVcXSmQBvjfa7NZdfLVSy3u1pEDDUxoxpwy89WA==", "license": "BSD-3-Clause", "dependencies": { - "@es-joy/jsdoccomment": "~0.49.0", + "@es-joy/jsdoccomment": "~0.50.2", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", - "debug": "^4.3.6", + "debug": "^4.4.1", "escape-string-regexp": "^4.0.0", - "espree": "^10.1.0", + "espree": "^10.3.0", "esquery": "^1.6.0", "parse-imports-exports": "^0.2.4", - "semver": "^7.6.3", + "semver": "^7.7.2", "spdx-expression-parse": "^4.0.0" }, "engines": { @@ -989,22 +1080,10 @@ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-plugin-jsdoc/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1050,34 +1129,6 @@ "node": ">=10" } }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/eslint-scope": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", @@ -1098,6 +1149,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1118,6 +1170,7 @@ "version": "10.3.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", @@ -1134,6 +1187,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1261,9 +1315,9 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "license": "ISC" }, "node_modules/gensync": { @@ -1288,9 +1342,9 @@ } }, "node_modules/globals": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", - "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz", + "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==", "license": "MIT", "engines": { "node": ">=18" @@ -1410,7 +1464,8 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, "node_modules/js-tokens": { "version": "4.0.0", @@ -1434,6 +1489,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", + "license": "MIT", "engines": { "node": ">=12.0.0" } @@ -1592,9 +1648,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/natural-compare": { @@ -1714,6 +1770,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", "engines": { "node": ">=8" } @@ -1764,6 +1821,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -1775,6 +1833,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", "engines": { "node": ">=8" } @@ -1796,9 +1855,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", "license": "CC0-1.0" }, "node_modules/strip-json-comments": { @@ -1893,6 +1952,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, diff --git a/tools/eslint/package.json b/tools/eslint/package.json index d0fbd7d433cc8a..9909ded4d33533 100644 --- a/tools/eslint/package.json +++ b/tools/eslint/package.json @@ -7,6 +7,7 @@ "@babel/eslint-parser": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-import-source": "^7.27.1", + "@babel/plugin-proposal-explicit-resource-management": "^7.27.1", "@stylistic/eslint-plugin-js": "^4.2.0", "eslint": "^9.25.1", "eslint-formatter-tap": "^8.40.0", diff --git a/tools/install.py b/tools/install.py index c067b65ed5d32f..24c297d60a497b 100755 --- a/tools/install.py +++ b/tools/install.py @@ -181,9 +181,19 @@ def files(options, action): link_path = abspath(options.install_path, 'lib/libnode.so') try_symlink(options, so_name, link_path) else: - output_lib = 'libnode.' + options.variables.get('shlib_suffix') - action(options, [os.path.join(options.build_dir, output_lib)], - os.path.join(options.variables.get('libdir'), output_lib)) + # Ninja and Makefile generators output the library in different directories; + # find out which one we have, and install first found + output_lib_name = 'libnode.' + options.variables.get('shlib_suffix') + output_lib_candidate_paths = [ + os.path.join(options.build_dir, output_lib_name), + os.path.join(options.build_dir, "lib", output_lib_name), + ] + try: + output_lib = next(filter(os.path.exists, output_lib_candidate_paths)) + except StopIteration as not_found: + raise RuntimeError("No libnode.so to install!") from not_found + action(options, [output_lib], + os.path.join(options.variables.get('libdir'), output_lib_name)) action(options, [os.path.join(options.v8_dir, 'tools/gdbinit')], 'share/doc/node/') action(options, [os.path.join(options.v8_dir, 'tools/lldb_commands.py')], 'share/doc/node/') diff --git a/tools/sign.bat b/tools/sign.bat index f4d18d9f7a8a0d..607eb6de793ee3 100644 --- a/tools/sign.bat +++ b/tools/sign.bat @@ -1,12 +1,29 @@ @echo off -@REM From December 2023, new certificates use DigiCert cloud HSM service for EV signing. -@REM They provide a client side app smctl.exe for managing certificates and signing process. +@REM From June 2025, we started using Azure Trusted Signing for code signing. @REM Release CI machines are configured to have it in the PATH so this can be used safely. -smctl sign -k key_nodejs -i %1 + +where signtool >nul 2>&1 +if errorlevel 1 ( + echo signtool not found in PATH. + exit /b 1 +) + +if "%AZURE_SIGN_DLIB_PATH%"=="" ( + echo AZURE_SIGN_DLIB_PATH is not set. + exit /b 1 +) + +if "%AZURE_SIGN_METADATA_PATH%"=="" ( + echo AZURE_SIGN_METADATA_PATH is not set. + exit /b 1 +) + + +signtool sign /tr "http://timestamp.acs.microsoft.com" /td sha256 /fd sha256 /v /dlib %AZURE_SIGN_DLIB_PATH% /dmdf %AZURE_SIGN_METADATA_PATH% %1 if not ERRORLEVEL 1 ( - echo Successfully signed %1 using smctl + echo Successfully signed %1 using signtool exit /b 0 ) -echo Could not sign %1 using smctl +echo Could not sign %1 using signtool exit /b 1 \ No newline at end of file diff --git a/tools/test.py b/tools/test.py index 08e10f18122c80..8725a9103fdb0f 100755 --- a/tools/test.py +++ b/tools/test.py @@ -31,7 +31,7 @@ from __future__ import print_function from typing import Dict import logging -import optparse +import argparse import os import re import signal @@ -1378,84 +1378,84 @@ def ReadConfigurationInto(path, sections, defs): def BuildOptions(): - result = optparse.OptionParser() - result.add_option("-m", "--mode", help="The test modes in which to run (comma-separated)", + result = argparse.ArgumentParser() + result.add_argument("-m", "--mode", help="The test modes in which to run (comma-separated)", default='release') - result.add_option("-v", "--verbose", help="Verbose output", + result.add_argument("-v", "--verbose", help="Verbose output", default=False, action="store_true") - result.add_option('--logfile', dest='logfile', + result.add_argument('--logfile', dest='logfile', help='write test output to file. NOTE: this only applies the tap progress indicator') - result.add_option("-p", "--progress", + result.add_argument("-p", "--progress", help="The style of progress indicator (%s)" % ", ".join(PROGRESS_INDICATORS.keys()), choices=list(PROGRESS_INDICATORS.keys()), default="mono") - result.add_option("--report", help="Print a summary of the tests to be run", + result.add_argument("--report", help="Print a summary of the tests to be run", default=False, action="store_true") - result.add_option("-s", "--suite", help="A test suite", + result.add_argument("-s", "--suite", help="A test suite", default=[], action="append") - result.add_option("-t", "--timeout", help="Timeout in seconds", - default=120, type="int") - result.add_option("--arch", help='The architecture to run tests for', + result.add_argument("-t", "--timeout", help="Timeout in seconds", + default=120, type=int) + result.add_argument("--arch", help='The architecture to run tests for', default='none') - result.add_option("--snapshot", help="Run the tests with snapshot turned on", + result.add_argument("--snapshot", help="Run the tests with snapshot turned on", default=False, action="store_true") - result.add_option("--special-command", default=None) - result.add_option("--node-args", dest="node_args", help="Args to pass through to Node", + result.add_argument("--special-command", default=None) + result.add_argument("--node-args", dest="node_args", help="Args to pass through to Node", default=[], action="append") - result.add_option("--expect-fail", dest="expect_fail", + result.add_argument("--expect-fail", dest="expect_fail", help="Expect test cases to fail", default=False, action="store_true") - result.add_option("--valgrind", help="Run tests through valgrind", + result.add_argument("--valgrind", help="Run tests through valgrind", default=False, action="store_true") - result.add_option("--worker", help="Run parallel tests inside a worker context", + result.add_argument("--worker", help="Run parallel tests inside a worker context", default=False, action="store_true") - result.add_option("--check-deopts", help="Check tests for permanent deoptimizations", + result.add_argument("--check-deopts", help="Check tests for permanent deoptimizations", default=False, action="store_true") - result.add_option("--cat", help="Print the source of the tests", + result.add_argument("--cat", help="Print the source of the tests", default=False, action="store_true") - result.add_option("--flaky-tests", + result.add_argument("--flaky-tests", help="Regard tests marked as flaky (run|skip|dontcare|keep_retrying)", default="run") - result.add_option("--measure-flakiness", + result.add_argument("--measure-flakiness", help="When a test fails, re-run it x number of times", - default=0, type="int") - result.add_option("--skip-tests", + default=0, type=int) + result.add_argument("--skip-tests", help="Tests that should not be executed (comma-separated)", default="") - result.add_option("--warn-unused", help="Report unused rules", + result.add_argument("--warn-unused", help="Report unused rules", default=False, action="store_true") - result.add_option("-j", help="The number of parallel tasks to run, 0=use number of cores", - default=0, type="int") - result.add_option("-J", help="For legacy compatibility, has no effect", + result.add_argument("-j", help="The number of parallel tasks to run, 0=use number of cores", + default=0, type=int) + result.add_argument("-J", help="For legacy compatibility, has no effect", default=False, action="store_true") - result.add_option("--time", help="Print timing information after running", + result.add_argument("--time", help="Print timing information after running", default=False, action="store_true") - result.add_option("--suppress-dialogs", help="Suppress Windows dialogs for crashing tests", + result.add_argument("--suppress-dialogs", help="Suppress Windows dialogs for crashing tests", dest="suppress_dialogs", default=True, action="store_true") - result.add_option("--no-suppress-dialogs", help="Display Windows dialogs for crashing tests", + result.add_argument("--no-suppress-dialogs", help="Display Windows dialogs for crashing tests", dest="suppress_dialogs", action="store_false") - result.add_option("--shell", help="Path to node executable", default=None) - result.add_option("--store-unexpected-output", + result.add_argument("--shell", help="Path to node executable", default=None) + result.add_argument("--store-unexpected-output", help="Store the temporary JS files from tests that fails", dest="store_unexpected_output", default=True, action="store_true") - result.add_option("--no-store-unexpected-output", + result.add_argument("--no-store-unexpected-output", help="Deletes the temporary JS files from tests that fails", dest="store_unexpected_output", action="store_false") - result.add_option("-r", "--run", + result.add_argument("-r", "--run", help="Divide the tests in m groups (interleaved) and run tests from group n (--run=n,m with n < m)", default="") - result.add_option('--temp-dir', + result.add_argument('--temp-dir', help='Optional path to change directory used for tests', default=False) - result.add_option('--test-root', + result.add_argument('--test-root', help='Optional path to change test directory', dest='test_root', default=None) - result.add_option('--repeat', + result.add_argument('--repeat', help='Number of times to repeat given tests', - default=1, type="int") - result.add_option('--abort-on-timeout', + default=1, type=int) + result.add_argument('--abort-on-timeout', help='Send SIGABRT instead of SIGTERM to kill processes that time out', default=False, action="store_true", dest="abort_on_timeout") - result.add_option("--type", + result.add_argument("--type", help="Type of build (simple, fips, coverage)", default=None) - result.add_option("--error-reporter", + result.add_argument("--error-reporter", help="use error reporter", default=True, action="store_true") return result @@ -1628,10 +1628,13 @@ def get_asan_state(vm, context): asan = Execute([vm, '-p', 'process.config.variables.asan'], context).stdout.strip() return "on" if asan == "1" else "off" +def get_pointer_compression_state(vm, context): + pointer_compression = Execute([vm, '-p', 'process.config.variables.v8_enable_pointer_compression'], context).stdout.strip() + return "on" if pointer_compression == "1" else "off" def Main(): parser = BuildOptions() - (options, args) = parser.parse_args() + (options, args) = parser.parse_known_args() if not ProcessOptions(options): parser.print_help() return 1 @@ -1726,6 +1729,7 @@ def Main(): 'arch': vmArch, 'type': get_env_type(vm, options.type, context), 'asan': get_asan_state(vm, context), + 'pointer_compression': get_pointer_compression_state(vm, context), } test_list = root.ListTests([], path, context, arch, mode) unclassified_tests += test_list diff --git a/tools/v8_gypfiles/d8.gyp b/tools/v8_gypfiles/d8.gyp index 0dc0859bd6868a..f5f8a194318eb5 100644 --- a/tools/v8_gypfiles/d8.gyp +++ b/tools/v8_gypfiles/d8.gyp @@ -41,7 +41,7 @@ }], ['(OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="netbsd" \ or OS=="openbsd" or OS=="solaris" or OS=="android" \ - or OS=="qnx" or OS=="aix" or OS=="os400")', { + or OS=="qnx" or OS=="aix" or OS=="os400" or OS=="openharmony")', { 'sources': [ '<(V8_ROOT)/src/d8/d8-posix.cc', ] }], [ 'OS=="win"', { diff --git a/tools/v8_gypfiles/features.gypi b/tools/v8_gypfiles/features.gypi index 0214bec80dd4d1..9b2917e4fc9f38 100644 --- a/tools/v8_gypfiles/features.gypi +++ b/tools/v8_gypfiles/features.gypi @@ -73,7 +73,7 @@ }, { 'v8_enable_etw_stack_walking': 0, }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { # Sets -dV8_ENABLE_PRIVATE_MAPPING_FORK_OPTIMIZATION. # # This flag speeds up the performance of fork/execve on Linux systems for @@ -248,6 +248,11 @@ # Sets -DV8_ENABLE_SANDBOX. 'v8_enable_sandbox%': 0, + # Enable support for external code range relative to the pointer compression + # cage. + # Sets -DV8_EXTERNAL_CODE_SPACE. + 'v8_enable_external_code_space%': 0, + # Experimental feature for collecting per-class zone memory stats. # Requires use_rtti = true 'v8_enable_precise_zone_stats%': 0, @@ -380,6 +385,9 @@ ['v8_enable_sandbox==1', { 'defines': ['V8_ENABLE_SANDBOX',], }], + ['v8_enable_external_code_space==1', { + 'defines': ['V8_EXTERNAL_CODE_SPACE',], + }], ['v8_enable_object_print==1', { 'defines': ['OBJECT_PRINT',], }], diff --git a/tools/v8_gypfiles/toolchain.gypi b/tools/v8_gypfiles/toolchain.gypi index f11255c574f657..a3462d2bb33e1a 100644 --- a/tools/v8_gypfiles/toolchain.gypi +++ b/tools/v8_gypfiles/toolchain.gypi @@ -86,10 +86,10 @@ 'binutils_dir%': '', 'conditions': [ - ['OS=="linux" and host_arch=="x64"', { + ['OS in "linux openharmony" and host_arch=="x64"', { 'binutils_dir%': 'third_party/binutils/Linux_x64/Release/bin', }], - ['OS=="linux" and host_arch=="ia32"', { + ['OS in "linux openharmony" and host_arch=="ia32"', { 'binutils_dir%': 'third_party/binutils/Linux_ia32/Release/bin', }], ], @@ -530,7 +530,7 @@ 'V8_TARGET_OS_IOS', ] }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'defines': [ 'V8_HAVE_TARGET_OS', 'V8_TARGET_OS_LINUX', @@ -548,9 +548,7 @@ 'V8_TARGET_OS_WIN', ] }], - ['(OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris" \ - or OS=="netbsd" or OS=="mac" or OS=="android" or OS=="qnx") and \ - v8_target_arch=="ia32"', { + ['OS in "linux freebsd openbsd solaris netbsd mac android qnx openharmony" and v8_target_arch=="ia32"', { 'cflags': [ '-msse2', '-mfpmath=sse', @@ -591,7 +589,7 @@ 'DEBUG', ], 'conditions': [ - ['OS=="linux" and v8_enable_backtrace==1', { + ['OS in "linux openharmony" and v8_enable_backtrace==1', { # Support for backtrace_symbols. 'ldflags': [ '-rdynamic' ], }], @@ -638,8 +636,7 @@ 'v8_enable_slow_dchecks%': 1, }, 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \ - OS=="qnx" or OS=="aix" or OS=="os400"', { + ['OS in "linux freebsd openbsd netbsd qnx aix os400 openharmony"', { 'cflags!': [ '-O3', '-O2', @@ -689,8 +686,7 @@ 'v8_enable_slow_dchecks%': 0, }, 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \ - OS=="qnx" or OS=="aix" or OS=="os400"', { + ['OS in "linux freebsd openbsd netbsd qnx aix os400 openharmony"', { 'cflags!': [ '-O0', '-O1', @@ -741,8 +737,7 @@ # Temporary refs: https://github.com/nodejs/node/pull/23801 'defines!': ['ENABLE_HANDLE_ZAPPING',], 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" \ - or OS=="aix" or OS=="os400"', { + ['OS in "linux freebsd openbsd netbsd aix os400 openharmony"', { 'cflags!': [ '-Os', ], diff --git a/tools/v8_gypfiles/v8.gyp b/tools/v8_gypfiles/v8.gyp index 8e3f015dff14e1..dd977d8641ea6e 100644 --- a/tools/v8_gypfiles/v8.gyp +++ b/tools/v8_gypfiles/v8.gyp @@ -724,7 +724,7 @@ }], ['v8_enable_webassembly==1', { 'conditions': [ - ['OS=="linux" or OS=="mac" or OS=="ios" or OS=="freebsd"', { + ['OS in "linux mac ios freebsd openharmony"', { 'sources': [ '<(V8_ROOT)/src/trap-handler/handler-inside-posix.h', ], @@ -767,12 +767,12 @@ }], ['v8_enable_webassembly==1', { 'conditions': [ - ['((_toolset=="host" and host_arch=="arm64" or _toolset=="target" and target_arch=="arm64") and (OS=="linux" or OS=="mac")) or ((_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS=="linux" or OS=="mac"))', { + ['((_toolset=="host" and host_arch=="arm64" or _toolset=="target" and target_arch=="arm64") and (OS in "linux mac openharmony")) or ((_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS in "linux mac openharmony"))', { 'sources': [ '<(V8_ROOT)/src/trap-handler/handler-inside-posix.h', ], }], - ['(_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS=="linux" or OS=="mac" or OS=="win")', { + ['(_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS in "linux mac win openharmony")', { 'sources': [ '<(V8_ROOT)/src/trap-handler/trap-handler-simulator.h', ], @@ -1139,7 +1139,7 @@ }], ['v8_enable_webassembly==1', { 'conditions': [ - ['OS=="linux" or OS=="mac" or OS=="ios" or OS=="freebsd"', { + ['OS in "linux mac ios freebsd openharmony"', { 'sources': [ '<(V8_ROOT)/src/trap-handler/handler-inside-posix.cc', '<(V8_ROOT)/src/trap-handler/handler-outside-posix.cc', @@ -1167,7 +1167,7 @@ 'conditions': [ ['v8_enable_webassembly==1', { 'conditions': [ - ['((_toolset=="host" and host_arch=="arm64" or _toolset=="target" and target_arch=="arm64") and (OS=="linux" or OS=="mac" or OS=="ios")) or ((_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS=="linux" or OS=="mac"))', { + ['((_toolset=="host" and host_arch=="arm64" or _toolset=="target" and target_arch=="arm64") and (OS in "linux mac ios openharmony")) or ((_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS in "linux mac openharmony"))', { 'sources': [ '<(V8_ROOT)/src/trap-handler/handler-inside-posix.cc', '<(V8_ROOT)/src/trap-handler/handler-outside-posix.cc', @@ -1179,7 +1179,7 @@ '<(V8_ROOT)/src/trap-handler/handler-outside-win.cc', ], }], - ['(_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS=="linux" or OS=="mac" or OS=="win")', { + ['(_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS in "linux mac win openharmony")', { 'sources': [ '<(V8_ROOT)/src/trap-handler/handler-outside-simulator.cc', ], @@ -1410,7 +1410,7 @@ }], ], }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'sources': [ '<(V8_ROOT)/src/base/debug/stack_trace_posix.cc', '<(V8_ROOT)/src/base/platform/platform-linux.cc', @@ -2291,7 +2291,7 @@ ['v8_target_arch=="s390x"', { 'defines': ['HWY_BROKEN_EMU128=0',], }], - ['OS == "aix"', { + ['OS in "aix os400"', { 'defines': ['HWY_BROKEN_EMU128=0',], }], ['v8_target_arch=="arm" and arm_version==7', { diff --git a/typings/globals.d.ts b/typings/globals.d.ts index 3730a56da2987c..1bd3f46d0e2567 100644 --- a/typings/globals.d.ts +++ b/typings/globals.d.ts @@ -4,6 +4,7 @@ import { ConfigBinding } from './internalBinding/config'; import { ConstantsBinding } from './internalBinding/constants'; import { DebugBinding } from './internalBinding/debug'; import { HttpParserBinding } from './internalBinding/http_parser'; +import { InspectorBinding } from './internalBinding/inspector'; import { FsBinding } from './internalBinding/fs'; import { FsDirBinding } from './internalBinding/fs_dir'; import { MessagingBinding } from './internalBinding/messaging'; @@ -31,6 +32,7 @@ interface InternalBindingMap { fs: FsBinding; fs_dir: FsDirBinding; http_parser: HttpParserBinding; + inspector: InspectorBinding; messaging: MessagingBinding; modules: ModulesBinding; options: OptionsBinding; diff --git a/typings/internalBinding/blob.d.ts b/typings/internalBinding/blob.d.ts index 5396c863bb5e59..9a22c789e189bc 100644 --- a/typings/internalBinding/blob.d.ts +++ b/typings/internalBinding/blob.d.ts @@ -2,18 +2,10 @@ declare namespace InternalBlobBinding { interface BlobHandle { slice(start: number, end: number): BlobHandle; } - - class FixedSizeBlobCopyJob { - constructor(handle: BlobHandle); - run(): ArrayBuffer | undefined; - ondone: (err: unknown, res?: ArrayBuffer) => void; - } } export interface BlobBinding { createBlob(sources: Array, length: number): InternalBlobBinding.BlobHandle; - FixedSizeBlobCopyJob: typeof InternalBlobBinding.FixedSizeBlobCopyJob; getDataObject(id: string): [handle: InternalBlobBinding.BlobHandle | undefined, length: number, type: string] | undefined; storeDataObject(id: string, handle: InternalBlobBinding.BlobHandle, size: number, type: string): void; - revokeDataObject(id: string): void; } diff --git a/typings/internalBinding/constants.d.ts b/typings/internalBinding/constants.d.ts index dc4657080ba54b..2c645d99f17679 100644 --- a/typings/internalBinding/constants.d.ts +++ b/typings/internalBinding/constants.d.ts @@ -191,8 +191,6 @@ export interface ConstantsBinding { COPYFILE_FICLONE: 2; UV_FS_COPYFILE_FICLONE_FORCE: 4; COPYFILE_FICLONE_FORCE: 4; - EXTENSIONLESS_FORMAT_JAVASCRIPT: 0; - EXTENSIONLESS_FORMAT_WASM: 1; }; crypto: { OPENSSL_VERSION_NUMBER: 269488319; @@ -389,4 +387,8 @@ export interface ConstantsBinding { TRACE_EVENT_PHASE_LEAVE_CONTEXT: 41; TRACE_EVENT_PHASE_LINK_IDS: 61; }; + internal: { + EXTENSIONLESS_FORMAT_JAVASCRIPT: 0; + EXTENSIONLESS_FORMAT_WASM: 1; + }; } diff --git a/typings/internalBinding/fs.d.ts b/typings/internalBinding/fs.d.ts index 7e3f03de22d026..6e1702996dfcf1 100644 --- a/typings/internalBinding/fs.d.ts +++ b/typings/internalBinding/fs.d.ts @@ -77,6 +77,8 @@ declare namespace InternalFSBinding { function copyFile(src: StringOrBuffer, dest: StringOrBuffer, mode: number, usePromises: typeof kUsePromises): Promise; function cpSyncCheckPaths(src: StringOrBuffer, dest: StringOrBuffer, dereference: boolean, recursive: boolean): void; + function cpSyncOverrideFile(src: StringOrBuffer, dest: StringOrBuffer, mode: number, preserveTimestamps: boolean): void; + function cpSyncCopyDir(src: StringOrBuffer, dest: StringOrBuffer, force: boolean, errorOnExist: boolean, verbatimSymlinks: boolean, dereference: boolean): void; function fchmod(fd: number, mode: number, req: FSReqCallback): void; function fchmod(fd: number, mode: number): void; @@ -235,7 +237,7 @@ declare namespace InternalFSBinding { function writeString(fd: number, value: string, pos: unknown, encoding: unknown, req: undefined, ctx: FSSyncContext): number; function writeString(fd: number, value: string, pos: unknown, encoding: unknown, usePromises: typeof kUsePromises): Promise; - function getFormatOfExtensionlessFile(url: string): ConstantsBinding['fs']; + function getFormatOfExtensionlessFile(url: string): ConstantsBinding['internal']; function writeFileUtf8(path: string, data: string, flag: number, mode: number): void; function writeFileUtf8(fd: number, data: string, flag: number, mode: number): void; @@ -260,6 +262,8 @@ export interface FsBinding { close: typeof InternalFSBinding.close; copyFile: typeof InternalFSBinding.copyFile; cpSyncCheckPaths: typeof InternalFSBinding.cpSyncCheckPaths; + cpSyncOverrideFile: typeof InternalFSBinding.cpSyncOverrideFile; + cpSyncCopyDir: typeof InternalFSBinding.cpSyncCopyDir; fchmod: typeof InternalFSBinding.fchmod; fchown: typeof InternalFSBinding.fchown; fdatasync: typeof InternalFSBinding.fdatasync; diff --git a/typings/internalBinding/inspector.d.ts b/typings/internalBinding/inspector.d.ts new file mode 100644 index 00000000000000..ab32838b2366ca --- /dev/null +++ b/typings/internalBinding/inspector.d.ts @@ -0,0 +1,36 @@ +interface InspectorConnectionInstance { + dispatch(message: string): void; + disconnect(): void; +} + +interface InspectorConnectionConstructor { + new(onMessageHandler: (message: string) => void): InspectorConnectionInstance; +} + +export interface InspectorBinding { + consoleCall( + inspectorMethod: (...args: any[]) => any, + nodeMethod: (...args: any[]) => any, + ...args: any[] + ): void; + setConsoleExtensionInstaller(installer: Function): void; + callAndPauseOnStart( + fn: (...args: any[]) => any, + thisArg: any, + ...args: any[] + ): any; + open(port: number, host: string): void; + url(): string | undefined; + waitForDebugger(): boolean; + asyncTaskScheduled(taskName: string, taskId: number, recurring: boolean): void; + asyncTaskCanceled(taskId: number): void; + asyncTaskStarted(taskId: number): void; + asyncTaskFinished(taskId: number): void; + registerAsyncHook(enable: () => void, disable: () => void): void; + isEnabled(): boolean; + emitProtocolEvent(eventName: string, params: object): void; + setupNetworkTracking(enable: () => void, disable: () => void): void; + console: Console; + Connection: InspectorConnectionConstructor; + MainThreadConnection: InspectorConnectionConstructor; +}