From 9f33cd28963a72d8fea0b1e99bb61ca9bec21a94 Mon Sep 17 00:00:00 2001 From: Dmitry Sharshakov Date: Tue, 5 Mar 2019 02:23:04 +0300 Subject: [PATCH] Refactor WebSockets (denoland/deno_std#173) * Use assert.equal instead of deprecated assertEqual * Replace let with const where possible * Add WebSocketMessage type * Use OpCode in WebSocketFrame * Use const where possible in WS * Separate sha1 tests, use const instead of let Original: https://github.com/denoland/deno_std/commit/385f866a545176261806d75184e2ef97fa0d5269 --- ws/mod.ts | 31 +++++++++++++++-------- ws/sha1.ts | 52 +++++++++++++++++++------------------- ws/sha1_test.ts | 11 ++++++--- ws/test.ts | 66 ++++++++++++++++++++++++------------------------- 4 files changed, 87 insertions(+), 73 deletions(-) diff --git a/ws/mod.ts b/ws/mod.ts index bb943c7142..6c827802bb 100644 --- a/ws/mod.ts +++ b/ws/mod.ts @@ -43,10 +43,16 @@ export function isWebSocketPongEvent(a): a is WebSocketPongEvent { return Array.isArray(a) && a[0] === "pong" && a[1] instanceof Uint8Array; } +export type WebSocketMessage = string | Uint8Array; + // TODO move this to common/util module export function append(a: Uint8Array, b: Uint8Array) { - if (a == null || !a.length) return b; - if (b == null || !b.length) return a; + if (a == null || !a.length) { + return b; + } + if (b == null || !b.length) { + return a; + } const output = new Uint8Array(a.length + b.length); output.set(a, 0); output.set(b, a.length); @@ -57,7 +63,7 @@ export class SocketClosedError extends Error {} export type WebSocketFrame = { isLastFrame: boolean; - opcode: number; + opcode: OpCode; mask?: Uint8Array; payload: Uint8Array; }; @@ -65,8 +71,8 @@ export type WebSocketFrame = { export type WebSocket = { readonly isClosed: boolean; receive(): AsyncIterableIterator; - send(data: string | Uint8Array): Promise; - ping(data?: string | Uint8Array): Promise; + send(data: WebSocketMessage): Promise; + ping(data?: WebSocketMessage): Promise; close(code: number, reason?: string): Promise; }; @@ -118,11 +124,12 @@ class WebSocketImpl implements WebSocket { case OpCode.Pong: yield ["pong", frame.payload] as WebSocketPongEvent; break; + default: } } } - async send(data: string | Uint8Array): Promise { + async send(data: WebSocketMessage): Promise { if (this.isClosed) { throw new SocketClosedError("socket has been closed"); } @@ -141,7 +148,7 @@ class WebSocketImpl implements WebSocket { ); } - async ping(data: string | Uint8Array): Promise { + async ping(data: WebSocketMessage): Promise { const payload = typeof data === "string" ? this.encoder.encode(data) : data; await writeFrame( { @@ -188,7 +195,10 @@ class WebSocketImpl implements WebSocket { } private ensureSocketClosed(): Error { - if (this.isClosed) return; + if (this.isClosed) { + return; + } + try { this.conn.close(); } catch (e) { @@ -203,7 +213,7 @@ export async function* receiveFrame( conn: Conn ): AsyncIterableIterator { let receiving = true; - let isLastFrame = true; + const isLastFrame = true; const reader = new BufReader(conn); while (receiving) { const frame = await readFrame(reader); @@ -241,12 +251,13 @@ export async function* receiveFrame( case OpCode.Pong: yield frame; break; + default: } } } export async function writeFrame(frame: WebSocketFrame, writer: Writer) { - let payloadLength = frame.payload.byteLength; + const payloadLength = frame.payload.byteLength; let header: Uint8Array; const hasMask = frame.mask ? 0x80 : 0; if (payloadLength < 126) { diff --git a/ws/sha1.ts b/ws/sha1.ts index 38101fb22e..c30a1e6ac9 100644 --- a/ws/sha1.ts +++ b/ws/sha1.ts @@ -61,12 +61,12 @@ export class Sha1 { notString = false; message = String(data); } - let code, - index = 0, - i, - start = this._start, - length = message.length || 0, - blocks = this._blocks; + let code; + let index = 0; + let i; + const start = this._start; + const length = message.length || 0; + const blocks = this._blocks; while (index < length) { if (this._hashed) { @@ -125,8 +125,8 @@ export class Sha1 { return; } this._finalized = true; - let blocks = this._blocks, - i = this._lastByteIndex; + const blocks = this._blocks; + const i = this._lastByteIndex; blocks[16] = this._block; blocks[i >> 2] |= EXTRA[i & 3]; this._block = blocks[16]; @@ -143,15 +143,13 @@ export class Sha1 { } hash() { - let a = this._h0, - b = this._h1, - c = this._h2, - d = this._h3, - e = this._h4; - let f, - j, - t, - blocks = this._blocks; + let a = this._h0; + let b = this._h1; + let c = this._h2; + let d = this._h3; + let e = this._h4; + let f, j, t; + const blocks = this._blocks; for (j = 16; j < 80; ++j) { t = blocks[j - 3] ^ blocks[j - 8] ^ blocks[j - 14] ^ blocks[j - 16]; @@ -276,11 +274,11 @@ export class Sha1 { hex() { this.finalize(); - let h0 = this._h0, - h1 = this._h1, - h2 = this._h2, - h3 = this._h3, - h4 = this._h4; + const h0 = this._h0; + const h1 = this._h1; + const h2 = this._h2; + const h3 = this._h3; + const h4 = this._h4; return ( HEX_CHARS[(h0 >> 28) & 0x0f] + @@ -333,11 +331,11 @@ export class Sha1 { digest() { this.finalize(); - let h0 = this._h0, - h1 = this._h1, - h2 = this._h2, - h3 = this._h3, - h4 = this._h4; + const h0 = this._h0; + const h1 = this._h1; + const h2 = this._h2; + const h3 = this._h3; + const h4 = this._h4; return [ (h0 >> 24) & 0xff, diff --git a/ws/sha1_test.ts b/ws/sha1_test.ts index 865e443e5e..fb6b7c13e3 100644 --- a/ws/sha1_test.ts +++ b/ws/sha1_test.ts @@ -3,16 +3,21 @@ import { assert, test } from "../testing/mod.ts"; import { Sha1 } from "./sha1.ts"; test(function testSha1() { - let sha1 = new Sha1(); + const sha1 = new Sha1(); sha1.update("abcde"); assert.equal(sha1.toString(), "03de6c570bfe24bfc328ccd7ca46b76eadaf4334"); +}); +test(function testSha1WithArray() { const data = Uint8Array.of(0x61, 0x62, 0x63, 0x64, 0x65); - sha1 = new Sha1(); + const sha1 = new Sha1(); sha1.update(data); assert.equal(sha1.toString(), "03de6c570bfe24bfc328ccd7ca46b76eadaf4334"); +}); - sha1 = new Sha1(); +test(function testSha1WithBuffer() { + const data = Uint8Array.of(0x61, 0x62, 0x63, 0x64, 0x65); + const sha1 = new Sha1(); sha1.update(data.buffer); assert.equal(sha1.toString(), "03de6c570bfe24bfc328ccd7ca46b76eadaf4334"); }); diff --git a/ws/test.ts b/ws/test.ts index 46ea1cb83c..79add17406 100644 --- a/ws/test.ts +++ b/ws/test.ts @@ -3,7 +3,7 @@ import "./sha1_test.ts"; const { Buffer } = Deno; import { BufReader } from "../io/bufio.ts"; -import { assert, assertEqual, test } from "../testing/mod.ts"; +import { test, assert } from "../testing/mod.ts"; import { acceptable, createSecAccept, @@ -18,10 +18,10 @@ test(async function testReadUnmaskedTextFrame() { new Buffer(new Uint8Array([0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f])) ); const frame = await readFrame(buf); - assertEqual(frame.opcode, OpCode.TextFrame); - assertEqual(frame.mask, undefined); - assertEqual(new Buffer(frame.payload).toString(), "Hello"); - assertEqual(frame.isLastFrame, true); + assert.equal(frame.opcode, OpCode.TextFrame); + assert.equal(frame.mask, undefined); + assert.equal(new Buffer(frame.payload).toString(), "Hello"); + assert.equal(frame.isLastFrame, true); }); test(async function testReadMakedTextFrame() { @@ -45,10 +45,10 @@ test(async function testReadMakedTextFrame() { ); const frame = await readFrame(buf); console.dir(frame); - assertEqual(frame.opcode, OpCode.TextFrame); + assert.equal(frame.opcode, OpCode.TextFrame); unmask(frame.payload, frame.mask); - assertEqual(new Buffer(frame.payload).toString(), "Hello"); - assertEqual(frame.isLastFrame, true); + assert.equal(new Buffer(frame.payload).toString(), "Hello"); + assert.equal(frame.isLastFrame, true); }); test(async function testReadUnmaskedSplittedTextFrames() { @@ -59,15 +59,15 @@ test(async function testReadUnmaskedSplittedTextFrames() { new Buffer(new Uint8Array([0x80, 0x02, 0x6c, 0x6f])) ); const [f1, f2] = await Promise.all([readFrame(buf1), readFrame(buf2)]); - assertEqual(f1.isLastFrame, false); - assertEqual(f1.mask, undefined); - assertEqual(f1.opcode, OpCode.TextFrame); - assertEqual(new Buffer(f1.payload).toString(), "Hel"); + assert.equal(f1.isLastFrame, false); + assert.equal(f1.mask, undefined); + assert.equal(f1.opcode, OpCode.TextFrame); + assert.equal(new Buffer(f1.payload).toString(), "Hel"); - assertEqual(f2.isLastFrame, true); - assertEqual(f2.mask, undefined); - assertEqual(f2.opcode, OpCode.Continue); - assertEqual(new Buffer(f2.payload).toString(), "lo"); + assert.equal(f2.isLastFrame, true); + assert.equal(f2.mask, undefined); + assert.equal(f2.opcode, OpCode.Continue); + assert.equal(new Buffer(f2.payload).toString(), "lo"); }); test(async function testReadUnmaksedPingPongFrame() { @@ -76,8 +76,8 @@ test(async function testReadUnmaksedPingPongFrame() { new Buffer(new Uint8Array([0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f])) ); const ping = await readFrame(buf); - assertEqual(ping.opcode, OpCode.Ping); - assertEqual(new Buffer(ping.payload).toString(), "Hello"); + assert.equal(ping.opcode, OpCode.Ping); + assert.equal(new Buffer(ping.payload).toString(), "Hello"); const buf2 = new BufReader( new Buffer( @@ -97,42 +97,42 @@ test(async function testReadUnmaksedPingPongFrame() { ) ); const pong = await readFrame(buf2); - assertEqual(pong.opcode, OpCode.Pong); + assert.equal(pong.opcode, OpCode.Pong); assert(pong.mask !== undefined); unmask(pong.payload, pong.mask); - assertEqual(new Buffer(pong.payload).toString(), "Hello"); + assert.equal(new Buffer(pong.payload).toString(), "Hello"); }); test(async function testReadUnmaksedBigBinaryFrame() { - let a = [0x82, 0x7e, 0x01, 0x00]; + const a = [0x82, 0x7e, 0x01, 0x00]; for (let i = 0; i < 256; i++) { a.push(i); } const buf = new BufReader(new Buffer(new Uint8Array(a))); const bin = await readFrame(buf); - assertEqual(bin.opcode, OpCode.BinaryFrame); - assertEqual(bin.isLastFrame, true); - assertEqual(bin.mask, undefined); - assertEqual(bin.payload.length, 256); + assert.equal(bin.opcode, OpCode.BinaryFrame); + assert.equal(bin.isLastFrame, true); + assert.equal(bin.mask, undefined); + assert.equal(bin.payload.length, 256); }); test(async function testReadUnmaskedBigBigBinaryFrame() { - let a = [0x82, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00]; + const a = [0x82, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00]; for (let i = 0; i < 0xffff; i++) { a.push(i); } const buf = new BufReader(new Buffer(new Uint8Array(a))); const bin = await readFrame(buf); - assertEqual(bin.opcode, OpCode.BinaryFrame); - assertEqual(bin.isLastFrame, true); - assertEqual(bin.mask, undefined); - assertEqual(bin.payload.length, 0xffff + 1); + assert.equal(bin.opcode, OpCode.BinaryFrame); + assert.equal(bin.isLastFrame, true); + assert.equal(bin.mask, undefined); + assert.equal(bin.payload.length, 0xffff + 1); }); test(async function testCreateSecAccept() { const nonce = "dGhlIHNhbXBsZSBub25jZQ=="; const d = createSecAccept(nonce); - assertEqual(d, "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="); + assert.equal(d, "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="); }); test(function testAcceptable() { @@ -142,7 +142,7 @@ test(function testAcceptable() { "sec-websocket-key": "aaa" }) }); - assertEqual(ret, true); + assert.equal(ret, true); }); const invalidHeaders = [ @@ -157,6 +157,6 @@ test(function testAcceptableInvalid() { const ret = acceptable({ headers: new Headers(pat) }); - assertEqual(ret, false); + assert.equal(ret, false); } });