UNPKG

@stomp/stompjs

Version:

STOMP client for Javascript and Typescript

171 lines 5.55 kB
import { BYTE } from './byte.js'; /** * Frame class represents a STOMP frame. * * @internal */ export class FrameImpl { /** * Frame constructor. `command`, `headers` and `body` are available as properties. * * @internal */ constructor(params) { const { command, headers, body, binaryBody, escapeHeaderValues, skipContentLengthHeader, } = params; this.command = command; this.headers = Object.assign({}, headers || {}); if (binaryBody) { this._binaryBody = binaryBody; this.isBinaryBody = true; } else { this._body = body || ''; this.isBinaryBody = false; } this.escapeHeaderValues = escapeHeaderValues || false; this.skipContentLengthHeader = skipContentLengthHeader || false; } /** * body of the frame */ get body() { if (!this._body && this.isBinaryBody) { this._body = new TextDecoder().decode(this._binaryBody); } return this._body || ''; } /** * body as Uint8Array */ get binaryBody() { if (!this._binaryBody && !this.isBinaryBody) { this._binaryBody = new TextEncoder().encode(this._body); } // At this stage it will definitely have a valid value return this._binaryBody; } /** * deserialize a STOMP Frame from raw data. * * @internal */ static fromRawFrame(rawFrame, escapeHeaderValues) { const headers = {}; const trim = (str) => str.replace(/^\s+|\s+$/g, ''); // In case of repeated headers, as per standards, first value need to be used for (const header of rawFrame.headers.reverse()) { const idx = header.indexOf(':'); const key = trim(header[0]); let value = trim(header[1]); if (escapeHeaderValues && rawFrame.command !== 'CONNECT' && rawFrame.command !== 'CONNECTED') { value = FrameImpl.hdrValueUnEscape(value); } headers[key] = value; } return new FrameImpl({ command: rawFrame.command, headers, binaryBody: rawFrame.binaryBody, escapeHeaderValues, }); } /** * @internal */ toString() { return this.serializeCmdAndHeaders(); } /** * serialize this Frame in a format suitable to be passed to WebSocket. * If the body is string the output will be string. * If the body is binary (i.e. of type Unit8Array) it will be serialized to ArrayBuffer. * * @internal */ serialize() { const cmdAndHeaders = this.serializeCmdAndHeaders(); if (this.isBinaryBody) { return FrameImpl.toUnit8Array(cmdAndHeaders, this._binaryBody).buffer; } else { return cmdAndHeaders + this._body + BYTE.NULL; } } serializeCmdAndHeaders() { const lines = [this.command]; if (this.skipContentLengthHeader) { delete this.headers['content-length']; } for (const name of Object.keys(this.headers || {})) { const value = this.headers[name]; if (this.escapeHeaderValues && this.command !== 'CONNECT' && this.command !== 'CONNECTED') { lines.push(`${name}:${FrameImpl.hdrValueEscape(`${value}`)}`); } else { lines.push(`${name}:${value}`); } } if (this.isBinaryBody || (!this.isBodyEmpty() && !this.skipContentLengthHeader)) { lines.push(`content-length:${this.bodyLength()}`); } return lines.join(BYTE.LF) + BYTE.LF + BYTE.LF; } isBodyEmpty() { return this.bodyLength() === 0; } bodyLength() { const binaryBody = this.binaryBody; return binaryBody ? binaryBody.length : 0; } /** * Compute the size of a UTF-8 string by counting its number of bytes * (and not the number of characters composing the string) */ static sizeOfUTF8(s) { return s ? new TextEncoder().encode(s).length : 0; } static toUnit8Array(cmdAndHeaders, binaryBody) { const uint8CmdAndHeaders = new TextEncoder().encode(cmdAndHeaders); const nullTerminator = new Uint8Array([0]); const uint8Frame = new Uint8Array(uint8CmdAndHeaders.length + binaryBody.length + nullTerminator.length); uint8Frame.set(uint8CmdAndHeaders); uint8Frame.set(binaryBody, uint8CmdAndHeaders.length); uint8Frame.set(nullTerminator, uint8CmdAndHeaders.length + binaryBody.length); return uint8Frame; } /** * Serialize a STOMP frame as per STOMP standards, suitable to be sent to the STOMP broker. * * @internal */ static marshall(params) { const frame = new FrameImpl(params); return frame.serialize(); } /** * Escape header values */ static hdrValueEscape(str) { return str .replace(/\\/g, '\\\\') .replace(/\r/g, '\\r') .replace(/\n/g, '\\n') .replace(/:/g, '\\c'); } /** * UnEscape header values */ static hdrValueUnEscape(str) { return str .replace(/\\r/g, '\r') .replace(/\\n/g, '\n') .replace(/\\c/g, ':') .replace(/\\\\/g, '\\'); } } //# sourceMappingURL=frame-impl.js.map