1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-26 09:10:40 -05:00

Refactor WebSockets (#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
This commit is contained in:
Dmitry Sharshakov 2019-03-05 02:23:04 +03:00 committed by Ryan Dahl
parent 41bdd096f0
commit 385f866a54
4 changed files with 87 additions and 73 deletions

View file

@ -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<WebSocketEvent>;
send(data: string | Uint8Array): Promise<void>;
ping(data?: string | Uint8Array): Promise<void>;
send(data: WebSocketMessage): Promise<void>;
ping(data?: WebSocketMessage): Promise<void>;
close(code: number, reason?: string): Promise<void>;
};
@ -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<void> {
async send(data: WebSocketMessage): Promise<void> {
if (this.isClosed) {
throw new SocketClosedError("socket has been closed");
}
@ -141,7 +148,7 @@ class WebSocketImpl implements WebSocket {
);
}
async ping(data: string | Uint8Array): Promise<void> {
async ping(data: WebSocketMessage): Promise<void> {
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<WebSocketFrame> {
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) {

View file

@ -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,

View file

@ -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");
});

View file

@ -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);
}
});