aboutsummaryrefslogtreecommitdiff
path: root/node_modules/mysql2/lib/packet_parser.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/mysql2/lib/packet_parser.js')
-rw-r--r--node_modules/mysql2/lib/packet_parser.js195
1 files changed, 195 insertions, 0 deletions
diff --git a/node_modules/mysql2/lib/packet_parser.js b/node_modules/mysql2/lib/packet_parser.js
new file mode 100644
index 0000000..1899e56
--- /dev/null
+++ b/node_modules/mysql2/lib/packet_parser.js
@@ -0,0 +1,195 @@
+'use strict';
+
+const Packet = require('./packets/packet.js');
+
+const MAX_PACKET_LENGTH = 16777215;
+
+function readPacketLength(b, off) {
+ const b0 = b[off];
+ const b1 = b[off + 1];
+ const b2 = b[off + 2];
+ if (b1 + b2 === 0) {
+ return b0;
+ }
+ return b0 + (b1 << 8) + (b2 << 16);
+}
+
+class PacketParser {
+ constructor(onPacket, packetHeaderLength) {
+ // 4 for normal packets, 7 for comprssed protocol packets
+ if (typeof packetHeaderLength === 'undefined') {
+ packetHeaderLength = 4;
+ }
+ // array of last payload chunks
+ // only used when current payload is not complete
+ this.buffer = [];
+ // total length of chunks on buffer
+ this.bufferLength = 0;
+ this.packetHeaderLength = packetHeaderLength;
+ // incomplete header state: number of header bytes received
+ this.headerLen = 0;
+ // expected payload length
+ this.length = 0;
+ this.largePacketParts = [];
+ this.firstPacketSequenceId = 0;
+ this.onPacket = onPacket;
+ this.execute = PacketParser.prototype.executeStart;
+ this._flushLargePacket =
+ packetHeaderLength === 7
+ ? this._flushLargePacket7
+ : this._flushLargePacket4;
+ }
+
+ _flushLargePacket4() {
+ const numPackets = this.largePacketParts.length;
+ this.largePacketParts.unshift(Buffer.from([0, 0, 0, 0])); // insert header
+ const body = Buffer.concat(this.largePacketParts);
+ const packet = new Packet(this.firstPacketSequenceId, body, 0, body.length);
+ this.largePacketParts.length = 0;
+ packet.numPackets = numPackets;
+ this.onPacket(packet);
+ }
+
+ _flushLargePacket7() {
+ const numPackets = this.largePacketParts.length;
+ this.largePacketParts.unshift(Buffer.from([0, 0, 0, 0, 0, 0, 0])); // insert header
+ const body = Buffer.concat(this.largePacketParts);
+ this.largePacketParts.length = 0;
+ const packet = new Packet(this.firstPacketSequenceId, body, 0, body.length);
+ packet.numPackets = numPackets;
+ this.onPacket(packet);
+ }
+
+ executeStart(chunk) {
+ let start = 0;
+ const end = chunk.length;
+ while (end - start >= 3) {
+ this.length = readPacketLength(chunk, start);
+ if (end - start >= this.length + this.packetHeaderLength) {
+ // at least one full packet
+ const sequenceId = chunk[start + 3];
+ if (
+ this.length < MAX_PACKET_LENGTH &&
+ this.largePacketParts.length === 0
+ ) {
+ this.onPacket(
+ new Packet(
+ sequenceId,
+ chunk,
+ start,
+ start + this.packetHeaderLength + this.length
+ )
+ );
+ } else {
+ // first large packet - remember it's id
+ if (this.largePacketParts.length === 0) {
+ this.firstPacketSequenceId = sequenceId;
+ }
+ this.largePacketParts.push(
+ chunk.slice(
+ start + this.packetHeaderLength,
+ start + this.packetHeaderLength + this.length
+ )
+ );
+ if (this.length < MAX_PACKET_LENGTH) {
+ this._flushLargePacket();
+ }
+ }
+ start += this.packetHeaderLength + this.length;
+ } else {
+ // payload is incomplete
+ this.buffer = [chunk.slice(start + 3, end)];
+ this.bufferLength = end - start - 3;
+ this.execute = PacketParser.prototype.executePayload;
+ return;
+ }
+ }
+ if (end - start > 0) {
+ // there is start of length header, but it's not full 3 bytes
+ this.headerLen = end - start; // 1 or 2 bytes
+ this.length = chunk[start];
+ if (this.headerLen === 2) {
+ this.length = chunk[start] + (chunk[start + 1] << 8);
+ this.execute = PacketParser.prototype.executeHeader3;
+ } else {
+ this.execute = PacketParser.prototype.executeHeader2;
+ }
+ }
+ }
+
+ executePayload(chunk) {
+ let start = 0;
+ const end = chunk.length;
+ const remainingPayload =
+ this.length - this.bufferLength + this.packetHeaderLength - 3;
+ if (end - start >= remainingPayload) {
+ // last chunk for payload
+ const payload = Buffer.allocUnsafe(this.length + this.packetHeaderLength);
+ let offset = 3;
+ for (let i = 0; i < this.buffer.length; ++i) {
+ this.buffer[i].copy(payload, offset);
+ offset += this.buffer[i].length;
+ }
+ chunk.copy(payload, offset, start, start + remainingPayload);
+ const sequenceId = payload[3];
+ if (
+ this.length < MAX_PACKET_LENGTH &&
+ this.largePacketParts.length === 0
+ ) {
+ this.onPacket(
+ new Packet(
+ sequenceId,
+ payload,
+ 0,
+ this.length + this.packetHeaderLength
+ )
+ );
+ } else {
+ // first large packet - remember it's id
+ if (this.largePacketParts.length === 0) {
+ this.firstPacketSequenceId = sequenceId;
+ }
+ this.largePacketParts.push(
+ payload.slice(
+ this.packetHeaderLength,
+ this.packetHeaderLength + this.length
+ )
+ );
+ if (this.length < MAX_PACKET_LENGTH) {
+ this._flushLargePacket();
+ }
+ }
+ this.buffer = [];
+ this.bufferLength = 0;
+ this.execute = PacketParser.prototype.executeStart;
+ start += remainingPayload;
+ if (end - start > 0) {
+ return this.execute(chunk.slice(start, end));
+ }
+ } else {
+ this.buffer.push(chunk);
+ this.bufferLength += chunk.length;
+ }
+ return null;
+ }
+
+ executeHeader2(chunk) {
+ this.length += chunk[0] << 8;
+ if (chunk.length > 1) {
+ this.length += chunk[1] << 16;
+ this.execute = PacketParser.prototype.executePayload;
+ return this.executePayload(chunk.slice(2));
+ }
+ this.execute = PacketParser.prototype.executeHeader3;
+
+ return null;
+ }
+
+ executeHeader3(chunk) {
+ this.length += chunk[0] << 16;
+ this.execute = PacketParser.prototype.executePayload;
+ return this.executePayload(chunk.slice(1));
+ }
+}
+
+module.exports = PacketParser;