Skip to content

Commit

Permalink
fix(node): implement TLSSocket._start (#20120)
Browse files Browse the repository at this point in the history
Closes #19983
Closes #18303
Closes #16681
Closes #19978
  • Loading branch information
littledivy authored Aug 11, 2023
1 parent 2f00b0a commit 33dc5d2
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 3 deletions.
32 changes: 32 additions & 0 deletions cli/tests/unit_node/tls_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,38 @@ Connection: close
await serve;
});

// https://github.com/denoland/deno/pull/20120
Deno.test("tls.connect mid-read tcp->tls upgrade", async () => {
const ctl = new AbortController();
const serve = serveTls(() => new Response("hello"), {
port: 8443,
key,
cert,
signal: ctl.signal,
});

await delay(200);

const conn = tls.connect({
host: "localhost",
port: 8443,
secureContext: {
ca: rootCaCert,
// deno-lint-ignore no-explicit-any
} as any,
});

conn.setEncoding("utf8");
conn.write(`GET / HTTP/1.1\nHost: www.google.com\n\n`);

conn.on("data", (_) => {
conn.destroy();
ctl.abort();
});

await serve;
});

Deno.test("tls.createServer creates a TLS server", async () => {
const p = deferred();
const server = tls.createServer(
Expand Down
16 changes: 14 additions & 2 deletions ext/node/polyfills/_tls_wrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ import {
import { EventEmitter } from "node:events";
import { kEmptyObject } from "ext:deno_node/internal/util.mjs";
import { nextTick } from "ext:deno_node/_next_tick.ts";
import { kHandle } from "ext:deno_node/internal/stream_base_commons.ts";
import {
isAnyArrayBuffer,
isArrayBufferView,
} from "ext:deno_node/internal/util/types.ts";

const kConnectOptions = Symbol("connect-options");
const kIsVerified = Symbol("verified");
Expand Down Expand Up @@ -71,7 +76,11 @@ export class TLSSocket extends net.Socket {
[kPendingSession]: any;
[kConnectOptions]: any;
ssl: any;
_start: any;

_start() {
this[kHandle].afterConnect();
}

constructor(socket: any, opts: any = kEmptyObject) {
const tlsOptions = { ...opts };

Expand All @@ -84,6 +93,9 @@ export class TLSSocket extends net.Socket {

let caCerts = tlsOptions?.secureContext?.ca;
if (typeof caCerts === "string") caCerts = [caCerts];
else if (isArrayBufferView(caCerts) || isAnyArrayBuffer(caCerts)) {
caCerts = [new TextDecoder().decode(caCerts)];
}
tlsOptions.caCerts = caCerts;

super({
Expand Down Expand Up @@ -139,9 +151,9 @@ export class TLSSocket extends net.Socket {
handle.afterConnect = async (req: any, status: number) => {
try {
const conn = await Deno.startTls(handle[kStreamBaseField], options);
handle[kStreamBaseField] = conn;
tlssock.emit("secure");
tlssock.removeListener("end", onConnectEnd);
handle[kStreamBaseField] = conn;
} catch {
// TODO(kt3k): Handle this
}
Expand Down
17 changes: 16 additions & 1 deletion ext/node/polyfills/internal_binding/stream_wrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,16 @@ export class LibuvStreamWrap extends HandleWrap {
let buf = BUF;

let nread: number | null;
const ridBefore = this[kStreamBaseField]!.rid;
try {
nread = await this[kStreamBaseField]!.read(buf);
} catch (e) {
// Try to read again if the underlying stream resource
// changed. This can happen during TLS upgrades (eg. STARTTLS)
if (ridBefore != this[kStreamBaseField]!.rid) {
return this.#read();
}

if (
e instanceof Deno.errors.Interrupted ||
e instanceof Deno.errors.BadResource
Expand Down Expand Up @@ -365,15 +372,23 @@ export class LibuvStreamWrap extends HandleWrap {
async #write(req: WriteWrap<LibuvStreamWrap>, data: Uint8Array) {
const { byteLength } = data;

const ridBefore = this[kStreamBaseField]!.rid;

let nwritten = 0;
try {
// TODO(crowlKats): duplicate from runtime/js/13_buffer.js
let nwritten = 0;
while (nwritten < data.length) {
nwritten += await this[kStreamBaseField]!.write(
data.subarray(nwritten),
);
}
} catch (e) {
// Try to read again if the underlying stream resource
// changed. This can happen during TLS upgrades (eg. STARTTLS)
if (ridBefore != this[kStreamBaseField]!.rid) {
return this.#write(req, data.subarray(nwritten));
}

let status: number;

// TODO(cmorten): map err to status codes
Expand Down

0 comments on commit 33dc5d2

Please sign in to comment.