mirror of
https://github.com/oven-sh/bun
synced 2026-02-17 14:22:01 +00:00
Compare commits
15 Commits
3ubj1i-cod
...
codex/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9329bc9c4 | ||
|
|
27a08fca84 | ||
|
|
a398bd62a3 | ||
|
|
2aa7c59727 | ||
|
|
7765b61038 | ||
|
|
8a06ddb1fb | ||
|
|
2e76e69939 | ||
|
|
aa404b14c4 | ||
|
|
a4819b41e9 | ||
|
|
570c69773e | ||
|
|
39a9dbb207 | ||
|
|
f5bfda9699 | ||
|
|
9f5adfefe3 | ||
|
|
316c8d6c48 | ||
|
|
da87890532 |
@@ -309,6 +309,19 @@ function getCppAgent(platform, options) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Platform}
|
||||
*/
|
||||
function getZigPlatform() {
|
||||
return {
|
||||
os: "linux",
|
||||
arch: "aarch64",
|
||||
abi: "musl",
|
||||
distro: "alpine",
|
||||
release: "3.21",
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Platform} platform
|
||||
* @param {PipelineOptions} options
|
||||
@@ -322,19 +335,9 @@ function getZigAgent(platform, options) {
|
||||
// queue: "build-zig",
|
||||
// };
|
||||
|
||||
return getEc2Agent(
|
||||
{
|
||||
os: "linux",
|
||||
arch: "aarch64",
|
||||
abi: "musl",
|
||||
distro: "alpine",
|
||||
release: "3.21",
|
||||
},
|
||||
options,
|
||||
{
|
||||
instanceType: "r8g.large",
|
||||
},
|
||||
);
|
||||
return getEc2Agent(getZigPlatform(), options, {
|
||||
instanceType: "r8g.large",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1105,6 +1108,11 @@ async function getPipeline(options = {}) {
|
||||
steps.push(
|
||||
...relevantBuildPlatforms.map(target => {
|
||||
const imageKey = getImageKey(target);
|
||||
const zigImageKey = getImageKey(getZigPlatform());
|
||||
const dependsOn = imagePlatforms.has(zigImageKey) ? [`${zigImageKey}-build-image`] : [];
|
||||
if (imagePlatforms.has(imageKey)) {
|
||||
dependsOn.push(`${imageKey}-build-image`);
|
||||
}
|
||||
|
||||
return getStepWithDependsOn(
|
||||
{
|
||||
@@ -1114,7 +1122,7 @@ async function getPipeline(options = {}) {
|
||||
? [getBuildBunStep(target, options)]
|
||||
: [getBuildCppStep(target, options), getBuildZigStep(target, options), getLinkBunStep(target, options)],
|
||||
},
|
||||
imagePlatforms.has(imageKey) ? `${imageKey}-build-image` : undefined,
|
||||
...dependsOn,
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"terminals": []
|
||||
}
|
||||
47
.github/workflows/codex-test-sync.yml
vendored
Normal file
47
.github/workflows/codex-test-sync.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
name: Codex Test Sync
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled, opened]
|
||||
|
||||
env:
|
||||
BUN_VERSION: "1.2.15"
|
||||
|
||||
jobs:
|
||||
sync-node-tests:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
(github.event.action == 'labeled' && github.event.label.name == 'codex') ||
|
||||
(github.event.action == 'opened' && contains(github.event.pull_request.labels.*.name, 'codex')) ||
|
||||
contains(github.head_ref, 'codex')
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: ${{ env.BUN_VERSION }}
|
||||
|
||||
- name: Get changed files and sync tests
|
||||
shell: bash
|
||||
run: |
|
||||
# Get the list of changed files from the PR
|
||||
git diff --name-only origin/main...HEAD | while read -r file; do
|
||||
if [[ "$file" =~ ^test/js/node/test/(parallel|sequential)/(.+)\.(js|mjs|ts)$ ]]; then
|
||||
test_name="${BASH_REMATCH[2]}"
|
||||
echo "Syncing test: $test_name"
|
||||
bun node:test:cp "$test_name"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Commit changes
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: "Sync Node.js tests with upstream"
|
||||
@@ -76,6 +76,7 @@
|
||||
"zig-format:check": "bun run analysis:no-llvm --target zig-format-check",
|
||||
"prettier": "bunx prettier@latest --plugin=prettier-plugin-organize-imports --config .prettierrc --write scripts packages src docs 'test/**/*.{test,spec}.{ts,tsx,js,jsx,mts,mjs,cjs,cts}' '!test/**/*fixture*.*'",
|
||||
"node:test": "node ./scripts/runner.node.mjs --quiet --exec-path=$npm_execpath --node-tests ",
|
||||
"node:test:cp": "bun ./scripts/fetch-node-test.ts ",
|
||||
"clean:zig": "rm -rf build/debug/cache/zig build/debug/CMakeCache.txt 'build/debug/*.o' .zig-cache zig-out || true",
|
||||
"sync-webkit-source": "bun ./scripts/sync-webkit-source.ts"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Version: 7
|
||||
# Version: 8
|
||||
# A script that installs the dependencies needed to build and test Bun.
|
||||
# This should work on Windows 10 or newer with PowerShell.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# Version: 10
|
||||
# Version: 11
|
||||
|
||||
# A script that installs the dependencies needed to build and test Bun.
|
||||
# This should work on macOS and Linux with a POSIX shell.
|
||||
|
||||
112
scripts/fetch-node-test.ts
Normal file
112
scripts/fetch-node-test.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { mkdirSync, writeFileSync } from "fs";
|
||||
import path, { dirname, join } from "path";
|
||||
|
||||
const options: RequestInit = {};
|
||||
|
||||
if (process.env.GITHUB_TOKEN) {
|
||||
options.headers = {
|
||||
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
||||
};
|
||||
}
|
||||
|
||||
async function fetchNodeTest(testName: string) {
|
||||
const nodeRepoUrl = "https://raw.githubusercontent.com/nodejs/node/main";
|
||||
const extensions = ["js", "mjs", "ts"];
|
||||
const testDirs = ["test/parallel", "test/sequential"];
|
||||
|
||||
// Try different combinations of test name patterns
|
||||
const testNameVariations = [
|
||||
testName,
|
||||
testName.startsWith("test-") ? testName : `test-${testName}`,
|
||||
testName.replace(/^test-/, ""),
|
||||
];
|
||||
|
||||
for (const testDir of testDirs) {
|
||||
for (const nameVariation of testNameVariations) {
|
||||
// Try with extensions
|
||||
for (const ext of extensions) {
|
||||
const testPath = `${testDir}/${nameVariation}.${ext}`;
|
||||
const url = `${nodeRepoUrl}/${testPath}`;
|
||||
|
||||
try {
|
||||
console.log(`Trying: ${url}`);
|
||||
const response = await fetch(url, options);
|
||||
if (response.ok) {
|
||||
const content = await response.text();
|
||||
const localPath = join("test/js/node", testPath);
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
mkdirSync(dirname(localPath), { recursive: true });
|
||||
|
||||
// Write the file
|
||||
writeFileSync(localPath, content);
|
||||
console.log(
|
||||
`✅ Successfully fetched and saved: ${localPath} (${new Intl.NumberFormat("en-US", {
|
||||
notation: "compact",
|
||||
unit: "kilobyte",
|
||||
}).format(Buffer.byteLength(content, "utf-8"))})`,
|
||||
);
|
||||
return localPath;
|
||||
}
|
||||
} catch (error) {
|
||||
// Continue to next variation
|
||||
}
|
||||
}
|
||||
|
||||
// Try without extension
|
||||
const testPath = `${testDir}/${nameVariation}`;
|
||||
const url = `${nodeRepoUrl}/${testPath}`;
|
||||
|
||||
try {
|
||||
console.log(`Trying: ${url}`);
|
||||
const response = await fetch(url, options);
|
||||
if (response.ok) {
|
||||
const content = await response.text();
|
||||
const localPath = join("test/js/node", testPath);
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
mkdirSync(dirname(localPath), { recursive: true });
|
||||
|
||||
// Write the file
|
||||
writeFileSync(localPath, content);
|
||||
console.log(
|
||||
`✅ Successfully fetched and saved: ${localPath} (${new Intl.NumberFormat("en-US", {
|
||||
notation: "compact",
|
||||
unit: "kilobyte",
|
||||
}).format(Buffer.byteLength(content, "utf-8"))})`,
|
||||
);
|
||||
return localPath;
|
||||
}
|
||||
} catch (error) {
|
||||
// Continue to next variation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`❌ Could not find test: ${testName}`);
|
||||
}
|
||||
|
||||
// Get test name from command line arguments
|
||||
let testName = process.argv[2];
|
||||
|
||||
if (testName.startsWith(path.join(import.meta.dirname, ".."))) {
|
||||
testName = testName.slice(path.join(import.meta.dirname, "..").length);
|
||||
}
|
||||
|
||||
if (testName.startsWith("test/parallel/")) {
|
||||
testName = testName.replace("test/parallel/", "");
|
||||
} else if (testName.startsWith("test/sequential/")) {
|
||||
testName = testName.replace("test/sequential/", "");
|
||||
}
|
||||
|
||||
if (!testName) {
|
||||
console.error("Usage: bun scripts/fetch-node-test.ts <test-name>");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
await fetchNodeTest(testName);
|
||||
} catch (error) {
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -290,7 +290,7 @@ export async function spawn(command, options = {}) {
|
||||
if (exitCode !== 0 && isWindows) {
|
||||
const exitReason = getWindowsExitReason(exitCode);
|
||||
if (exitReason) {
|
||||
exitCode = exitReason;
|
||||
signalCode = exitReason;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,7 +386,7 @@ export function spawnSync(command, options = {}) {
|
||||
if (exitCode !== 0 && isWindows) {
|
||||
const exitReason = getWindowsExitReason(exitCode);
|
||||
if (exitReason) {
|
||||
exitCode = exitReason;
|
||||
signalCode = exitReason;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,9 +442,37 @@ export function spawnSyncSafe(command, options = {}) {
|
||||
* @returns {string | undefined}
|
||||
*/
|
||||
export function getWindowsExitReason(exitCode) {
|
||||
const ntStatusPath = "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.22621.0\\shared\\ntstatus.h";
|
||||
const nthStatus = readFile(ntStatusPath, { cache: true });
|
||||
const windowsKitPath = "C:\\Program Files (x86)\\Windows Kits";
|
||||
if (!existsSync(windowsKitPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const windowsKitPaths = readdirSync(windowsKitPath)
|
||||
.filter(filename => isFinite(parseInt(filename)))
|
||||
.sort((a, b) => parseInt(b) - parseInt(a));
|
||||
|
||||
let ntStatusPath;
|
||||
for (const windowsKitPath of windowsKitPaths) {
|
||||
const includePath = `${windowsKitPath}\\Include`;
|
||||
if (!existsSync(includePath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const windowsSdkPaths = readdirSync(includePath).sort();
|
||||
for (const windowsSdkPath of windowsSdkPaths) {
|
||||
const statusPath = `${includePath}\\${windowsSdkPath}\\shared\\ntstatus.h`;
|
||||
if (existsSync(statusPath)) {
|
||||
ntStatusPath = statusPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ntStatusPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nthStatus = readFile(ntStatusPath, { cache: true });
|
||||
const match = nthStatus.match(new RegExp(`(STATUS_\\w+).*0x${exitCode?.toString(16)}`, "i"));
|
||||
if (match) {
|
||||
const [, exitReason] = match;
|
||||
|
||||
@@ -3139,6 +3139,21 @@ JSC_DEFINE_HOST_FUNCTION(Process_stubEmptyFunction, (JSGlobalObject * globalObje
|
||||
return JSValue::encode(jsUndefined());
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(Process_setSourceMapsEnabled, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
|
||||
{
|
||||
Zig::GlobalObject* globalObject = defaultGlobalObject(lexicalGlobalObject);
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
JSValue arg0 = callFrame->argument(0);
|
||||
if (!arg0.isBoolean()) {
|
||||
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, "enabled"_s, "boolean"_s, arg0);
|
||||
}
|
||||
|
||||
globalObject->processObject()->m_sourceMapsEnabled = arg0.toBoolean(globalObject);
|
||||
return JSValue::encode(jsUndefined());
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(Process_stubFunctionReturningArray, (JSGlobalObject * globalObject, CallFrame* callFrame))
|
||||
{
|
||||
return JSValue::encode(JSC::constructEmptyArray(globalObject, nullptr));
|
||||
@@ -3645,7 +3660,7 @@ extern "C" void Process__emitErrorEvent(Zig::GlobalObject* global, EncodedJSValu
|
||||
resourceUsage Process_functionResourceUsage Function 0
|
||||
revision constructRevision PropertyCallback
|
||||
send constructProcessSend PropertyCallback
|
||||
setSourceMapsEnabled Process_stubEmptyFunction Function 1
|
||||
setSourceMapsEnabled Process_setSourceMapsEnabled Function 1
|
||||
setUncaughtExceptionCaptureCallback Process_setUncaughtExceptionCaptureCallback Function 1
|
||||
stderr constructStderr PropertyCallback
|
||||
stdin constructStdin PropertyCallback
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
~Process();
|
||||
|
||||
bool m_isExitCodeObservable = false;
|
||||
bool m_sourceMapsEnabled = false;
|
||||
|
||||
static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable;
|
||||
|
||||
|
||||
@@ -1071,12 +1071,19 @@ const ServerPrototype = {
|
||||
http_res.assignSocket(socket);
|
||||
}
|
||||
}
|
||||
} else if (http_req.headers.expect === "100-continue") {
|
||||
if (server.listenerCount("checkContinue") > 0) {
|
||||
server.emit("checkContinue", http_req, http_res);
|
||||
} else if (http_req.headers.expect !== undefined) {
|
||||
if (http_req.headers.expect === "100-continue") {
|
||||
if (server.listenerCount("checkContinue") > 0) {
|
||||
server.emit("checkContinue", http_req, http_res);
|
||||
} else {
|
||||
http_res.writeContinue();
|
||||
server.emit("request", http_req, http_res);
|
||||
}
|
||||
} else if (server.listenerCount("checkExpectation") > 0) {
|
||||
server.emit("checkExpectation", http_req, http_res);
|
||||
} else {
|
||||
http_res.writeContinue();
|
||||
server.emit("request", http_req, http_res);
|
||||
http_res.writeHead(417);
|
||||
http_res.end();
|
||||
}
|
||||
} else {
|
||||
server.emit("request", http_req, http_res);
|
||||
@@ -1408,6 +1415,12 @@ const NodeHTTPServerSocket = class Socket extends Duplex {
|
||||
return this;
|
||||
}
|
||||
|
||||
setEncoding(_encoding) {
|
||||
const err = new Error("Changing the socket encoding is not allowed per RFC7230 Section 3.");
|
||||
err.code = "ERR_HTTP_SOCKET_ENCODING";
|
||||
throw err;
|
||||
}
|
||||
|
||||
unref() {
|
||||
return this;
|
||||
}
|
||||
|
||||
26
test/js/node/parallel/test-http-socket-encoding-error.js
Normal file
26
test/js/node/parallel/test-http-socket-encoding-error.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const http = require('http');
|
||||
|
||||
const server = http.createServer().listen(0, connectToServer);
|
||||
|
||||
server.on('connection', common.mustCall((socket) => {
|
||||
assert.throws(
|
||||
() => {
|
||||
socket.setEncoding('');
|
||||
},
|
||||
{
|
||||
code: 'ERR_HTTP_SOCKET_ENCODING',
|
||||
name: 'Error',
|
||||
message: 'Changing the socket encoding is not allowed per RFC7230 Section 3.'
|
||||
}
|
||||
);
|
||||
|
||||
socket.end();
|
||||
}));
|
||||
|
||||
function connectToServer() {
|
||||
const client = new http.Agent().createConnection(this.address().port, () => {
|
||||
client.end();
|
||||
}).on('end', () => server.close());
|
||||
}
|
||||
16
test/js/node/test/parallel/test-destroy-socket-in-lookup.js
Normal file
16
test/js/node/test/parallel/test-destroy-socket-in-lookup.js
Normal file
@@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const net = require('net');
|
||||
|
||||
// Test that the process does not crash.
|
||||
const socket = net.connect({
|
||||
port: 12345,
|
||||
host: 'localhost',
|
||||
// Make sure autoSelectFamily is true
|
||||
// so that lookupAndConnectMultiple is called.
|
||||
autoSelectFamily: true,
|
||||
});
|
||||
// DNS resolution fails or succeeds
|
||||
socket.on('lookup', common.mustCall(() => {
|
||||
socket.destroy();
|
||||
}));
|
||||
20
test/js/node/test/parallel/test-dgram-async-dispose.mjs
Normal file
20
test/js/node/test/parallel/test-dgram-async-dispose.mjs
Normal file
@@ -0,0 +1,20 @@
|
||||
import * as common from '../common/index.mjs';
|
||||
import assert from 'node:assert';
|
||||
import dgram from 'node:dgram';
|
||||
import { describe, it } from 'node:test';
|
||||
|
||||
describe('dgram.Socket[Symbol.asyncDispose]()', () => {
|
||||
it('should close the socket', async () => {
|
||||
const server = dgram.createSocket({ type: 'udp4' });
|
||||
server.on('close', common.mustCall());
|
||||
await server[Symbol.asyncDispose]().then(common.mustCall());
|
||||
|
||||
assert.throws(() => server.address(), { code: 'ERR_SOCKET_DGRAM_NOT_RUNNING' });
|
||||
});
|
||||
|
||||
it('should resolve even if the socket is already closed', async () => {
|
||||
const server = dgram.createSocket({ type: 'udp4' });
|
||||
await server[Symbol.asyncDispose]().then(common.mustCall());
|
||||
await server[Symbol.asyncDispose]().then(common.mustCall(), common.mustNotCall());
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,79 @@
|
||||
import * as common from '../common/index.mjs';
|
||||
import * as fixtures from '../common/fixtures.mjs';
|
||||
import fs from 'fs';
|
||||
import assert from 'assert';
|
||||
|
||||
// This test ensures that "position" argument is correctly validated
|
||||
|
||||
const filepath = fixtures.path('x.txt');
|
||||
|
||||
const buffer = Buffer.from('xyz\n');
|
||||
const offset = 0;
|
||||
const length = buffer.byteLength;
|
||||
|
||||
// allowedErrors is an array of acceptable internal errors
|
||||
// For example, on some platforms read syscall might return -EFBIG or -EOVERFLOW
|
||||
function testValid(position, allowedErrors = []) {
|
||||
let fdSync;
|
||||
try {
|
||||
fdSync = fs.openSync(filepath, 'r');
|
||||
fs.readSync(fdSync, buffer, offset, length, position);
|
||||
fs.readSync(fdSync, buffer, common.mustNotMutateObjectDeep({ offset, length, position }));
|
||||
} catch (err) {
|
||||
if (!allowedErrors.includes(err.code)) {
|
||||
assert.fail(err);
|
||||
}
|
||||
} finally {
|
||||
if (fdSync) fs.closeSync(fdSync);
|
||||
}
|
||||
}
|
||||
|
||||
function testInvalid(code, position) {
|
||||
let fdSync;
|
||||
try {
|
||||
fdSync = fs.openSync(filepath, 'r');
|
||||
assert.throws(
|
||||
() => fs.readSync(fdSync, buffer, offset, length, position),
|
||||
{ code }
|
||||
);
|
||||
assert.throws(
|
||||
() => fs.readSync(fdSync, buffer, common.mustNotMutateObjectDeep({ offset, length, position })),
|
||||
{ code }
|
||||
);
|
||||
} finally {
|
||||
if (fdSync) fs.closeSync(fdSync);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
testValid(undefined);
|
||||
testValid(null);
|
||||
testValid(-1);
|
||||
testValid(-1n);
|
||||
|
||||
testValid(0);
|
||||
testValid(0n);
|
||||
testValid(1);
|
||||
testValid(1n);
|
||||
testValid(9);
|
||||
testValid(9n);
|
||||
testValid(Number.MAX_SAFE_INTEGER, [ 'EFBIG', 'EOVERFLOW' ]);
|
||||
|
||||
testValid(2n ** 63n - 1n - BigInt(length), [ 'EFBIG', 'EOVERFLOW' ]);
|
||||
testInvalid('ERR_OUT_OF_RANGE', 2n ** 63n);
|
||||
testInvalid('ERR_OUT_OF_RANGE', 2n ** 63n - BigInt(length));
|
||||
|
||||
testInvalid('ERR_OUT_OF_RANGE', NaN);
|
||||
testInvalid('ERR_OUT_OF_RANGE', -Infinity);
|
||||
testInvalid('ERR_OUT_OF_RANGE', Infinity);
|
||||
testInvalid('ERR_OUT_OF_RANGE', -0.999);
|
||||
testInvalid('ERR_OUT_OF_RANGE', -(2n ** 64n));
|
||||
testInvalid('ERR_OUT_OF_RANGE', Number.MAX_SAFE_INTEGER + 1);
|
||||
testInvalid('ERR_OUT_OF_RANGE', Number.MAX_VALUE);
|
||||
|
||||
for (const badTypeValue of [
|
||||
false, true, '1', Symbol(1), {}, [], () => {}, Promise.resolve(1),
|
||||
]) {
|
||||
testInvalid('ERR_INVALID_ARG_TYPE', badTypeValue);
|
||||
}
|
||||
}
|
||||
55
test/js/node/test/parallel/test-http-expect-handling.js
Normal file
55
test/js/node/test/parallel/test-http-expect-handling.js
Normal file
@@ -0,0 +1,55 @@
|
||||
// Spec documentation http://httpwg.github.io/specs/rfc7231.html#header.expect
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const http = require('http');
|
||||
|
||||
const tests = [417, 417];
|
||||
|
||||
let testsComplete = 0;
|
||||
let testIdx = 0;
|
||||
|
||||
const s = http.createServer((req, res) => {
|
||||
throw new Error('this should never be executed');
|
||||
});
|
||||
|
||||
s.listen(0, nextTest);
|
||||
|
||||
function nextTest() {
|
||||
const options = {
|
||||
port: s.address().port,
|
||||
headers: { 'Expect': 'meoww' }
|
||||
};
|
||||
|
||||
if (testIdx === tests.length) {
|
||||
return s.close();
|
||||
}
|
||||
|
||||
const test = tests[testIdx];
|
||||
|
||||
if (testIdx > 0) {
|
||||
s.on('checkExpectation', common.mustCall((req, res) => {
|
||||
res.statusCode = 417;
|
||||
res.end();
|
||||
}));
|
||||
}
|
||||
|
||||
http.get(options, (response) => {
|
||||
console.log(`client: expected status: ${test}`);
|
||||
console.log(`client: statusCode: ${response.statusCode}`);
|
||||
assert.strictEqual(response.statusCode, test);
|
||||
assert.strictEqual(response.statusMessage, 'Expectation Failed');
|
||||
|
||||
response.on('end', () => {
|
||||
testsComplete++;
|
||||
testIdx++;
|
||||
nextTest();
|
||||
});
|
||||
response.resume();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
process.on('exit', () => {
|
||||
assert.strictEqual(testsComplete, 2);
|
||||
});
|
||||
30
test/js/node/test/parallel/test-net-server-async-dispose.mjs
Normal file
30
test/js/node/test/parallel/test-net-server-async-dispose.mjs
Normal file
@@ -0,0 +1,30 @@
|
||||
import * as common from '../common/index.mjs';
|
||||
import assert from 'node:assert';
|
||||
import net from 'node:net';
|
||||
import { describe, it } from 'node:test';
|
||||
|
||||
describe('net.Server[Symbol.asyncDispose]()', () => {
|
||||
it('should close the server', async () => {
|
||||
const server = net.createServer();
|
||||
const timeoutRef = setTimeout(common.mustNotCall(), 2 ** 31 - 1);
|
||||
|
||||
server.listen(0, common.mustCall(async () => {
|
||||
await server[Symbol.asyncDispose]().then(common.mustCall());
|
||||
assert.strictEqual(server.address(), null);
|
||||
clearTimeout(timeoutRef);
|
||||
}));
|
||||
|
||||
server.on('close', common.mustCall());
|
||||
});
|
||||
|
||||
it('should resolve even if the server is already closed', async () => {
|
||||
const server = net.createServer();
|
||||
const timeoutRef = setTimeout(common.mustNotCall(), 2 ** 31 - 1);
|
||||
|
||||
server.listen(0, common.mustCall(async () => {
|
||||
await server[Symbol.asyncDispose]().then(common.mustCall());
|
||||
await server[Symbol.asyncDispose]().then(common.mustCall(), common.mustNotCall());
|
||||
clearTimeout(timeoutRef);
|
||||
}));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const http = require('http');
|
||||
const stream = require('stream');
|
||||
|
||||
// Verify that when piping a stream to an `OutgoingMessage` (or a type that
|
||||
// inherits from `OutgoingMessage`), if data is emitted after the
|
||||
// `OutgoingMessage` was closed - a `write after end` error is raised
|
||||
|
||||
class MyStream extends stream {}
|
||||
|
||||
const server = http.createServer(common.mustCall(function(req, res) {
|
||||
const myStream = new MyStream();
|
||||
myStream.pipe(res);
|
||||
|
||||
process.nextTick(common.mustCall(() => {
|
||||
res.end();
|
||||
myStream.emit('data', 'some data');
|
||||
res.on('error', common.expectsError({
|
||||
code: 'ERR_STREAM_WRITE_AFTER_END',
|
||||
name: 'Error'
|
||||
}));
|
||||
|
||||
process.nextTick(common.mustCall(() => server.close()));
|
||||
}));
|
||||
}));
|
||||
|
||||
server.listen(0);
|
||||
|
||||
server.on('listening', common.mustCall(function() {
|
||||
http.request({
|
||||
port: server.address().port,
|
||||
method: 'GET',
|
||||
path: '/'
|
||||
}).end();
|
||||
}));
|
||||
@@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
const unexpectedValues = [
|
||||
undefined,
|
||||
null,
|
||||
1,
|
||||
{},
|
||||
() => {},
|
||||
];
|
||||
for (const it of unexpectedValues) {
|
||||
assert.throws(() => {
|
||||
process.setSourceMapsEnabled(it);
|
||||
}, /ERR_INVALID_ARG_TYPE/);
|
||||
}
|
||||
81
test/js/node/test/parallel/test-set-http-max-http-headers.js
Normal file
81
test/js/node/test/parallel/test-set-http-max-http-headers.js
Normal file
@@ -0,0 +1,81 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const { spawn } = require('child_process');
|
||||
const path = require('path');
|
||||
const { suite, test } = require('node:test');
|
||||
const testName = path.join(__dirname, 'test-http-max-http-headers.js');
|
||||
|
||||
test(function(_, cb) {
|
||||
console.log('running subtest expecting failure');
|
||||
|
||||
// Validate that the test fails if the max header size is too small.
|
||||
const args = ['--expose-internals',
|
||||
'--max-http-header-size=1024',
|
||||
testName];
|
||||
const cp = spawn(process.execPath, args, { stdio: 'inherit' });
|
||||
|
||||
cp.on('close', common.mustCall((code, signal) => {
|
||||
assert.strictEqual(code, 1);
|
||||
assert.strictEqual(signal, null);
|
||||
cb();
|
||||
}));
|
||||
});
|
||||
|
||||
test(function(_, cb) {
|
||||
console.log('running subtest expecting success');
|
||||
|
||||
const env = Object.assign({}, process.env, {
|
||||
NODE_DEBUG: 'http'
|
||||
});
|
||||
|
||||
// Validate that the test now passes if the same limit is large enough.
|
||||
const args = ['--expose-internals',
|
||||
'--max-http-header-size=1024',
|
||||
testName,
|
||||
'1024'];
|
||||
const cp = spawn(process.execPath, args, {
|
||||
env,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
|
||||
cp.on('close', common.mustCall((code, signal) => {
|
||||
assert.strictEqual(code, 0);
|
||||
assert.strictEqual(signal, null);
|
||||
cb();
|
||||
}));
|
||||
});
|
||||
|
||||
const skip = process.config.variables.node_without_node_options;
|
||||
suite('same checks using NODE_OPTIONS if it is supported', { skip }, () => {
|
||||
const env = Object.assign({}, process.env, {
|
||||
NODE_OPTIONS: '--max-http-header-size=1024'
|
||||
});
|
||||
|
||||
test(function(_, cb) {
|
||||
console.log('running subtest expecting failure');
|
||||
|
||||
// Validate that the test fails if the max header size is too small.
|
||||
const args = ['--expose-internals', testName];
|
||||
const cp = spawn(process.execPath, args, { env, stdio: 'inherit' });
|
||||
|
||||
cp.on('close', common.mustCall((code, signal) => {
|
||||
assert.strictEqual(code, 1);
|
||||
assert.strictEqual(signal, null);
|
||||
cb();
|
||||
}));
|
||||
});
|
||||
|
||||
test(function(_, cb) {
|
||||
// Validate that the test now passes if the same limit is large enough.
|
||||
const args = ['--expose-internals', testName, '1024'];
|
||||
const cp = spawn(process.execPath, args, { env, stdio: 'inherit' });
|
||||
|
||||
cp.on('close', common.mustCall((code, signal) => {
|
||||
assert.strictEqual(code, 0);
|
||||
assert.strictEqual(signal, null);
|
||||
cb();
|
||||
}));
|
||||
});
|
||||
});
|
||||
17
test/js/node/test/parallel/test-socket-address.js
Normal file
17
test/js/node/test/parallel/test-socket-address.js
Normal file
@@ -0,0 +1,17 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const net = require('net');
|
||||
|
||||
// This tests checks that if server._handle.getsockname
|
||||
// returns an error number, an error is thrown.
|
||||
|
||||
const server = net.createServer({});
|
||||
server.listen(0, common.mustCall(function() {
|
||||
server._handle.getsockname = function(out) {
|
||||
return -1;
|
||||
};
|
||||
assert.throws(() => this.address(),
|
||||
/^Error: address [\w|\s-\d]+$/);
|
||||
server.close();
|
||||
}));
|
||||
62
test/js/node/test/parallel/test-stream-readable-to-web.js
Normal file
62
test/js/node/test/parallel/test-stream-readable-to-web.js
Normal file
@@ -0,0 +1,62 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto) { common.skip('missing crypto'); }
|
||||
|
||||
const { Readable } = require('stream');
|
||||
const process = require('process');
|
||||
const { randomBytes } = require('crypto');
|
||||
const assert = require('assert');
|
||||
|
||||
// Based on: https://github.com/nodejs/node/issues/46347#issuecomment-1413886707
|
||||
// edit: make it cross-platform as /dev/urandom is not available on Windows
|
||||
{
|
||||
let currentMemoryUsage = process.memoryUsage().arrayBuffers;
|
||||
|
||||
// We initialize a stream, but not start consuming it
|
||||
const randomNodeStream = new Readable({
|
||||
read(size) {
|
||||
randomBytes(size, (err, buffer) => {
|
||||
if (err) {
|
||||
// If an error occurs, emit an 'error' event
|
||||
this.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Push the random bytes to the stream
|
||||
this.push(buffer);
|
||||
});
|
||||
}
|
||||
});
|
||||
// after 2 seconds, it'll get converted to web stream
|
||||
let randomWebStream;
|
||||
|
||||
// We check memory usage every second
|
||||
// since it's a stream, it shouldn't be higher than the chunk size
|
||||
const reportMemoryUsage = () => {
|
||||
const { arrayBuffers } = process.memoryUsage();
|
||||
currentMemoryUsage = arrayBuffers;
|
||||
|
||||
assert(currentMemoryUsage <= 256 * 1024 * 1024);
|
||||
};
|
||||
setInterval(reportMemoryUsage, 1000);
|
||||
|
||||
// after 1 second we use Readable.toWeb
|
||||
// memory usage should stay pretty much the same since it's still a stream
|
||||
setTimeout(() => {
|
||||
randomWebStream = Readable.toWeb(randomNodeStream);
|
||||
}, 1000);
|
||||
|
||||
// after 2 seconds we start consuming the stream
|
||||
// memory usage will grow, but the old chunks should be garbage-collected pretty quickly
|
||||
setTimeout(async () => {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
for await (const _ of randomWebStream) {
|
||||
// Do nothing, just let the stream flow
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
setTimeout(() => {
|
||||
// Test considered passed if we don't crash
|
||||
process.exit(0);
|
||||
}, 5000);
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const tls = require('tls');
|
||||
const assert = require('assert');
|
||||
const fixtures = require('../common/fixtures');
|
||||
const { getEventListeners, once } = require('events');
|
||||
|
||||
const serverOptions = {
|
||||
key: fixtures.readKey('agent1-key.pem'),
|
||||
cert: fixtures.readKey('agent1-cert.pem')
|
||||
};
|
||||
const server = tls.createServer(serverOptions);
|
||||
server.listen(0, common.mustCall(async () => {
|
||||
const port = server.address().port;
|
||||
const host = 'localhost';
|
||||
const connectOptions = (signal) => ({
|
||||
port,
|
||||
host,
|
||||
signal,
|
||||
rejectUnauthorized: false,
|
||||
});
|
||||
|
||||
function assertAbort(socket, testName) {
|
||||
return assert.rejects(() => once(socket, 'close'), {
|
||||
name: 'AbortError',
|
||||
}, `close ${testName} should have thrown`);
|
||||
}
|
||||
|
||||
async function postAbort() {
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
const socket = tls.connect(connectOptions(signal));
|
||||
assert.strictEqual(getEventListeners(signal, 'abort').length, 1);
|
||||
ac.abort();
|
||||
await assertAbort(socket, 'postAbort');
|
||||
}
|
||||
|
||||
async function preAbort() {
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
ac.abort();
|
||||
const socket = tls.connect(connectOptions(signal));
|
||||
assert.strictEqual(getEventListeners(signal, 'abort').length, 0);
|
||||
await assertAbort(socket, 'preAbort');
|
||||
}
|
||||
|
||||
async function tickAbort() {
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
const socket = tls.connect(connectOptions(signal));
|
||||
setImmediate(() => ac.abort());
|
||||
assert.strictEqual(getEventListeners(signal, 'abort').length, 1);
|
||||
await assertAbort(socket, 'tickAbort');
|
||||
}
|
||||
|
||||
async function testConstructor() {
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
ac.abort();
|
||||
const socket = new tls.TLSSocket(undefined, connectOptions(signal));
|
||||
assert.strictEqual(getEventListeners(signal, 'abort').length, 0);
|
||||
await assertAbort(socket, 'testConstructor');
|
||||
}
|
||||
|
||||
async function testConstructorPost() {
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
const socket = new tls.TLSSocket(undefined, connectOptions(signal));
|
||||
assert.strictEqual(getEventListeners(signal, 'abort').length, 1);
|
||||
ac.abort();
|
||||
await assertAbort(socket, 'testConstructorPost');
|
||||
}
|
||||
|
||||
async function testConstructorPostTick() {
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
const socket = new tls.TLSSocket(undefined, connectOptions(signal));
|
||||
setImmediate(() => ac.abort());
|
||||
assert.strictEqual(getEventListeners(signal, 'abort').length, 1);
|
||||
await assertAbort(socket, 'testConstructorPostTick');
|
||||
}
|
||||
|
||||
await postAbort();
|
||||
await preAbort();
|
||||
await tickAbort();
|
||||
await testConstructor();
|
||||
await testConstructorPost();
|
||||
await testConstructorPostTick();
|
||||
|
||||
server.close(common.mustCall());
|
||||
}));
|
||||
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
if (!common.hasIPv6)
|
||||
common.skip('no IPv6 support');
|
||||
|
||||
const assert = require('assert');
|
||||
const fixtures = require('../common/fixtures');
|
||||
const tls = require('tls');
|
||||
const dns = require('dns');
|
||||
|
||||
function runTest() {
|
||||
tls.createServer({
|
||||
cert: fixtures.readKey('agent1-cert.pem'),
|
||||
key: fixtures.readKey('agent1-key.pem'),
|
||||
}).on('connection', common.mustCall(function() {
|
||||
this.close();
|
||||
})).listen(0, '::1', common.mustCall(function() {
|
||||
const options = {
|
||||
host: 'localhost',
|
||||
port: this.address().port,
|
||||
family: 6,
|
||||
rejectUnauthorized: false,
|
||||
};
|
||||
// Will fail with ECONNREFUSED if the address family is not honored.
|
||||
tls.connect(options).once('secureConnect', common.mustCall(function() {
|
||||
assert.strictEqual(this.remoteAddress, '::1');
|
||||
this.destroy();
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
dns.lookup('localhost', {
|
||||
family: 6, all: true
|
||||
}, common.mustCall((err, addresses) => {
|
||||
if (err) {
|
||||
if (err.code === 'ENOTFOUND' || err.code === 'EAI_AGAIN')
|
||||
common.skip('localhost does not resolve to ::1');
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (addresses.some((val) => val.address === '::1'))
|
||||
runTest();
|
||||
else
|
||||
common.skip('localhost does not resolve to ::1');
|
||||
}));
|
||||
65
test/js/node/test/parallel/test-tls-junk-closes-server.js
Normal file
65
test/js/node/test/parallel/test-tls-junk-closes-server.js
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const tls = require('tls');
|
||||
const net = require('net');
|
||||
|
||||
const options = {
|
||||
key: fixtures.readKey('agent2-key.pem'),
|
||||
cert: fixtures.readKey('agent2-cert.pem')
|
||||
};
|
||||
|
||||
const server = tls.createServer(options, common.mustNotCall());
|
||||
|
||||
server.listen(0, common.mustCall(function() {
|
||||
const c = net.createConnection(this.address().port);
|
||||
|
||||
c.on('data', function() {
|
||||
// We must consume all data sent by the server. Otherwise the
|
||||
// end event will not be sent and the test will hang.
|
||||
// For example, when compiled with OpenSSL32 we see the
|
||||
// following response '15 03 03 00 02 02 16' which
|
||||
// decodes as a fatal (0x02) TLS error alert number 22 (0x16),
|
||||
// which corresponds to TLS1_AD_RECORD_OVERFLOW which matches
|
||||
// the error we see if NODE_DEBUG is turned on.
|
||||
// Some earlier OpenSSL versions did not seem to send a response
|
||||
// but the TLS spec seems to indicate there should be one
|
||||
// https://datatracker.ietf.org/doc/html/rfc8446#page-85
|
||||
// and error handling seems to have been re-written/improved
|
||||
// in OpenSSL32. Consuming the data allows the test to pass
|
||||
// either way.
|
||||
});
|
||||
|
||||
c.on('connect', common.mustCall(function() {
|
||||
c.write('blah\nblah\nblah\n');
|
||||
}));
|
||||
|
||||
c.on('end', common.mustCall(function() {
|
||||
server.close();
|
||||
}));
|
||||
}));
|
||||
130
test/js/node/test/parallel/test-tls-sni-server-client.js
Normal file
130
test/js/node/test/parallel/test-tls-sni-server-client.js
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
|
||||
function loadPEM(n) {
|
||||
return fixtures.readKey(`${n}.pem`);
|
||||
}
|
||||
|
||||
const serverOptions = {
|
||||
key: loadPEM('agent2-key'),
|
||||
cert: loadPEM('agent2-cert')
|
||||
};
|
||||
|
||||
const SNIContexts = {
|
||||
'a.example.com': {
|
||||
key: loadPEM('agent1-key'),
|
||||
cert: loadPEM('agent1-cert')
|
||||
},
|
||||
'asterisk.test.com': {
|
||||
key: loadPEM('agent3-key'),
|
||||
cert: loadPEM('agent3-cert')
|
||||
},
|
||||
'chain.example.com': {
|
||||
key: loadPEM('agent6-key'),
|
||||
// NOTE: Contains ca3 chain cert
|
||||
cert: loadPEM('agent6-cert')
|
||||
}
|
||||
};
|
||||
|
||||
test(
|
||||
{
|
||||
ca: [loadPEM('ca1-cert')],
|
||||
servername: 'a.example.com'
|
||||
},
|
||||
true,
|
||||
'a.example.com'
|
||||
);
|
||||
|
||||
test(
|
||||
{
|
||||
ca: [loadPEM('ca2-cert')],
|
||||
servername: 'b.test.com',
|
||||
},
|
||||
true,
|
||||
'b.test.com'
|
||||
);
|
||||
|
||||
test(
|
||||
{
|
||||
ca: [loadPEM('ca2-cert')],
|
||||
servername: 'a.b.test.com',
|
||||
},
|
||||
false,
|
||||
'a.b.test.com'
|
||||
);
|
||||
|
||||
test(
|
||||
{
|
||||
ca: [loadPEM('ca1-cert')],
|
||||
servername: 'c.wrong.com',
|
||||
},
|
||||
false,
|
||||
'c.wrong.com'
|
||||
);
|
||||
|
||||
test(
|
||||
{
|
||||
ca: [loadPEM('ca1-cert')],
|
||||
servername: 'chain.example.com',
|
||||
},
|
||||
true,
|
||||
'chain.example.com'
|
||||
);
|
||||
|
||||
function test(options, clientResult, serverResult) {
|
||||
const server = tls.createServer(serverOptions, (c) => {
|
||||
assert.strictEqual(c.servername, serverResult);
|
||||
assert.strictEqual(c.authorized, false);
|
||||
});
|
||||
|
||||
server.addContext('a.example.com', SNIContexts['a.example.com']);
|
||||
server.addContext('*.test.com', SNIContexts['asterisk.test.com']);
|
||||
server.addContext('chain.example.com', SNIContexts['chain.example.com']);
|
||||
|
||||
server.on('tlsClientError', common.mustNotCall());
|
||||
|
||||
server.listen(0, () => {
|
||||
const client = tls.connect({
|
||||
...options,
|
||||
port: server.address().port,
|
||||
rejectUnauthorized: false
|
||||
}, () => {
|
||||
const result = client.authorizationError &&
|
||||
(client.authorizationError === 'ERR_TLS_CERT_ALTNAME_INVALID');
|
||||
assert.strictEqual(result, clientResult);
|
||||
client.end();
|
||||
});
|
||||
|
||||
client.on('close', common.mustCall(() => {
|
||||
server.close();
|
||||
}));
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
'use strict';
|
||||
|
||||
// This test ensures that CryptoKey instances can be correctly
|
||||
// sent to a Worker via postMessage.
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const { subtle } = globalThis.crypto;
|
||||
const { once } = require('events');
|
||||
|
||||
const {
|
||||
Worker,
|
||||
parentPort,
|
||||
} = require('worker_threads');
|
||||
|
||||
const keyData =
|
||||
Buffer.from(
|
||||
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', 'hex');
|
||||
|
||||
const sig = '13691a79fb55a0417e4d6699a32f91ad29283fa2c1439865cc0632931f4f48dc';
|
||||
|
||||
async function doSig(key) {
|
||||
const signature = await subtle.sign({
|
||||
name: 'HMAC'
|
||||
}, key, Buffer.from('some data'));
|
||||
assert.strictEqual(Buffer.from(signature).toString('hex'), sig);
|
||||
}
|
||||
|
||||
if (process.env.HAS_STARTED_WORKER) {
|
||||
return parentPort.once('message', (key) => {
|
||||
assert.strictEqual(key.algorithm.name, 'HMAC');
|
||||
doSig(key).then(common.mustCall());
|
||||
});
|
||||
}
|
||||
|
||||
// Don't use isMainThread to allow running this test inside a worker.
|
||||
process.env.HAS_STARTED_WORKER = 1;
|
||||
|
||||
(async function() {
|
||||
const worker = new Worker(__filename);
|
||||
|
||||
await once(worker, 'online');
|
||||
|
||||
const key = await subtle.importKey(
|
||||
'raw',
|
||||
keyData,
|
||||
{ name: 'HMAC', hash: 'SHA-256' },
|
||||
true, ['sign', 'verify']);
|
||||
|
||||
worker.postMessage(key);
|
||||
|
||||
await doSig(key);
|
||||
})().then(common.mustCall());
|
||||
78
test/js/node/test/sequential/test-child-process-emfile.js
Normal file
78
test/js/node/test/sequential/test-child-process-emfile.js
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (common.isWindows)
|
||||
common.skip('no RLIMIT_NOFILE on Windows');
|
||||
|
||||
const assert = require('assert');
|
||||
const child_process = require('child_process');
|
||||
const fs = require('fs');
|
||||
|
||||
const ulimit = Number(child_process.execSync('ulimit -Hn'));
|
||||
if (ulimit > 64 || Number.isNaN(ulimit)) {
|
||||
const [cmd, opts] = common.escapePOSIXShell`ulimit -n 64 && "${process.execPath}" "${__filename}"`;
|
||||
// Sorry about this nonsense. It can be replaced if
|
||||
// https://github.com/nodejs/node-v0.x-archive/pull/2143#issuecomment-2847886
|
||||
// ever happens.
|
||||
const result = child_process.spawnSync(
|
||||
'/bin/sh',
|
||||
['-c', cmd],
|
||||
opts,
|
||||
);
|
||||
assert.strictEqual(result.stdout.toString(), '');
|
||||
assert.strictEqual(result.stderr.toString(), '');
|
||||
assert.strictEqual(result.status, 0);
|
||||
assert.strictEqual(result.error, undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
const openFds = [];
|
||||
|
||||
for (;;) {
|
||||
try {
|
||||
openFds.push(fs.openSync(__filename, 'r'));
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.code, 'EMFILE');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Should emit an error, not throw.
|
||||
const proc = child_process.spawn(process.execPath, ['-e', '0']);
|
||||
|
||||
// Verify that stdio is not setup on EMFILE or ENFILE.
|
||||
assert.strictEqual(proc.stdin, undefined);
|
||||
assert.strictEqual(proc.stdout, undefined);
|
||||
assert.strictEqual(proc.stderr, undefined);
|
||||
assert.strictEqual(proc.stdio, undefined);
|
||||
|
||||
proc.on('error', common.mustCall(function(err) {
|
||||
assert.strictEqual(err.code, 'EMFILE');
|
||||
}));
|
||||
|
||||
proc.on('exit', common.mustNotCall('"exit" event should not be emitted'));
|
||||
|
||||
// Close one fd for LSan
|
||||
if (openFds.length >= 1) {
|
||||
fs.closeSync(openFds.pop());
|
||||
}
|
||||
34
test/js/node/test/sequential/test-tls-lookup.js
Normal file
34
test/js/node/test/sequential/test-tls-lookup.js
Normal file
@@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
|
||||
['foobar', 1, {}, []].forEach(function connectThrows(input) {
|
||||
const opts = {
|
||||
host: 'localhost',
|
||||
port: common.PORT,
|
||||
lookup: input
|
||||
};
|
||||
|
||||
assert.throws(() => {
|
||||
tls.connect(opts);
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError'
|
||||
});
|
||||
});
|
||||
|
||||
connectDoesNotThrow(common.mustCall());
|
||||
|
||||
function connectDoesNotThrow(input) {
|
||||
const opts = {
|
||||
host: 'localhost',
|
||||
port: common.PORT,
|
||||
lookup: input
|
||||
};
|
||||
|
||||
tls.connect(opts);
|
||||
}
|
||||
Reference in New Issue
Block a user