Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ext/node): http2.createServer #22708

Merged
merged 16 commits into from Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1,061 changes: 918 additions & 143 deletions ext/node/polyfills/http2.ts

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions ext/node/polyfills/internal/errors.ts
Expand Up @@ -2248,6 +2248,16 @@ export class ERR_FALSY_VALUE_REJECTION extends NodeError {
this.reason = reason;
}
}

export class ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS extends NodeError {
constructor() {
super(
"ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS",
"Number of custom settings exceeds MAX_ADDITIONAL_SETTINGS",
);
}
}

export class ERR_HTTP2_INVALID_SETTING_VALUE extends NodeRangeError {
actual: unknown;
min?: number;
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/chmod_test.ts
Expand Up @@ -4,7 +4,7 @@ import {
assertEquals,
assertRejects,
assertThrows,
} from "./test_util.ts";
} from "../util/test_util.ts";

Deno.test(
{
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/command_test.ts
Expand Up @@ -6,7 +6,7 @@ import {
assertRejects,
assertStringIncludes,
assertThrows,
} from "./test_util.ts";
} from "../util/test_util.ts";

Deno.test(
{ permissions: { write: true, run: true, read: true } },
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/files_test.ts
Expand Up @@ -7,7 +7,7 @@ import {
assertEquals,
assertRejects,
assertThrows,
} from "./test_util.ts";
} from "../util/test_util.ts";
import { copy } from "@std/streams/copy.ts";

// Note tests for Deno.FsFile.setRaw is in integration tests.
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/read_file_test.ts
Expand Up @@ -6,7 +6,7 @@ import {
assertThrows,
pathToAbsoluteFileUrl,
unreachable,
} from "./test_util.ts";
} from "../util/test_util.ts";

Deno.test({ permissions: { read: true } }, function readFileSyncSuccess() {
const data = Deno.readFileSync("tests/testdata/assets/fixture.json");
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/real_path_test.ts
Expand Up @@ -6,7 +6,7 @@ import {
assertRejects,
assertThrows,
pathToAbsoluteFileUrl,
} from "./test_util.ts";
} from "../util/test_util.ts";

Deno.test({ permissions: { read: true } }, function realPathSyncSuccess() {
const relative = "tests/testdata/assets/fixture.json";
Expand Down
32 changes: 4 additions & 28 deletions tests/unit/serve_test.ts
Expand Up @@ -8,10 +8,12 @@ import {
assertEquals,
assertStringIncludes,
assertThrows,
curlRequest,
curlRequestWithStdErr,
execCode,
fail,
tmpUnixSocketPath,
} from "./test_util.ts";
} from "../util/test_util.ts";

// Since these tests may run in parallel, ensure this port is unique to this file
const servePort = 4502;
Expand Down Expand Up @@ -3708,7 +3710,7 @@ Deno.test(
// TODO(mmastrac): This test should eventually use fetch, when we support trailers there.
// This test is ignored because it's flaky and relies on cURL's verbose output.
Deno.test(
{ permissions: { net: true, run: true, read: true }, ignore: true },
{ permissions: { net: true, run: true, read: true }, ignore: false },
satyarohith marked this conversation as resolved.
Show resolved Hide resolved
async function httpServerTrailers() {
const ac = new AbortController();
const { resolve } = Promise.withResolvers<void>();
Expand Down Expand Up @@ -3793,32 +3795,6 @@ Deno.test(
},
);

async function curlRequest(args: string[]) {
const { success, stdout, stderr } = await new Deno.Command("curl", {
args,
stdout: "piped",
stderr: "piped",
}).output();
assert(
success,
`Failed to cURL ${args}: stdout\n\n${stdout}\n\nstderr:\n\n${stderr}`,
);
return new TextDecoder().decode(stdout);
}

async function curlRequestWithStdErr(args: string[]) {
const { success, stdout, stderr } = await new Deno.Command("curl", {
args,
stdout: "piped",
stderr: "piped",
}).output();
assert(
success,
`Failed to cURL ${args}: stdout\n\n${stdout}\n\nstderr:\n\n${stderr}`,
);
return [new TextDecoder().decode(stdout), new TextDecoder().decode(stderr)];
}

Deno.test("Deno.HttpServer is not thenable", async () => {
// deno-lint-ignore require-await
async function serveTest() {
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/symlink_test.ts
Expand Up @@ -4,7 +4,7 @@ import {
assertRejects,
assertThrows,
pathToAbsoluteFileUrl,
} from "./test_util.ts";
} from "../util/test_util.ts";

Deno.test(
{ permissions: { read: true, write: true } },
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/tls_test.ts
Expand Up @@ -6,7 +6,7 @@ import {
assertRejects,
assertStrictEquals,
assertThrows,
} from "./test_util.ts";
} from "../util/test_util.ts";
import { BufReader, BufWriter } from "@std/io/mod.ts";
import { readAll } from "@std/streams/read_all.ts";
import { writeAll } from "@std/streams/write_all.ts";
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/write_file_test.ts
Expand Up @@ -5,7 +5,7 @@ import {
assertRejects,
assertThrows,
unreachable,
} from "./test_util.ts";
} from "../util/test_util.ts";

Deno.test(
{ permissions: { read: true, write: true } },
Expand Down
2 changes: 1 addition & 1 deletion tests/unit_node/dgram_test.ts
@@ -1,7 +1,7 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

import { assertEquals } from "@std/assert/mod.ts";
import { execCode } from "../unit/test_util.ts";
import { execCode } from "../util/test_util.ts";
import { createSocket } from "node:dgram";

const listenPort = 4503;
Expand Down
2 changes: 1 addition & 1 deletion tests/unit_node/fs_test.ts
Expand Up @@ -12,7 +12,7 @@ import {
writeFileSync,
} from "node:fs";
import { constants as fsPromiseConstants, cp } from "node:fs/promises";
import { pathToAbsoluteFileUrl } from "../unit/test_util.ts";
import { pathToAbsoluteFileUrl } from "../util/test_util.ts";

Deno.test(
"[node/fs writeFileSync] write file without option",
Expand Down
21 changes: 21 additions & 0 deletions tests/unit_node/http2_test.ts
Expand Up @@ -3,6 +3,7 @@
import * as http2 from "node:http2";
import * as net from "node:net";
import { assert, assertEquals } from "@std/assert/mod.ts";
import { curlRequest } from "../util/test_util.ts";

for (const url of ["http://127.0.0.1:4246", "https://127.0.0.1:4247"]) {
Deno.test(`[node/http2 client] ${url}`, {
Expand Down Expand Up @@ -165,3 +166,23 @@ Deno.test("[node/http2 client GET https://www.example.com]", async () => {
assertEquals(status, 200);
assert(chunk.length > 0);
});

Deno.test("[node/http2.createServer()]", { sanitizeOps: false }, async () => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests are timing out when we have two http2.createServer() in the same file. I'm not sure how the tests are processed by Deno.test underneath but I'll explore what's the cause.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous test was timing out because we no longer emit "stream" on a session in the current implement. I replaced the test with the new test instead.

const server = http2.createServer((_req, res) => {
res.setHeader("Content-Type", "text/html");
res.setHeader("X-Foo", "bar");
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
res.write("Hello, World!");
res.end();
});
server.listen(0);
const port = (<net.AddressInfo> server.address()).port;
const endpoint = `http://localhost:${port}`;

const response = await curlRequest([
endpoint,
"--http2-prior-knowledge",
]);
assertEquals(response, "Hello, World!");
server.close();
});
2 changes: 1 addition & 1 deletion tests/unit_node/http_test.ts
Expand Up @@ -10,7 +10,7 @@ import { assertSpyCalls, spy } from "@std/testing/mock.ts";
import { gzip } from "node:zlib";
import { Buffer } from "node:buffer";
import { serve } from "@std/http/server.ts";
import { execCode } from "../unit/test_util.ts";
import { execCode } from "../util/test_util.ts";

Deno.test("[node/http listen]", async () => {
{
Expand Down
33 changes: 33 additions & 0 deletions tests/unit/test_util.ts → tests/util/test_util.ts
@@ -1,6 +1,7 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

import * as colors from "@std/fmt/colors.ts";
import { assert } from "@std/assert/mod.ts";
export { colors };
import { join, resolve } from "@std/path/mod.ts";
export {
Expand Down Expand Up @@ -85,3 +86,35 @@ export function tmpUnixSocketPath(): string {
const folder = Deno.makeTempDirSync();
return join(folder, "socket");
}

export async function curlRequest(args: string[]) {
const { success, stdout, stderr } = await new Deno.Command("curl", {
args,
stdout: "piped",
stderr: "piped",
}).output();
const decoder = new TextDecoder();
assert(
success,
`Failed to cURL ${args}: stdout\n\n${
decoder.decode(stdout)
}\n\nstderr:\n\n${decoder.decode(stderr)}`,
);
return decoder.decode(stdout);
}

export async function curlRequestWithStdErr(args: string[]) {
const { success, stdout, stderr } = await new Deno.Command("curl", {
args,
stdout: "piped",
stderr: "piped",
}).output();
const decoder = new TextDecoder();
assert(
success,
`Failed to cURL ${args}: stdout\n\n${
decoder.decode(stdout)
}\n\nstderr:\n\n${decoder.decode(stderr)}`,
);
return [decoder.decode(stdout), decoder.decode(stderr)];
}