Skip to content

Commit

Permalink
Close conn when HTTP/1.1 clients call bidi methods
Browse files Browse the repository at this point in the history
  • Loading branch information
timostamm committed Nov 30, 2022
1 parent 332f03b commit 3c8c393
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 5 deletions.
7 changes: 6 additions & 1 deletion packages/connect-node/src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,12 @@ export function createHandler<M extends MethodInfo>(
res: http.ServerResponse | http2.Http2ServerResponse
): void {
if (method.kind == MethodKind.BiDiStreaming && req.httpVersionMajor !== 2) {
return void endWithHttpStatus(res, 505, "Version Not Supported");
// Clients coded to expect full-duplex connections may hang if they've
// mistakenly negotiated HTTP/1.1. To unblock them, we must close the
// underlying TCP connection.
return void endWithHttpStatus(res, 505, "Version Not Supported", {
Connection: "close",
});
}
if (req.method !== "POST") {
// The gRPC-HTTP2, gRPC-Web, and Connect protocols are all POST-only.
Expand Down
15 changes: 11 additions & 4 deletions packages/connect-node/src/private/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import { assert } from "./assert.js";
import type { ReadableStreamReadResultLike } from "../lib.dom.streams.js";
import { Code, ConnectError, EnvelopedMessage } from "@bufbuild/connect-core";
import type { JsonValue } from "@bufbuild/protobuf";
import { nodeHeaderToWebHeader } from "./web-header-to-node-headers.js";
import {
nodeHeaderToWebHeader,
webHeaderToNodeHeaders,
} from "./web-header-to-node-headers.js";

export function jsonParse(bytes: Uint8Array): JsonValue {
const buf = bytes instanceof Buffer ? bytes : Buffer.from(bytes);
Expand Down Expand Up @@ -197,13 +200,17 @@ export function readToEnd(stream: stream.Readable): Promise<Uint8Array> {
export async function endWithHttpStatus(
res: http.ServerResponse | http2.Http2ServerResponse,
statusCode: number,
statusMessage: string
statusMessage: string,
header?: HeadersInit
): Promise<void> {
const headers: http.OutgoingHttpHeaders | undefined = header
? webHeaderToNodeHeaders(header)
: undefined;
if ("createPushResponse" in res) {
// this is a HTTP/2 response, which does not support status messages
res.writeHead(statusCode);
res.writeHead(statusCode, headers);
} else {
res.writeHead(statusCode, statusMessage);
res.writeHead(statusCode, statusMessage, headers);
}
await end(res);
}
Expand Down

0 comments on commit 3c8c393

Please sign in to comment.