= 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 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; } 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, "\\"); } } module.exports = { Frame: FrameImpl }; PK