mirror of
https://github.com/denoland/deno.git
synced 2025-01-04 05:18:59 -05:00
fix(ext/node): tls.connect
socket upgrades (#27125)
Fixes https://github.com/denoland/deno/issues/27087 Fixes https://github.com/denoland/deno/issues/26685 Fixes https://github.com/denoland/deno/issues/26660
This commit is contained in:
parent
f161adf19e
commit
1af2d2474e
4 changed files with 45 additions and 5 deletions
|
@ -148,9 +148,13 @@ export class TLSSocket extends net.Socket {
|
||||||
: new TCP(TCPConstants.SOCKET);
|
: new TCP(TCPConstants.SOCKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { promise, resolve } = Promise.withResolvers();
|
||||||
|
|
||||||
// Patches `afterConnect` hook to replace TCP conn with TLS conn
|
// Patches `afterConnect` hook to replace TCP conn with TLS conn
|
||||||
const afterConnect = handle.afterConnect;
|
const afterConnect = handle.afterConnect;
|
||||||
handle.afterConnect = async (req: any, status: number) => {
|
handle.afterConnect = async (req: any, status: number) => {
|
||||||
|
options.hostname ??= undefined; // coerce to undefined if null, startTls expects hostname to be undefined
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const conn = await Deno.startTls(handle[kStreamBaseField], options);
|
const conn = await Deno.startTls(handle[kStreamBaseField], options);
|
||||||
try {
|
try {
|
||||||
|
@ -164,15 +168,25 @@ export class TLSSocket extends net.Socket {
|
||||||
// Don't interrupt "secure" event to let the first read/write
|
// Don't interrupt "secure" event to let the first read/write
|
||||||
// operation emit the error.
|
// operation emit the error.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assign the TLS connection to the handle and resume reading.
|
||||||
handle[kStreamBaseField] = conn;
|
handle[kStreamBaseField] = conn;
|
||||||
|
handle.upgrading = false;
|
||||||
|
if (!handle.pauseOnCreate) {
|
||||||
|
handle.readStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
|
||||||
tlssock.emit("secure");
|
tlssock.emit("secure");
|
||||||
tlssock.removeListener("end", onConnectEnd);
|
tlssock.removeListener("end", onConnectEnd);
|
||||||
} catch (_) {
|
} catch {
|
||||||
// TODO(kt3k): Handle this
|
// TODO(kt3k): Handle this
|
||||||
}
|
}
|
||||||
return afterConnect.call(handle, req, status);
|
return afterConnect.call(handle, req, status);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handle.upgrading = promise;
|
||||||
(handle as any).verifyError = function () {
|
(handle as any).verifyError = function () {
|
||||||
return null; // Never fails, rejectUnauthorized is always true in Deno.
|
return null; // Never fails, rejectUnauthorized is always true in Deno.
|
||||||
};
|
};
|
||||||
|
|
|
@ -479,13 +479,13 @@ export class ClientHttp2Session extends Http2Session {
|
||||||
|
|
||||||
socket.on("error", socketOnError);
|
socket.on("error", socketOnError);
|
||||||
socket.on("close", socketOnClose);
|
socket.on("close", socketOnClose);
|
||||||
|
|
||||||
|
socket[kHandle].pauseOnCreate = true;
|
||||||
const connPromise = new Promise((resolve) => {
|
const connPromise = new Promise((resolve) => {
|
||||||
const eventName = url.startsWith("https") ? "secureConnect" : "connect";
|
const eventName = url.startsWith("https") ? "secureConnect" : "connect";
|
||||||
socket.once(eventName, () => {
|
socket.once(eventName, () => {
|
||||||
const rid = socket[kHandle][kStreamBaseField][internalRidSymbol];
|
const rid = socket[kHandle][kStreamBaseField][internalRidSymbol];
|
||||||
nextTick(() => {
|
nextTick(() => resolve(rid));
|
||||||
resolve(rid);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
socket[kSession] = this;
|
socket[kSession] = this;
|
||||||
|
|
|
@ -320,8 +320,16 @@ export class LibuvStreamWrap extends HandleWrap {
|
||||||
/** Internal method for reading from the attached stream. */
|
/** Internal method for reading from the attached stream. */
|
||||||
async #read() {
|
async #read() {
|
||||||
let buf = this.#buf;
|
let buf = this.#buf;
|
||||||
|
|
||||||
let nread: number | null;
|
let nread: number | null;
|
||||||
const ridBefore = this[kStreamBaseField]![internalRidSymbol];
|
const ridBefore = this[kStreamBaseField]![internalRidSymbol];
|
||||||
|
|
||||||
|
if (this.upgrading) {
|
||||||
|
// Starting an upgrade, stop reading. Upgrading will resume reading.
|
||||||
|
this.readStop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
nread = await this[kStreamBaseField]!.read(buf);
|
nread = await this[kStreamBaseField]!.read(buf);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -382,6 +390,11 @@ export class LibuvStreamWrap extends HandleWrap {
|
||||||
|
|
||||||
const ridBefore = this[kStreamBaseField]![internalRidSymbol];
|
const ridBefore = this[kStreamBaseField]![internalRidSymbol];
|
||||||
|
|
||||||
|
if (this.upgrading) {
|
||||||
|
// There is an upgrade in progress, queue the write request.
|
||||||
|
await this.upgrading;
|
||||||
|
}
|
||||||
|
|
||||||
let nwritten = 0;
|
let nwritten = 0;
|
||||||
try {
|
try {
|
||||||
// TODO(crowlKats): duplicate from runtime/js/13_buffer.js
|
// TODO(crowlKats): duplicate from runtime/js/13_buffer.js
|
||||||
|
@ -400,7 +413,6 @@ export class LibuvStreamWrap extends HandleWrap {
|
||||||
}
|
}
|
||||||
|
|
||||||
let status: number;
|
let status: number;
|
||||||
|
|
||||||
// TODO(cmorten): map err to status codes
|
// TODO(cmorten): map err to status codes
|
||||||
if (
|
if (
|
||||||
e instanceof Deno.errors.BadResource ||
|
e instanceof Deno.errors.BadResource ||
|
||||||
|
|
|
@ -257,3 +257,17 @@ Deno.test("TLSSocket.alpnProtocol is set for client", async () => {
|
||||||
listener.close();
|
listener.close();
|
||||||
await new Promise((resolve) => outgoing.on("close", resolve));
|
await new Promise((resolve) => outgoing.on("close", resolve));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Deno.test("tls connect upgrade tcp", async () => {
|
||||||
|
const { promise, resolve } = Promise.withResolvers<void>();
|
||||||
|
|
||||||
|
const socket = new net.Socket();
|
||||||
|
socket.connect(443, "google.com");
|
||||||
|
socket.on("connect", () => {
|
||||||
|
const secure = tls.connect({ socket });
|
||||||
|
secure.on("secureConnect", () => resolve());
|
||||||
|
});
|
||||||
|
|
||||||
|
await promise;
|
||||||
|
socket.destroy();
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in a new issue