mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
fix(ext/node/net): emit error
before close
when connection is refused (#24656)
This commit is contained in:
parent
29934d558c
commit
199a8ca4c5
5 changed files with 48 additions and 16 deletions
|
@ -531,16 +531,17 @@ export class Socket extends EventEmitter {
|
|||
healthCheck(this);
|
||||
stopReceiving(this);
|
||||
|
||||
state.handle!.close();
|
||||
state.handle!.close(() => {
|
||||
// Deviates from the Node implementation to avoid leaking the timer ops at 'close' event
|
||||
defaultTriggerAsyncIdScope(
|
||||
this[asyncIdSymbol],
|
||||
nextTick,
|
||||
socketCloseNT,
|
||||
this,
|
||||
);
|
||||
});
|
||||
state.handle = null;
|
||||
|
||||
defaultTriggerAsyncIdScope(
|
||||
this[asyncIdSymbol],
|
||||
nextTick,
|
||||
socketCloseNT,
|
||||
this,
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,13 +25,12 @@
|
|||
// - https://github.com/nodejs/node/blob/master/src/handle_wrap.h
|
||||
|
||||
// TODO(petamoriken): enable prefer-primordials for node polyfills
|
||||
// deno-lint-ignore-file prefer-primordials
|
||||
|
||||
import { unreachable } from "ext:deno_node/_util/asserts.ts";
|
||||
import {
|
||||
AsyncWrap,
|
||||
providerType,
|
||||
} from "ext:deno_node/internal_binding/async_wrap.ts";
|
||||
import { nextTick } from "ext:deno_node/_process/process.ts";
|
||||
|
||||
export class HandleWrap extends AsyncWrap {
|
||||
constructor(provider: providerType) {
|
||||
|
@ -40,7 +39,9 @@ export class HandleWrap extends AsyncWrap {
|
|||
|
||||
close(cb: () => void = () => {}) {
|
||||
this._onClose();
|
||||
queueMicrotask(cb);
|
||||
// We need to delay 'cb' at least 2 ticks to avoid "close" event happenning before "error" event in net.Socket
|
||||
// See https://github.com/denoland/deno/pull/24656 for more information
|
||||
nextTick(nextTick, cb);
|
||||
}
|
||||
|
||||
ref() {
|
||||
|
|
|
@ -846,7 +846,10 @@ Deno.test(
|
|||
"[node/http] client upgrade",
|
||||
{ permissions: { net: true } },
|
||||
async () => {
|
||||
const { promise, resolve } = Promise.withResolvers<void>();
|
||||
const { promise: serverClosed, resolve: resolveServer } = Promise
|
||||
.withResolvers<void>();
|
||||
const { promise: socketClosed, resolve: resolveSocket } = Promise
|
||||
.withResolvers<void>();
|
||||
const server = http.createServer((req, res) => {
|
||||
// @ts-ignore: It exists on TLSSocket
|
||||
assert(!req.socket.encrypted);
|
||||
|
@ -887,12 +890,16 @@ Deno.test(
|
|||
// @ts-ignore it's a socket for real
|
||||
serverSocket!.end();
|
||||
server.close(() => {
|
||||
resolve();
|
||||
resolveServer();
|
||||
});
|
||||
socket.on("close", () => {
|
||||
resolveSocket();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
await promise;
|
||||
await serverClosed;
|
||||
await socketClosed;
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import { assert, assertEquals } from "@std/assert/mod.ts";
|
|||
import * as path from "@std/path/mod.ts";
|
||||
import * as http from "node:http";
|
||||
|
||||
Deno.test("[node/net] close event emits after error event", async () => {
|
||||
Deno.test("[node/net] close event emits after error event - when host is not found", async () => {
|
||||
const socket = net.createConnection(27009, "doesnotexist");
|
||||
const events: ("error" | "close")[] = [];
|
||||
const errorEmitted = Promise.withResolvers<void>();
|
||||
|
@ -24,6 +24,25 @@ Deno.test("[node/net] close event emits after error event", async () => {
|
|||
assertEquals(events, ["error", "close"]);
|
||||
});
|
||||
|
||||
Deno.test("[node/net] close event emits after error event - when connection is refused", async () => {
|
||||
const socket = net.createConnection(27009, "127.0.0.1");
|
||||
const events: ("error" | "close")[] = [];
|
||||
const errorEmitted = Promise.withResolvers<void>();
|
||||
const closeEmitted = Promise.withResolvers<void>();
|
||||
socket.once("error", () => {
|
||||
events.push("error");
|
||||
errorEmitted.resolve();
|
||||
});
|
||||
socket.once("close", () => {
|
||||
events.push("close");
|
||||
closeEmitted.resolve();
|
||||
});
|
||||
await Promise.all([errorEmitted.promise, closeEmitted.promise]);
|
||||
|
||||
// `error` happens before `close`
|
||||
assertEquals(events, ["error", "close"]);
|
||||
});
|
||||
|
||||
Deno.test("[node/net] the port is available immediately after close callback", async () => {
|
||||
const deferred = Promise.withResolvers<void>();
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ for (
|
|||
conn.close();
|
||||
outgoing.destroy();
|
||||
listener.close();
|
||||
await new Promise((resolve) => outgoing.on("close", resolve));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -93,6 +94,7 @@ Connection: close
|
|||
|
||||
// https://github.com/denoland/deno/pull/20120
|
||||
Deno.test("tls.connect mid-read tcp->tls upgrade", async () => {
|
||||
const { promise, resolve } = Promise.withResolvers<void>();
|
||||
const ctl = new AbortController();
|
||||
const serve = Deno.serve({
|
||||
port: 8443,
|
||||
|
@ -119,8 +121,10 @@ Deno.test("tls.connect mid-read tcp->tls upgrade", async () => {
|
|||
conn.destroy();
|
||||
ctl.abort();
|
||||
});
|
||||
conn.on("close", resolve);
|
||||
|
||||
await serve.finished;
|
||||
await promise;
|
||||
});
|
||||
|
||||
Deno.test("tls.createServer creates a TLS server", async () => {
|
||||
|
@ -136,6 +140,7 @@ Deno.test("tls.createServer creates a TLS server", async () => {
|
|||
socket.destroy();
|
||||
}
|
||||
});
|
||||
socket.on("close", () => deferred.resolve());
|
||||
},
|
||||
);
|
||||
server.listen(0, async () => {
|
||||
|
@ -166,7 +171,6 @@ Deno.test("tls.createServer creates a TLS server", async () => {
|
|||
|
||||
conn.close();
|
||||
server.close();
|
||||
deferred.resolve();
|
||||
});
|
||||
await deferred.promise;
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue