From 32087c357f74c045371216397b32846d13ce807b Mon Sep 17 00:00:00 2001 From: yuhao <76569582+yuhao423@users.noreply.github.com> Date: Mon, 24 Jun 2024 09:38:45 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E6=8F=A1=E6=89=8B=20(#15)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: test * sv * fewngo * 3223 * chore: 加入commit提交规范 * chore: 优化commit规范 * workflow: 增加ci检测及加入pr模板 * fix: 修复pnpm format引起的ci问题 * fix: 修复pnpm lint引起的ci问题 * fix: 修复pnpm lint引起的ci问题 * feat: 初始化websocket客户端 * fix: 修改eslint规则,优化websocket(#6) * ci: 去除typescript的ci * refactor: 重构项目,去除typescript * feat: 加入ws 开发依赖等(#13) * fix: 修复无法握手,host=>hostName * fix: 修复无法握手 --- src/index.js | 5 +++-- src/websocket.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 0457ac2..f19c44f 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,7 @@ const YuFlux = require("./websocket"); const yuFlux = new YuFlux("http://localhost:8000"); -yuFlux.on("upgrade", (res, socket, head) => { - console.error("res.headers"); + +yuFlux.on("upgrade", (res) => { + console.error(res.headers, "res.headers"); }); diff --git a/src/websocket.js b/src/websocket.js index e044e2c..a3c630c 100644 --- a/src/websocket.js +++ b/src/websocket.js @@ -97,7 +97,7 @@ const initWebSocketClient = (websocket, address, protocols, options) => { const defaultPort = isSecure ? 443 : 80; opts.port = parseUrl.port || defaultPort; //处理ipv6 - opts.host = parseUrl.host.startsWith("[") ? parseUrl.host.slice(1, -1) : parseUrl.host; + opts.host = parseUrl.host.startsWith("[") ? parseUrl.hostName.slice(1, -1) : parseUrl.hostName; //请求头 opts.headers = { ...opts.headers, From be8eb2a3e167a13402e195d26e30be676b46134a Mon Sep 17 00:00:00 2001 From: yuhao <76569582+yuhao423@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:41:24 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20upgrade=E5=9B=9E=E8=B0=83=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E7=9A=84=E5=AE=9E=E7=8E=B0=20(#17)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: test * sv * fewngo * 3223 * chore: 加入commit提交规范 * chore: 优化commit规范 * workflow: 增加ci检测及加入pr模板 * fix: 修复pnpm format引起的ci问题 * fix: 修复pnpm lint引起的ci问题 * fix: 修复pnpm lint引起的ci问题 * feat: 初始化websocket客户端 * fix: 修改eslint规则,优化websocket(#6) * ci: 去除typescript的ci * refactor: 重构项目,去除typescript * feat: 加入ws 开发依赖等(#13) * fix: 修复无法握手,host=>hostName * fix: 修复无法握手 * feat: upgrade回调函数的实现 --- src/constant.js | 2 + src/websocket.js | 95 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/constant.js b/src/constant.js index 4d980fb..f3273e6 100644 --- a/src/constant.js +++ b/src/constant.js @@ -5,4 +5,6 @@ const readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"]; module.exports = { protocolVersions, readyStates, + //这个GUID只能是这个,不能是其他值 + GUID: "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", }; diff --git a/src/websocket.js b/src/websocket.js index a3c630c..4837f70 100644 --- a/src/websocket.js +++ b/src/websocket.js @@ -1,9 +1,9 @@ const http = require("http"); const EventEmitter = require("events"); const { URL } = require("url"); -const { randomBytes } = require("crypto"); +const { randomBytes, createHash } = require("crypto"); -const { protocolVersions, readyStates } = require("./constant"); +const { protocolVersions, readyStates, GUID } = require("./constant"); class YuFlux extends EventEmitter { constructor(address, protocols, options) { @@ -13,7 +13,9 @@ class YuFlux extends EventEmitter { if (address !== undefined) { this._isServer = false; this._redirect = 0; - + // 加入socket,tcp + this._socket = null; + this._protocol = ""; if (protocols === undefined || null) { protocols = []; } @@ -23,6 +25,18 @@ class YuFlux extends EventEmitter { this._isServer = true; } } + + /** + * @private + */ + emitClose() {} + + /** + * @param {Duplex} socket + * @param {Buffer} head + * @param {Object} options + */ + setSocket(socket, head, option) {} } module.exports = YuFlux; @@ -149,13 +163,72 @@ const initWebSocketClient = (websocket, address, protocols, options) => { req.on("error", (err) => { req = websocket._req = null; - emitErrorAndClose(); + emitErrorAndClose(websocket, err); }); //todo respose 重定向 req.on("upgrade", (res, socket, head) => { websocket.emit("upgrade", res); + + if (websocket._readyState !== readyStates[0]) { + return; + } + //http请求回来了,就置空req + req = websocket._req = null; + + const upgrade = res.headers.upgrade; + // console.log(res.headers, "res.headers"); + //请求头不对 + if (upgrade === undefined || upgrade.toLowerCase() !== "websocket") { + abortHandshake(websocket, socket, "不正确的请求头"); + return; + } + + //解密,使用sha1算法 + //定义GUID(全局唯一标识符)摘要,可以是一个固定值或动态生成,从而生成摘要,最终转化成base64 + const digest = createHash("sha1") + .update(key + GUID) + .digest("base64"); + + if (res.headers["sec-websocket-accept"] !== digest) { + abortHandshake(websocket, socket, "不正确的 sec-websocket-key 请求头"); + return; + } + + //子协议的处理 + const serverProtocol = res.headers["sec-websocket-protocol"]; + let protocolError; + + if (serverProtocol !== undefined) { + //todo 更细的error划分 + protocolError = "暂不支持子协议"; + } + + if (protocolError) { + abortHandshake(websocket, socket, protocolError); + return; + } + + if (serverProtocol) websocket._protocol = serverProtocol; + + //处理sec-websocket-extensions,扩展 + const secWebSocketExtensions = res.headers["sec-websocket-extensions"]; + if (secWebSocketExtensions !== undefined) { + //todo 更细的error划分 + const message = "暂不支持websocket扩展协议"; + abortHandshake(websocket, socket, message); + return; + } + + //握手结束,正式tcp连接(socket) + //setSocket + websocket.setSocket(socket, head, { + allowSynchronousEvents: opts.allowSynchronousEvents, + generateMask: opts.generateMask, + maxPayload: opts.maxPayload, + skipUTF8Validation: opts.skipUTF8Validation, + }); }); if (opts.finishRequest) { @@ -166,6 +239,16 @@ const initWebSocketClient = (websocket, address, protocols, options) => { }; //todo 完善 emitErrorAndClose 函数 -const emitErrorAndClose = (err) => { - console.error(err, "err"); +/** + * @param {websocket} websocket websocket实例 + * @param {*} err + * + */ +const emitErrorAndClose = (websocket, err) => { + //1. 改变websocket的状态 + websocket._readyState = readyStates[3]; + //2. emit error + websocket.emit("error", err); + //3. 真正的emitClose函数 + websocket.emitClose(); };