Skip to content

Commit cd5eefc

Browse files
committed
feat(httphandshake): added logic for implementing server initial http handshake response
Logic for headers needed was implemented following the official spec at https://www.rfc-editor.org/rfc/rfc6455.html#section-4.2.2
1 parent c9fe195 commit cd5eefc

4 files changed

Lines changed: 89 additions & 3 deletions

File tree

src/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import CONFIG from "@/config/app.config";
99
import * as CONSTANTS from "@/libs/custom_lib/constants/constants";
1010

1111
import sendUpgradeErrorResponse from "./libs/custom_lib/sendUpgradeErrorResponse";
12+
import { upgradeHttpConnection } from "./libs/custom_lib/upgradeHttpConnection";
1213
import UpgradeValidatorFactory from "./libs/custom_lib/validateHttpHandshake";
1314
import handleProcessErrors from "./utils/handleProcessErrors";
1415

@@ -45,8 +46,8 @@ httpServer.listen(CONFIG.PORT, CONFIG.HOST, () => {
4546

4647
// handle inital http handshake in order to establish a ws connection
4748
// Docs: https://nodejs.org/docs/latest/api/http.html#event-upgrade_1
48-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
49-
httpServer.on("upgrade", (request, socket, _head) => {
49+
50+
httpServer.on("upgrade", (request, socket) => {
5051
// Parsing required client request headers in conformity with https://www.rfc-editor.org/rfc/rfc6455.html#section-4.1
5152
const validationResult = upgradeValidator.validate(request);
5253
// https://www.rfc-editor.org/rfc/rfc6455.html#section-4.2.1
@@ -58,6 +59,7 @@ httpServer.on("upgrade", (request, socket, _head) => {
5859
);
5960
return;
6061
}
62+
upgradeHttpConnection(request, socket);
6163
});
6264

6365
// implement basic error handling

src/libs/custom_lib/constants/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ export const upgradeConfig: UpgradeConfig = {
1616
method: "GET",
1717
allowedOrigins: ["http://127.0.0.1:5500", "http://localhost:5500"],
1818
};
19+
20+
export const GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import crypto from "node:crypto";
2+
import http from "node:http";
3+
import { Duplex } from "node:stream";
4+
5+
import * as CONSTANTS from "@/libs/custom_lib/constants/constants";
6+
7+
class UpgradeHeadersBuilder {
8+
private headers: Record<string, string> = {};
9+
10+
constructor(request: http.IncomingMessage) {
11+
this.buildDefaultHeaders(request);
12+
}
13+
14+
private buildDefaultHeaders(request: http.IncomingMessage): void {
15+
const secWebSocketKey = request.headers["sec-websocket-key"] || "";
16+
const data = secWebSocketKey + CONSTANTS.GUID;
17+
const hash = crypto.createHash("sha1").update(data).digest("base64");
18+
19+
this.headers = {
20+
Upgrade: "websocket",
21+
Connection: "Upgrade",
22+
"Sec-WebSocket-Accept": hash,
23+
};
24+
}
25+
26+
addHeader(name: string, value: string): this {
27+
this.headers[name] = value;
28+
return this;
29+
}
30+
31+
build(): Record<string, string> {
32+
return this.headers;
33+
}
34+
}
35+
36+
class HttpResponseBuilder {
37+
private statusCode: number = 101;
38+
private statusText: string = "Switching Protocols";
39+
private headers: Record<string, string>;
40+
41+
constructor(headers: Record<string, string>) {
42+
this.headers = headers;
43+
}
44+
45+
setStatus(code: number, text: string): this {
46+
this.statusCode = code;
47+
this.statusText = text;
48+
return this;
49+
}
50+
51+
addHeader(name: string, value: string): this {
52+
this.headers[name] = value;
53+
return this;
54+
}
55+
56+
build(): string {
57+
const statusLine = `HTTP/1.1 ${this.statusCode} ${this.statusText}\r\n`;
58+
const headerLines = Object.entries(this.headers)
59+
.map(([key, value]) => `${key}: ${value}`)
60+
.join("\r\n");
61+
62+
return statusLine + headerLines + "\r\n\r\n";
63+
}
64+
}
65+
66+
function startWebSocketConnection(socket: Duplex) {
67+
console.log(socket);
68+
}
69+
70+
export function upgradeHttpConnection(
71+
request: http.IncomingMessage,
72+
socket: Duplex,
73+
): void {
74+
const headers = new UpgradeHeadersBuilder(request).build();
75+
76+
const response = new HttpResponseBuilder(headers)
77+
.setStatus(101, "Switching Protocols")
78+
.build();
79+
80+
socket.write(response);
81+
82+
startWebSocketConnection(socket);
83+
}

src/libs/custom_lib/upgradeHttpConnexion.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)