mirror of
https://github.com/denoland/deno.git
synced 2024-11-29 16:30:56 -05:00
6984b63f2f
This commit migrates all ops to use new resource table and "AsyncRefCell". Old implementation of resource table was completely removed and all code referencing it was updated to use new system.
628 lines
18 KiB
TypeScript
628 lines
18 KiB
TypeScript
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
import {
|
|
assert,
|
|
assertEquals,
|
|
assertNotEquals,
|
|
assertThrows,
|
|
assertThrowsAsync,
|
|
deferred,
|
|
unitTest,
|
|
} from "./test_util.ts";
|
|
|
|
unitTest({ perms: { net: true } }, function netTcpListenClose(): void {
|
|
const listener = Deno.listen({ hostname: "127.0.0.1", port: 3500 });
|
|
assert(listener.addr.transport === "tcp");
|
|
assertEquals(listener.addr.hostname, "127.0.0.1");
|
|
assertEquals(listener.addr.port, 3500);
|
|
assertNotEquals(listener.rid, 0);
|
|
listener.close();
|
|
});
|
|
|
|
unitTest(
|
|
{
|
|
perms: { net: true },
|
|
},
|
|
function netUdpListenClose(): void {
|
|
const socket = Deno.listenDatagram({
|
|
hostname: "127.0.0.1",
|
|
port: 3500,
|
|
transport: "udp",
|
|
});
|
|
assert(socket.addr.transport === "udp");
|
|
assertEquals(socket.addr.hostname, "127.0.0.1");
|
|
assertEquals(socket.addr.port, 3500);
|
|
socket.close();
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
|
|
function netUnixListenClose(): void {
|
|
const filePath = Deno.makeTempFileSync();
|
|
const socket = Deno.listen({
|
|
path: filePath,
|
|
transport: "unix",
|
|
});
|
|
assert(socket.addr.transport === "unix");
|
|
assertEquals(socket.addr.path, filePath);
|
|
socket.close();
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
|
|
function netUnixPacketListenClose(): void {
|
|
const filePath = Deno.makeTempFileSync();
|
|
const socket = Deno.listenDatagram({
|
|
path: filePath,
|
|
transport: "unixpacket",
|
|
});
|
|
assert(socket.addr.transport === "unixpacket");
|
|
assertEquals(socket.addr.path, filePath);
|
|
socket.close();
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ ignore: Deno.build.os === "windows", perms: { read: true } },
|
|
function netUnixListenWritePermission(): void {
|
|
assertThrows(() => {
|
|
const filePath = Deno.makeTempFileSync();
|
|
const socket = Deno.listen({
|
|
path: filePath,
|
|
transport: "unix",
|
|
});
|
|
assert(socket.addr.transport === "unix");
|
|
assertEquals(socket.addr.path, filePath);
|
|
socket.close();
|
|
}, Deno.errors.PermissionDenied);
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ ignore: Deno.build.os === "windows", perms: { read: true } },
|
|
function netUnixPacketListenWritePermission(): void {
|
|
assertThrows(() => {
|
|
const filePath = Deno.makeTempFileSync();
|
|
const socket = Deno.listenDatagram({
|
|
path: filePath,
|
|
transport: "unixpacket",
|
|
});
|
|
assert(socket.addr.transport === "unixpacket");
|
|
assertEquals(socket.addr.path, filePath);
|
|
socket.close();
|
|
}, Deno.errors.PermissionDenied);
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{
|
|
perms: { net: true },
|
|
},
|
|
async function netTcpCloseWhileAccept(): Promise<void> {
|
|
const listener = Deno.listen({ port: 4501 });
|
|
const p = listener.accept();
|
|
listener.close();
|
|
await assertThrowsAsync(
|
|
async (): Promise<void> => {
|
|
await p;
|
|
},
|
|
Deno.errors.BadResource,
|
|
"Listener has been closed",
|
|
);
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
|
|
async function netUnixCloseWhileAccept(): Promise<void> {
|
|
const filePath = await Deno.makeTempFile();
|
|
const listener = Deno.listen({
|
|
path: filePath,
|
|
transport: "unix",
|
|
});
|
|
const p = listener.accept();
|
|
listener.close();
|
|
await assertThrowsAsync(
|
|
async (): Promise<void> => {
|
|
await p;
|
|
},
|
|
Deno.errors.BadResource,
|
|
"Listener has been closed",
|
|
);
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ perms: { net: true } },
|
|
async function netTcpConcurrentAccept(): Promise<void> {
|
|
const listener = Deno.listen({ port: 4502 });
|
|
let acceptErrCount = 0;
|
|
const checkErr = (e: Error): void => {
|
|
if (e.message === "Listener has been closed") {
|
|
assertEquals(acceptErrCount, 1);
|
|
} else if (e.message === "Another accept task is ongoing") {
|
|
acceptErrCount++;
|
|
} else {
|
|
throw new Error("Unexpected error message");
|
|
}
|
|
};
|
|
const p = listener.accept().catch(checkErr);
|
|
const p1 = listener.accept().catch(checkErr);
|
|
await Promise.race([p, p1]);
|
|
listener.close();
|
|
await Promise.all([p, p1]);
|
|
assertEquals(acceptErrCount, 1);
|
|
},
|
|
);
|
|
|
|
// TODO(jsouto): Enable when tokio updates mio to v0.7!
|
|
unitTest(
|
|
{ ignore: true, perms: { read: true, write: true } },
|
|
async function netUnixConcurrentAccept(): Promise<void> {
|
|
const filePath = await Deno.makeTempFile();
|
|
const listener = Deno.listen({ transport: "unix", path: filePath });
|
|
let acceptErrCount = 0;
|
|
const checkErr = (e: Error): void => {
|
|
if (e.message === "Listener has been closed") {
|
|
assertEquals(acceptErrCount, 1);
|
|
} else if (e.message === "Another accept task is ongoing") {
|
|
acceptErrCount++;
|
|
} else {
|
|
throw new Error("Unexpected error message");
|
|
}
|
|
};
|
|
const p = listener.accept().catch(checkErr);
|
|
const p1 = listener.accept().catch(checkErr);
|
|
await Promise.race([p, p1]);
|
|
listener.close();
|
|
await [p, p1];
|
|
assertEquals(acceptErrCount, 1);
|
|
},
|
|
);
|
|
|
|
unitTest({ perms: { net: true } }, async function netTcpDialListen(): Promise<
|
|
void
|
|
> {
|
|
const listener = Deno.listen({ port: 3500 });
|
|
listener.accept().then(
|
|
async (conn): Promise<void> => {
|
|
assert(conn.remoteAddr != null);
|
|
assert(conn.localAddr.transport === "tcp");
|
|
assertEquals(conn.localAddr.hostname, "127.0.0.1");
|
|
assertEquals(conn.localAddr.port, 3500);
|
|
await conn.write(new Uint8Array([1, 2, 3]));
|
|
conn.close();
|
|
},
|
|
);
|
|
|
|
const conn = await Deno.connect({ hostname: "127.0.0.1", port: 3500 });
|
|
assert(conn.remoteAddr.transport === "tcp");
|
|
assertEquals(conn.remoteAddr.hostname, "127.0.0.1");
|
|
assertEquals(conn.remoteAddr.port, 3500);
|
|
assert(conn.localAddr != null);
|
|
const buf = new Uint8Array(1024);
|
|
const readResult = await conn.read(buf);
|
|
assertEquals(3, readResult);
|
|
assertEquals(1, buf[0]);
|
|
assertEquals(2, buf[1]);
|
|
assertEquals(3, buf[2]);
|
|
assert(conn.rid > 0);
|
|
|
|
assert(readResult !== null);
|
|
|
|
const readResult2 = await conn.read(buf);
|
|
assertEquals(readResult2, null);
|
|
|
|
listener.close();
|
|
conn.close();
|
|
});
|
|
|
|
unitTest(
|
|
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
|
|
async function netUnixDialListen(): Promise<void> {
|
|
const filePath = await Deno.makeTempFile();
|
|
const listener = Deno.listen({ path: filePath, transport: "unix" });
|
|
listener.accept().then(
|
|
async (conn): Promise<void> => {
|
|
assert(conn.remoteAddr != null);
|
|
assert(conn.localAddr.transport === "unix");
|
|
assertEquals(conn.localAddr.path, filePath);
|
|
await conn.write(new Uint8Array([1, 2, 3]));
|
|
conn.close();
|
|
},
|
|
);
|
|
const conn = await Deno.connect({ path: filePath, transport: "unix" });
|
|
assert(conn.remoteAddr.transport === "unix");
|
|
assertEquals(conn.remoteAddr.path, filePath);
|
|
assert(conn.remoteAddr != null);
|
|
const buf = new Uint8Array(1024);
|
|
const readResult = await conn.read(buf);
|
|
assertEquals(3, readResult);
|
|
assertEquals(1, buf[0]);
|
|
assertEquals(2, buf[1]);
|
|
assertEquals(3, buf[2]);
|
|
assert(conn.rid > 0);
|
|
|
|
assert(readResult !== null);
|
|
|
|
const readResult2 = await conn.read(buf);
|
|
assertEquals(readResult2, null);
|
|
|
|
listener.close();
|
|
conn.close();
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ perms: { net: true } },
|
|
async function netUdpSendReceive(): Promise<void> {
|
|
const alice = Deno.listenDatagram({ port: 3500, transport: "udp" });
|
|
assert(alice.addr.transport === "udp");
|
|
assertEquals(alice.addr.port, 3500);
|
|
assertEquals(alice.addr.hostname, "127.0.0.1");
|
|
|
|
const bob = Deno.listenDatagram({ port: 4501, transport: "udp" });
|
|
assert(bob.addr.transport === "udp");
|
|
assertEquals(bob.addr.port, 4501);
|
|
assertEquals(bob.addr.hostname, "127.0.0.1");
|
|
|
|
const sent = new Uint8Array([1, 2, 3]);
|
|
const byteLength = await alice.send(sent, bob.addr);
|
|
|
|
assertEquals(byteLength, 3);
|
|
|
|
const [recvd, remote] = await bob.receive();
|
|
assert(remote.transport === "udp");
|
|
assertEquals(remote.port, 3500);
|
|
assertEquals(recvd.length, 3);
|
|
assertEquals(1, recvd[0]);
|
|
assertEquals(2, recvd[1]);
|
|
assertEquals(3, recvd[2]);
|
|
alice.close();
|
|
bob.close();
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ perms: { net: true } },
|
|
async function netUdpConcurrentSendReceive(): Promise<void> {
|
|
const socket = Deno.listenDatagram({ port: 3500, transport: "udp" });
|
|
assert(socket.addr.transport === "udp");
|
|
assertEquals(socket.addr.port, 3500);
|
|
assertEquals(socket.addr.hostname, "127.0.0.1");
|
|
|
|
const recvPromise = socket.receive();
|
|
|
|
const sendBuf = new Uint8Array([1, 2, 3]);
|
|
const sendLen = await socket.send(sendBuf, socket.addr);
|
|
assertEquals(sendLen, 3);
|
|
|
|
const [recvBuf, recvAddr] = await recvPromise;
|
|
assertEquals(recvBuf.length, 3);
|
|
assertEquals(1, recvBuf[0]);
|
|
assertEquals(2, recvBuf[1]);
|
|
assertEquals(3, recvBuf[2]);
|
|
|
|
socket.close();
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ perms: { net: true } },
|
|
async function netUdpBorrowMutError(): Promise<void> {
|
|
const socket = Deno.listenDatagram({
|
|
port: 4501,
|
|
transport: "udp",
|
|
});
|
|
// Panic happened on second send: BorrowMutError
|
|
const a = socket.send(new Uint8Array(), socket.addr);
|
|
const b = socket.send(new Uint8Array(), socket.addr);
|
|
await Promise.all([a, b]);
|
|
socket.close();
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
|
|
async function netUnixPacketSendReceive(): Promise<void> {
|
|
const filePath = await Deno.makeTempFile();
|
|
const alice = Deno.listenDatagram({
|
|
path: filePath,
|
|
transport: "unixpacket",
|
|
});
|
|
assert(alice.addr.transport === "unixpacket");
|
|
assertEquals(alice.addr.path, filePath);
|
|
|
|
const bob = Deno.listenDatagram({
|
|
path: filePath,
|
|
transport: "unixpacket",
|
|
});
|
|
assert(bob.addr.transport === "unixpacket");
|
|
assertEquals(bob.addr.path, filePath);
|
|
|
|
const sent = new Uint8Array([1, 2, 3]);
|
|
const byteLength = await alice.send(sent, bob.addr);
|
|
assertEquals(byteLength, 3);
|
|
|
|
const [recvd, remote] = await bob.receive();
|
|
assert(remote.transport === "unixpacket");
|
|
assertEquals(remote.path, filePath);
|
|
assertEquals(recvd.length, 3);
|
|
assertEquals(1, recvd[0]);
|
|
assertEquals(2, recvd[1]);
|
|
assertEquals(3, recvd[2]);
|
|
alice.close();
|
|
bob.close();
|
|
},
|
|
);
|
|
|
|
// TODO(piscisaureus): Enable after Tokio v0.3/v1.0 upgrade.
|
|
unitTest(
|
|
{ ignore: true, perms: { read: true, write: true } },
|
|
async function netUnixPacketConcurrentSendReceive(): Promise<void> {
|
|
const filePath = await Deno.makeTempFile();
|
|
const socket = Deno.listenDatagram({
|
|
path: filePath,
|
|
transport: "unixpacket",
|
|
});
|
|
assert(socket.addr.transport === "unixpacket");
|
|
assertEquals(socket.addr.path, filePath);
|
|
|
|
const recvPromise = socket.receive();
|
|
|
|
const sendBuf = new Uint8Array([1, 2, 3]);
|
|
const sendLen = await socket.send(sendBuf, socket.addr);
|
|
assertEquals(sendLen, 3);
|
|
|
|
const [recvBuf, recvAddr] = await recvPromise;
|
|
assertEquals(recvBuf.length, 3);
|
|
assertEquals(1, recvBuf[0]);
|
|
assertEquals(2, recvBuf[1]);
|
|
assertEquals(3, recvBuf[2]);
|
|
|
|
socket.close();
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ perms: { net: true } },
|
|
async function netTcpListenIteratorBreakClosesResource(): Promise<void> {
|
|
const promise = deferred();
|
|
|
|
async function iterate(listener: Deno.Listener): Promise<void> {
|
|
let i = 0;
|
|
|
|
for await (const conn of listener) {
|
|
conn.close();
|
|
i++;
|
|
|
|
if (i > 1) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
promise.resolve();
|
|
}
|
|
|
|
const addr = { hostname: "127.0.0.1", port: 8888 };
|
|
const listener = Deno.listen(addr);
|
|
iterate(listener);
|
|
|
|
await new Promise<void>((resolve) => {
|
|
setTimeout(resolve, 100);
|
|
});
|
|
const conn1 = await Deno.connect(addr);
|
|
conn1.close();
|
|
const conn2 = await Deno.connect(addr);
|
|
conn2.close();
|
|
|
|
await promise;
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ perms: { net: true } },
|
|
async function netTcpListenCloseWhileIterating(): Promise<void> {
|
|
const listener = Deno.listen({ port: 8000 });
|
|
const nextWhileClosing = listener[Symbol.asyncIterator]().next();
|
|
listener.close();
|
|
assertEquals(await nextWhileClosing, { value: undefined, done: true });
|
|
|
|
const nextAfterClosing = listener[Symbol.asyncIterator]().next();
|
|
assertEquals(await nextAfterClosing, { value: undefined, done: true });
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ perms: { net: true } },
|
|
async function netUdpListenCloseWhileIterating(): Promise<void> {
|
|
const socket = Deno.listenDatagram({ port: 8000, transport: "udp" });
|
|
const nextWhileClosing = socket[Symbol.asyncIterator]().next();
|
|
socket.close();
|
|
assertEquals(await nextWhileClosing, { value: undefined, done: true });
|
|
|
|
const nextAfterClosing = socket[Symbol.asyncIterator]().next();
|
|
assertEquals(await nextAfterClosing, { value: undefined, done: true });
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
|
|
async function netUnixListenCloseWhileIterating(): Promise<void> {
|
|
const filePath = Deno.makeTempFileSync();
|
|
const socket = Deno.listen({ path: filePath, transport: "unix" });
|
|
const nextWhileClosing = socket[Symbol.asyncIterator]().next();
|
|
socket.close();
|
|
assertEquals(await nextWhileClosing, { value: undefined, done: true });
|
|
|
|
const nextAfterClosing = socket[Symbol.asyncIterator]().next();
|
|
assertEquals(await nextAfterClosing, { value: undefined, done: true });
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
|
|
async function netUnixPacketListenCloseWhileIterating(): Promise<void> {
|
|
const filePath = Deno.makeTempFileSync();
|
|
const socket = Deno.listenDatagram({
|
|
path: filePath,
|
|
transport: "unixpacket",
|
|
});
|
|
const nextWhileClosing = socket[Symbol.asyncIterator]().next();
|
|
socket.close();
|
|
assertEquals(await nextWhileClosing, { value: undefined, done: true });
|
|
|
|
const nextAfterClosing = socket[Symbol.asyncIterator]().next();
|
|
assertEquals(await nextAfterClosing, { value: undefined, done: true });
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{
|
|
// FIXME(bartlomieju)
|
|
ignore: true,
|
|
perms: { net: true },
|
|
},
|
|
async function netListenAsyncIterator(): Promise<void> {
|
|
const addr = { hostname: "127.0.0.1", port: 3500 };
|
|
const listener = Deno.listen(addr);
|
|
const runAsyncIterator = async (): Promise<void> => {
|
|
for await (const conn of listener) {
|
|
await conn.write(new Uint8Array([1, 2, 3]));
|
|
conn.close();
|
|
}
|
|
};
|
|
runAsyncIterator();
|
|
const conn = await Deno.connect(addr);
|
|
const buf = new Uint8Array(1024);
|
|
const readResult = await conn.read(buf);
|
|
assertEquals(3, readResult);
|
|
assertEquals(1, buf[0]);
|
|
assertEquals(2, buf[1]);
|
|
assertEquals(3, buf[2]);
|
|
assert(conn.rid > 0);
|
|
|
|
assert(readResult !== null);
|
|
|
|
const readResult2 = await conn.read(buf);
|
|
assertEquals(readResult2, null);
|
|
|
|
listener.close();
|
|
conn.close();
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{
|
|
// FIXME(bartlomieju)
|
|
ignore: true,
|
|
perms: { net: true },
|
|
},
|
|
async function netCloseWriteSuccess() {
|
|
const addr = { hostname: "127.0.0.1", port: 3500 };
|
|
const listener = Deno.listen(addr);
|
|
const closeDeferred = deferred();
|
|
listener.accept().then(async (conn) => {
|
|
await conn.write(new Uint8Array([1, 2, 3]));
|
|
await closeDeferred;
|
|
conn.close();
|
|
});
|
|
const conn = await Deno.connect(addr);
|
|
conn.closeWrite(); // closing write
|
|
const buf = new Uint8Array(1024);
|
|
// Check read not impacted
|
|
const readResult = await conn.read(buf);
|
|
assertEquals(3, readResult);
|
|
assertEquals(1, buf[0]);
|
|
assertEquals(2, buf[1]);
|
|
assertEquals(3, buf[2]);
|
|
// Check write should be closed
|
|
await assertThrowsAsync(async () => {
|
|
await conn.write(new Uint8Array([1, 2, 3]));
|
|
}, Deno.errors.BrokenPipe);
|
|
closeDeferred.resolve();
|
|
listener.close();
|
|
conn.close();
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{
|
|
// FIXME(bartlomieju)
|
|
ignore: true,
|
|
perms: { net: true },
|
|
},
|
|
async function netDoubleCloseWrite() {
|
|
const addr = { hostname: "127.0.0.1", port: 3500 };
|
|
const listener = Deno.listen(addr);
|
|
const closeDeferred = deferred();
|
|
listener.accept().then(async (conn) => {
|
|
await closeDeferred;
|
|
conn.close();
|
|
});
|
|
const conn = await Deno.connect(addr);
|
|
conn.closeWrite(); // closing write
|
|
assertThrows(() => {
|
|
// Duplicated close should throw error
|
|
conn.closeWrite();
|
|
}, Deno.errors.NotConnected);
|
|
closeDeferred.resolve();
|
|
listener.close();
|
|
conn.close();
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{
|
|
perms: { net: true },
|
|
},
|
|
async function netHangsOnClose() {
|
|
let acceptedConn: Deno.Conn;
|
|
const resolvable = deferred();
|
|
|
|
async function iteratorReq(listener: Deno.Listener): Promise<void> {
|
|
const p = new Uint8Array(10);
|
|
const conn = await listener.accept();
|
|
acceptedConn = conn;
|
|
|
|
try {
|
|
while (true) {
|
|
const nread = await conn.read(p);
|
|
if (nread === null) {
|
|
break;
|
|
}
|
|
await conn.write(new Uint8Array([1, 2, 3]));
|
|
}
|
|
} catch (err) {
|
|
assert(!!err);
|
|
assert(err instanceof Deno.errors.BadResource);
|
|
}
|
|
|
|
resolvable.resolve();
|
|
}
|
|
|
|
const addr = { hostname: "127.0.0.1", port: 3500 };
|
|
const listener = Deno.listen(addr);
|
|
iteratorReq(listener);
|
|
const conn = await Deno.connect(addr);
|
|
await conn.write(new Uint8Array([1, 2, 3, 4]));
|
|
const buf = new Uint8Array(10);
|
|
await conn.read(buf);
|
|
conn!.close();
|
|
acceptedConn!.close();
|
|
listener.close();
|
|
await resolvable;
|
|
},
|
|
);
|
|
|
|
unitTest(
|
|
{
|
|
perms: { net: true },
|
|
},
|
|
function netExplicitUndefinedHostname() {
|
|
const listener = Deno.listen({ hostname: undefined, port: 8080 });
|
|
assertEquals((listener.addr as Deno.NetAddr).hostname, "0.0.0.0");
|
|
listener.close();
|
|
},
|
|
);
|