| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 | "use strict";var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }    return new (P || (P = Promise))(function (resolve, reject) {        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }        step((generator = generator.apply(thisArg, _arguments || [])).next());    });};var __importDefault = (this && this.__importDefault) || function (mod) {    return (mod && mod.__esModule) ? mod : { "default": mod };};Object.defineProperty(exports, "__esModule", { value: true });const test_buffers_1 = __importDefault(require("./testing/test-buffers"));const buffer_list_1 = __importDefault(require("./testing/buffer-list"));const _1 = require(".");const assert_1 = __importDefault(require("assert"));const stream_1 = require("stream");var authOkBuffer = test_buffers_1.default.authenticationOk();var paramStatusBuffer = test_buffers_1.default.parameterStatus('client_encoding', 'UTF8');var readyForQueryBuffer = test_buffers_1.default.readyForQuery();var backendKeyDataBuffer = test_buffers_1.default.backendKeyData(1, 2);var commandCompleteBuffer = test_buffers_1.default.commandComplete('SELECT 3');var parseCompleteBuffer = test_buffers_1.default.parseComplete();var bindCompleteBuffer = test_buffers_1.default.bindComplete();var portalSuspendedBuffer = test_buffers_1.default.portalSuspended();var addRow = function (bufferList, name, offset) {    return bufferList        .addCString(name) // field name        .addInt32(offset++) // table id        .addInt16(offset++) // attribute of column number        .addInt32(offset++) // objectId of field's data type        .addInt16(offset++) // datatype size        .addInt32(offset++) // type modifier        .addInt16(0); // format code, 0 => text};var row1 = {    name: 'id',    tableID: 1,    attributeNumber: 2,    dataTypeID: 3,    dataTypeSize: 4,    typeModifier: 5,    formatCode: 0,};var oneRowDescBuff = test_buffers_1.default.rowDescription([row1]);row1.name = 'bang';var twoRowBuf = test_buffers_1.default.rowDescription([    row1,    {        name: 'whoah',        tableID: 10,        attributeNumber: 11,        dataTypeID: 12,        dataTypeSize: 13,        typeModifier: 14,        formatCode: 0,    },]);var emptyRowFieldBuf = new buffer_list_1.default().addInt16(0).join(true, 'D');var emptyRowFieldBuf = test_buffers_1.default.dataRow([]);var oneFieldBuf = new buffer_list_1.default()    .addInt16(1) // number of fields    .addInt32(5) // length of bytes of fields    .addCString('test')    .join(true, 'D');var oneFieldBuf = test_buffers_1.default.dataRow(['test']);var expectedAuthenticationOkayMessage = {    name: 'authenticationOk',    length: 8,};var expectedParameterStatusMessage = {    name: 'parameterStatus',    parameterName: 'client_encoding',    parameterValue: 'UTF8',    length: 25,};var expectedBackendKeyDataMessage = {    name: 'backendKeyData',    processID: 1,    secretKey: 2,};var expectedReadyForQueryMessage = {    name: 'readyForQuery',    length: 5,    status: 'I',};var expectedCommandCompleteMessage = {    name: 'commandComplete',    length: 13,    text: 'SELECT 3',};var emptyRowDescriptionBuffer = new buffer_list_1.default()    .addInt16(0) // number of fields    .join(true, 'T');var expectedEmptyRowDescriptionMessage = {    name: 'rowDescription',    length: 6,    fieldCount: 0,    fields: [],};var expectedOneRowMessage = {    name: 'rowDescription',    length: 27,    fieldCount: 1,    fields: [        {            name: 'id',            tableID: 1,            columnID: 2,            dataTypeID: 3,            dataTypeSize: 4,            dataTypeModifier: 5,            format: 'text',        },    ],};var expectedTwoRowMessage = {    name: 'rowDescription',    length: 53,    fieldCount: 2,    fields: [        {            name: 'bang',            tableID: 1,            columnID: 2,            dataTypeID: 3,            dataTypeSize: 4,            dataTypeModifier: 5,            format: 'text',        },        {            name: 'whoah',            tableID: 10,            columnID: 11,            dataTypeID: 12,            dataTypeSize: 13,            dataTypeModifier: 14,            format: 'text',        },    ],};var emptyParameterDescriptionBuffer = new buffer_list_1.default()    .addInt16(0) // number of parameters    .join(true, 't');var oneParameterDescBuf = test_buffers_1.default.parameterDescription([1111]);var twoParameterDescBuf = test_buffers_1.default.parameterDescription([2222, 3333]);var expectedEmptyParameterDescriptionMessage = {    name: 'parameterDescription',    length: 6,    parameterCount: 0,    dataTypeIDs: [],};var expectedOneParameterMessage = {    name: 'parameterDescription',    length: 10,    parameterCount: 1,    dataTypeIDs: [1111],};var expectedTwoParameterMessage = {    name: 'parameterDescription',    length: 14,    parameterCount: 2,    dataTypeIDs: [2222, 3333],};var testForMessage = function (buffer, expectedMessage) {    it('recieves and parses ' + expectedMessage.name, () => __awaiter(this, void 0, void 0, function* () {        const messages = yield parseBuffers([buffer]);        const [lastMessage] = messages;        for (const key in expectedMessage) {            assert_1.default.deepEqual(lastMessage[key], expectedMessage[key]);        }    }));};var plainPasswordBuffer = test_buffers_1.default.authenticationCleartextPassword();var md5PasswordBuffer = test_buffers_1.default.authenticationMD5Password();var SASLBuffer = test_buffers_1.default.authenticationSASL();var SASLContinueBuffer = test_buffers_1.default.authenticationSASLContinue();var SASLFinalBuffer = test_buffers_1.default.authenticationSASLFinal();var expectedPlainPasswordMessage = {    name: 'authenticationCleartextPassword',};var expectedMD5PasswordMessage = {    name: 'authenticationMD5Password',    salt: Buffer.from([1, 2, 3, 4]),};var expectedSASLMessage = {    name: 'authenticationSASL',    mechanisms: ['SCRAM-SHA-256'],};var expectedSASLContinueMessage = {    name: 'authenticationSASLContinue',    data: 'data',};var expectedSASLFinalMessage = {    name: 'authenticationSASLFinal',    data: 'data',};var notificationResponseBuffer = test_buffers_1.default.notification(4, 'hi', 'boom');var expectedNotificationResponseMessage = {    name: 'notification',    processId: 4,    channel: 'hi',    payload: 'boom',};const parseBuffers = (buffers) => __awaiter(void 0, void 0, void 0, function* () {    const stream = new stream_1.PassThrough();    for (const buffer of buffers) {        stream.write(buffer);    }    stream.end();    const msgs = [];    yield _1.parse(stream, (msg) => msgs.push(msg));    return msgs;});describe('PgPacketStream', function () {    testForMessage(authOkBuffer, expectedAuthenticationOkayMessage);    testForMessage(plainPasswordBuffer, expectedPlainPasswordMessage);    testForMessage(md5PasswordBuffer, expectedMD5PasswordMessage);    testForMessage(SASLBuffer, expectedSASLMessage);    testForMessage(SASLContinueBuffer, expectedSASLContinueMessage);    // this exercises a found bug in the parser:    // https://github.com/brianc/node-postgres/pull/2210#issuecomment-627626084    // and adds a test which is deterministic, rather than relying on network packet chunking    const extendedSASLContinueBuffer = Buffer.concat([SASLContinueBuffer, Buffer.from([1, 2, 3, 4])]);    testForMessage(extendedSASLContinueBuffer, expectedSASLContinueMessage);    testForMessage(SASLFinalBuffer, expectedSASLFinalMessage);    // this exercises a found bug in the parser:    // https://github.com/brianc/node-postgres/pull/2210#issuecomment-627626084    // and adds a test which is deterministic, rather than relying on network packet chunking    const extendedSASLFinalBuffer = Buffer.concat([SASLFinalBuffer, Buffer.from([1, 2, 4, 5])]);    testForMessage(extendedSASLFinalBuffer, expectedSASLFinalMessage);    testForMessage(paramStatusBuffer, expectedParameterStatusMessage);    testForMessage(backendKeyDataBuffer, expectedBackendKeyDataMessage);    testForMessage(readyForQueryBuffer, expectedReadyForQueryMessage);    testForMessage(commandCompleteBuffer, expectedCommandCompleteMessage);    testForMessage(notificationResponseBuffer, expectedNotificationResponseMessage);    testForMessage(test_buffers_1.default.emptyQuery(), {        name: 'emptyQuery',        length: 4,    });    testForMessage(Buffer.from([0x6e, 0, 0, 0, 4]), {        name: 'noData',    });    describe('rowDescription messages', function () {        testForMessage(emptyRowDescriptionBuffer, expectedEmptyRowDescriptionMessage);        testForMessage(oneRowDescBuff, expectedOneRowMessage);        testForMessage(twoRowBuf, expectedTwoRowMessage);    });    describe('parameterDescription messages', function () {        testForMessage(emptyParameterDescriptionBuffer, expectedEmptyParameterDescriptionMessage);        testForMessage(oneParameterDescBuf, expectedOneParameterMessage);        testForMessage(twoParameterDescBuf, expectedTwoParameterMessage);    });    describe('parsing rows', function () {        describe('parsing empty row', function () {            testForMessage(emptyRowFieldBuf, {                name: 'dataRow',                fieldCount: 0,            });        });        describe('parsing data row with fields', function () {            testForMessage(oneFieldBuf, {                name: 'dataRow',                fieldCount: 1,                fields: ['test'],            });        });    });    describe('notice message', function () {        // this uses the same logic as error message        var buff = test_buffers_1.default.notice([{ type: 'C', value: 'code' }]);        testForMessage(buff, {            name: 'notice',            code: 'code',        });    });    testForMessage(test_buffers_1.default.error([]), {        name: 'error',    });    describe('with all the fields', function () {        var buffer = test_buffers_1.default.error([            {                type: 'S',                value: 'ERROR',            },            {                type: 'C',                value: 'code',            },            {                type: 'M',                value: 'message',            },            {                type: 'D',                value: 'details',            },            {                type: 'H',                value: 'hint',            },            {                type: 'P',                value: '100',            },            {                type: 'p',                value: '101',            },            {                type: 'q',                value: 'query',            },            {                type: 'W',                value: 'where',            },            {                type: 'F',                value: 'file',            },            {                type: 'L',                value: 'line',            },            {                type: 'R',                value: 'routine',            },            {                type: 'Z',                value: 'alsdkf',            },        ]);        testForMessage(buffer, {            name: 'error',            severity: 'ERROR',            code: 'code',            message: 'message',            detail: 'details',            hint: 'hint',            position: '100',            internalPosition: '101',            internalQuery: 'query',            where: 'where',            file: 'file',            line: 'line',            routine: 'routine',        });    });    testForMessage(parseCompleteBuffer, {        name: 'parseComplete',    });    testForMessage(bindCompleteBuffer, {        name: 'bindComplete',    });    testForMessage(bindCompleteBuffer, {        name: 'bindComplete',    });    testForMessage(test_buffers_1.default.closeComplete(), {        name: 'closeComplete',    });    describe('parses portal suspended message', function () {        testForMessage(portalSuspendedBuffer, {            name: 'portalSuspended',        });    });    describe('parses replication start message', function () {        testForMessage(Buffer.from([0x57, 0x00, 0x00, 0x00, 0x04]), {            name: 'replicationStart',            length: 4,        });    });    describe('copy', () => {        testForMessage(test_buffers_1.default.copyIn(0), {            name: 'copyInResponse',            length: 7,            binary: false,            columnTypes: [],        });        testForMessage(test_buffers_1.default.copyIn(2), {            name: 'copyInResponse',            length: 11,            binary: false,            columnTypes: [0, 1],        });        testForMessage(test_buffers_1.default.copyOut(0), {            name: 'copyOutResponse',            length: 7,            binary: false,            columnTypes: [],        });        testForMessage(test_buffers_1.default.copyOut(3), {            name: 'copyOutResponse',            length: 13,            binary: false,            columnTypes: [0, 1, 2],        });        testForMessage(test_buffers_1.default.copyDone(), {            name: 'copyDone',            length: 4,        });        testForMessage(test_buffers_1.default.copyData(Buffer.from([5, 6, 7])), {            name: 'copyData',            length: 7,            chunk: Buffer.from([5, 6, 7]),        });    });    // since the data message on a stream can randomly divide the incomming    // tcp packets anywhere, we need to make sure we can parse every single    // split on a tcp message    describe('split buffer, single message parsing', function () {        var fullBuffer = test_buffers_1.default.dataRow([null, 'bang', 'zug zug', null, '!']);        it('parses when full buffer comes in', function () {            return __awaiter(this, void 0, void 0, function* () {                const messages = yield parseBuffers([fullBuffer]);                const message = messages[0];                assert_1.default.equal(message.fields.length, 5);                assert_1.default.equal(message.fields[0], null);                assert_1.default.equal(message.fields[1], 'bang');                assert_1.default.equal(message.fields[2], 'zug zug');                assert_1.default.equal(message.fields[3], null);                assert_1.default.equal(message.fields[4], '!');            });        });        var testMessageRecievedAfterSpiltAt = function (split) {            return __awaiter(this, void 0, void 0, function* () {                var firstBuffer = Buffer.alloc(fullBuffer.length - split);                var secondBuffer = Buffer.alloc(fullBuffer.length - firstBuffer.length);                fullBuffer.copy(firstBuffer, 0, 0);                fullBuffer.copy(secondBuffer, 0, firstBuffer.length);                const messages = yield parseBuffers([fullBuffer]);                const message = messages[0];                assert_1.default.equal(message.fields.length, 5);                assert_1.default.equal(message.fields[0], null);                assert_1.default.equal(message.fields[1], 'bang');                assert_1.default.equal(message.fields[2], 'zug zug');                assert_1.default.equal(message.fields[3], null);                assert_1.default.equal(message.fields[4], '!');            });        };        it('parses when split in the middle', function () {            testMessageRecievedAfterSpiltAt(6);        });        it('parses when split at end', function () {            testMessageRecievedAfterSpiltAt(2);        });        it('parses when split at beginning', function () {            testMessageRecievedAfterSpiltAt(fullBuffer.length - 2);            testMessageRecievedAfterSpiltAt(fullBuffer.length - 1);            testMessageRecievedAfterSpiltAt(fullBuffer.length - 5);        });    });    describe('split buffer, multiple message parsing', function () {        var dataRowBuffer = test_buffers_1.default.dataRow(['!']);        var readyForQueryBuffer = test_buffers_1.default.readyForQuery();        var fullBuffer = Buffer.alloc(dataRowBuffer.length + readyForQueryBuffer.length);        dataRowBuffer.copy(fullBuffer, 0, 0);        readyForQueryBuffer.copy(fullBuffer, dataRowBuffer.length, 0);        var verifyMessages = function (messages) {            assert_1.default.strictEqual(messages.length, 2);            assert_1.default.deepEqual(messages[0], {                name: 'dataRow',                fieldCount: 1,                length: 11,                fields: ['!'],            });            assert_1.default.equal(messages[0].fields[0], '!');            assert_1.default.deepEqual(messages[1], {                name: 'readyForQuery',                length: 5,                status: 'I',            });        };        // sanity check        it('recieves both messages when packet is not split', function () {            return __awaiter(this, void 0, void 0, function* () {                const messages = yield parseBuffers([fullBuffer]);                verifyMessages(messages);            });        });        var splitAndVerifyTwoMessages = function (split) {            return __awaiter(this, void 0, void 0, function* () {                var firstBuffer = Buffer.alloc(fullBuffer.length - split);                var secondBuffer = Buffer.alloc(fullBuffer.length - firstBuffer.length);                fullBuffer.copy(firstBuffer, 0, 0);                fullBuffer.copy(secondBuffer, 0, firstBuffer.length);                const messages = yield parseBuffers([firstBuffer, secondBuffer]);                verifyMessages(messages);            });        };        describe('recieves both messages when packet is split', function () {            it('in the middle', function () {                return splitAndVerifyTwoMessages(11);            });            it('at the front', function () {                return Promise.all([                    splitAndVerifyTwoMessages(fullBuffer.length - 1),                    splitAndVerifyTwoMessages(fullBuffer.length - 4),                    splitAndVerifyTwoMessages(fullBuffer.length - 6),                ]);            });            it('at the end', function () {                return Promise.all([splitAndVerifyTwoMessages(8), splitAndVerifyTwoMessages(1)]);            });        });    });});//# sourceMappingURL=inbound-parser.test.js.map
 |