From 6e63f0e2170cfd69992b7e691629e4565db0caa7 Mon Sep 17 00:00:00 2001 From: Patai Adam Date: Mon, 13 Feb 2017 05:20:41 +0100 Subject: [PATCH 01/12] Update readme (#1210) * Fix sample code in README * Fix typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 308e973..2901ee6 100644 --- a/README.md +++ b/README.md @@ -83,8 +83,8 @@ pool.connect(function(err, client, done) { return console.error('error fetching client from pool', err); } client.query('SELECT $1::int AS number', ['1'], function(err, result) { - //call `done()` to release the client back to the pool - done(); + //call `done(err)` to release the client back to the pool (or destroy it if there is an error) + done(err); if(err) { return console.error('error running query', err); From 5b6d883723d97936e309fdddfb3c438efcea84fd Mon Sep 17 00:00:00 2001 From: Charmander <~@charmander.me> Date: Sun, 12 Feb 2017 20:23:09 -0800 Subject: [PATCH 02/12] Remove broken tests with external dependency (#1209) Yikes. --- .../integration/client/heroku-pgpass-tests.js | 39 ------------------- test/integration/client/heroku-ssl-tests.js | 28 ------------- test/integration/client/heroku.pgpass | 1 - 3 files changed, 68 deletions(-) delete mode 100644 test/integration/client/heroku-pgpass-tests.js delete mode 100644 test/integration/client/heroku-ssl-tests.js delete mode 100644 test/integration/client/heroku.pgpass diff --git a/test/integration/client/heroku-pgpass-tests.js b/test/integration/client/heroku-pgpass-tests.js deleted file mode 100644 index 578342f..0000000 --- a/test/integration/client/heroku-pgpass-tests.js +++ /dev/null @@ -1,39 +0,0 @@ -var helper = require(__dirname + '/../test-helper'); - -// Path to the password file -var passfile = __dirname + '/heroku.pgpass'; - -// Export the path to the password file -process.env.PGPASSFILE = passfile; - -// Do a chmod 660, because git doesn't track those permissions -require('fs').chmodSync(passfile, 384); - -var pg = helper.pg; - -var host = 'ec2-107-20-224-218.compute-1.amazonaws.com'; -var database = 'db6kfntl5qhp2'; -var user = 'kwdzdnqpdiilfs'; - -var config = { - host: host, - database: database, - user: user, - ssl: true -}; - -test('uses password file when PGPASSFILE env variable is set', function() { - // connect & disconnect from heroku - pg.connect(config, assert.calls(function(err, client, done) { - assert.isNull(err); - client.query('SELECT NOW() as time', assert.success(function(res) { - assert(res.rows[0].time.getTime()); - - // cleanup ... remove the env variable - delete process.env.PGPASSFILE; - - done(); - pg.end(); - })) - })); -}); diff --git a/test/integration/client/heroku-ssl-tests.js b/test/integration/client/heroku-ssl-tests.js deleted file mode 100644 index dce3701..0000000 --- a/test/integration/client/heroku-ssl-tests.js +++ /dev/null @@ -1,28 +0,0 @@ -var helper = require(__dirname + '/../test-helper'); -var pg = helper.pg; - -var host = 'ec2-107-20-224-218.compute-1.amazonaws.com'; -var database = 'db6kfntl5qhp2'; -var user = 'kwdzdnqpdiilfs'; -var port = 5432; - -var config = { - host: host, - port: port, - database: database, - user: user, - password: 'uaZoSSHgi7mVM7kYaROtusClKu', - ssl: true -}; - -test('connection with config ssl = true', function() { - //connect & disconnect from heroku - pg.connect(config, assert.calls(function(err, client, done) { - assert.isNull(err); - client.query('SELECT NOW() as time', assert.success(function(res) { - assert(res.rows[0].time.getTime()); - done(); - pg.end(); - })) - })); -}); diff --git a/test/integration/client/heroku.pgpass b/test/integration/client/heroku.pgpass deleted file mode 100644 index 39bba52..0000000 --- a/test/integration/client/heroku.pgpass +++ /dev/null @@ -1 +0,0 @@ -ec2-107-20-224-218.compute-1.amazonaws.com:5432:db6kfntl5qhp2:kwdzdnqpdiilfs:uaZoSSHgi7mVM7kYaROtusClKu From 41017814d3c3195590bf23098aa9c63b3cb395de Mon Sep 17 00:00:00 2001 From: Charmander <~@charmander.me> Date: Tue, 21 Feb 2017 09:19:03 -0800 Subject: [PATCH 03/12] Avoid infinite loop on malformed message (#1208) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Avoid infinite loop on malformed message If handling of such messages is deemed unimportant, `indexOf` is still faster (~40%) and cleaner than a manual loop. Addresses #1048 to an extent. * Use indexOf fallback for Node ≤0.12 --- lib/connection.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/connection.js b/lib/connection.js index 6584c87..59247a7 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -13,6 +13,21 @@ var util = require('util'); var Writer = require('buffer-writer'); var Reader = require('packet-reader'); +var indexOf = + 'indexOf' in Buffer.prototype ? + function indexOf(buffer, value, start) { + return buffer.indexOf(value, start); + } : + function indexOf(buffer, value, start) { + for (var i = start, len = buffer.length; i < len; i++) { + if (buffer[i] === value) { + return i; + } + } + + return -1; + }; + var TEXT_MODE = 0; var BINARY_MODE = 1; var Connection = function(config) { @@ -647,8 +662,9 @@ Connection.prototype.readBytes = function(buffer, length) { Connection.prototype.parseCString = function(buffer) { var start = this.offset; - while(buffer[this.offset++] !== 0) { } - return buffer.toString(this.encoding, start, this.offset - 1); + var end = indexOf(buffer, 0, start); + this.offset = end + 1; + return buffer.toString(this.encoding, start, end); }; //end parsing methods module.exports = Connection; From 5cb38f58921ca84f3fd47c74fa7e895cee804918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Mon, 6 Mar 2017 18:04:16 +0100 Subject: [PATCH 04/12] Handle throws in type parsers (#1218) * Handle throws in type parsers * Fix throw in type parsers test for Node 0.x --- lib/query.js | 14 ++- .../unit/client/throw-in-type-parser-tests.js | 112 ++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 test/unit/client/throw-in-type-parser-tests.js diff --git a/lib/query.js b/lib/query.js index 36d52ba..19a8613 100644 --- a/lib/query.js +++ b/lib/query.js @@ -80,7 +80,19 @@ Query.prototype.handleRowDescription = function(msg) { }; Query.prototype.handleDataRow = function(msg) { - var row = this._result.parseRow(msg.fields); + var row; + + if (this._canceledDueToError) { + return; + } + + try { + row = this._result.parseRow(msg.fields); + } catch (err) { + this._canceledDueToError = err; + return; + } + this.emit('row', row, this._result); if (this._accumulateRows) { this._result.addRow(row); diff --git a/test/unit/client/throw-in-type-parser-tests.js b/test/unit/client/throw-in-type-parser-tests.js new file mode 100644 index 0000000..ed37113 --- /dev/null +++ b/test/unit/client/throw-in-type-parser-tests.js @@ -0,0 +1,112 @@ +var helper = require(__dirname + "/test-helper"); +var types = require('pg-types') + +test('handles throws in type parsers', function() { + var typeParserError = new Error('TEST: Throw in type parsers'); + + types.setTypeParser('special oid that will throw', function () { + throw typeParserError; + }); + + test('emits error', function() { + var handled; + var client = helper.client(); + var con = client.connection; + var query = client.query('whatever'); + + handled = con.emit('readyForQuery'); + assert.ok(handled, "should have handled ready for query"); + + con.emit('rowDescription',{ + fields: [{ + name: 'boom', + dataTypeID: 'special oid that will throw' + }] + }); + assert.ok(handled, "should have handled row description"); + + assert.emits(query, 'error', function(err) { + assert.equal(err, typeParserError); + }); + + handled = con.emit('dataRow', { fields: ["hi"] }); + assert.ok(handled, "should have handled first data row message"); + + handled = con.emit('commandComplete', { text: 'INSERT 31 1' }); + assert.ok(handled, "should have handled command complete"); + + handled = con.emit('readyForQuery'); + assert.ok(handled, "should have handled ready for query"); + }); + + test('calls callback with error', function() { + var handled; + + var callbackCalled = 0; + + var client = helper.client(); + var con = client.connection; + var query = client.query('whatever', assert.calls(function (err) { + callbackCalled += 1; + + assert.equal(callbackCalled, 1); + assert.equal(err, typeParserError); + })); + + handled = con.emit('readyForQuery'); + assert.ok(handled, "should have handled ready for query"); + + handled = con.emit('rowDescription',{ + fields: [{ + name: 'boom', + dataTypeID: 'special oid that will throw' + }] + }); + assert.ok(handled, "should have handled row description"); + + handled = con.emit('dataRow', { fields: ["hi"] }); + assert.ok(handled, "should have handled first data row message"); + + handled = con.emit('dataRow', { fields: ["hi"] }); + assert.ok(handled, "should have handled second data row message"); + + con.emit('commandComplete', { text: 'INSERT 31 1' }); + assert.ok(handled, "should have handled command complete"); + + handled = con.emit('readyForQuery'); + assert.ok(handled, "should have handled ready for query"); + }); + + test('rejects promise with error', function() { + var handled; + var client = helper.client(); + var con = client.connection; + var query = client.query('whatever'); + var queryPromise = query.promise(); + + handled = con.emit('readyForQuery'); + assert.ok(handled, "should have handled ready for query"); + + handled = con.emit('rowDescription',{ + fields: [{ + name: 'boom', + dataTypeID: 'special oid that will throw' + }] + }); + assert.ok(handled, "should have handled row description"); + + handled = con.emit('dataRow', { fields: ["hi"] }); + assert.ok(handled, "should have handled first data row message"); + + handled = con.emit('commandComplete', { text: 'INSERT 31 1' }); + assert.ok(handled, "should have handled command complete"); + + handled = con.emit('readyForQuery'); + assert.ok(handled, "should have handled ready for query"); + + queryPromise.catch(assert.calls(function (err) { + assert.equal(err, typeParserError); + })); + }); + +}); From ff5ceb4304535fe69cf472faac0bf61a057af253 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Mon, 6 Mar 2017 11:06:08 -0600 Subject: [PATCH 05/12] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 017e04c..db7c0be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pg", - "version": "6.1.2", + "version": "6.1.3", "description": "PostgreSQL client - pure javascript & libpq with the same API", "keywords": [ "postgres", From ce8f215c88583d82b0dde22743f4fdc688942d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Thu, 9 Mar 2017 22:05:26 +0100 Subject: [PATCH 06/12] Fix throw in type parsers when in prepared statement (#1242) --- lib/client.js | 2 +- lib/query.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/client.js b/lib/client.js index 770f353..a77e5d4 100644 --- a/lib/client.js +++ b/lib/client.js @@ -169,7 +169,7 @@ Client.prototype.connect = function(callback) { self.readyForQuery = true; self._pulseQueryQueue(); if(activeQuery) { - activeQuery.handleReadyForQuery(); + activeQuery.handleReadyForQuery(con); } }); diff --git a/lib/query.js b/lib/query.js index 19a8613..f627860 100644 --- a/lib/query.js +++ b/lib/query.js @@ -116,9 +116,9 @@ Query.prototype.handleEmptyQuery = function(con) { } }; -Query.prototype.handleReadyForQuery = function() { +Query.prototype.handleReadyForQuery = function(con) { if(this._canceledDueToError) { - return this.handleError(this._canceledDueToError); + return this.handleError(this._canceledDueToError, con); } if(this.callback) { this.callback(null, this._result); From 4fae7a9a7fc42fd25345a940ea9b8be2d4eaa012 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Thu, 9 Mar 2017 15:06:29 -0600 Subject: [PATCH 07/12] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index db7c0be..a2be721 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pg", - "version": "6.1.3", + "version": "6.1.4", "description": "PostgreSQL client - pure javascript & libpq with the same API", "keywords": [ "postgres", From 549404e21edd2a89c42ad7b9630e120c7b1cae1d Mon Sep 17 00:00:00 2001 From: Ryan Hamilton Date: Tue, 21 Mar 2017 01:00:57 +0800 Subject: [PATCH 08/12] Update README.md (#1247) grammar fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2901ee6..6bb0fe0 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ var config = { //this initializes a connection pool -//it will keep idle connections open for a 30 seconds +//it will keep idle connections open for 30 seconds //and set a limit of maximum 10 idle clients var pool = new pg.Pool(config); From 197f86f90decd7604249863460e828890f8632ba Mon Sep 17 00:00:00 2001 From: Magnus Hiie Date: Mon, 20 Mar 2017 19:01:41 +0200 Subject: [PATCH 09/12] Fix ECONNRESET error emitted after failed connect (#1230) On Windows, after a connect attempt has failed, an error event with ECONNRESET is emitted after the real connect error is propagated to the connect callback, because the connection is not in ending state (connection._ending) where ECONNRESET is ignored. This change ends the connection when connect has failed. This fixes #746. --- lib/client.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/client.js b/lib/client.js index a77e5d4..5d365da 100644 --- a/lib/client.js +++ b/lib/client.js @@ -182,6 +182,7 @@ Client.prototype.connect = function(callback) { if(!callback) { return self.emit('error', error); } + con.end(); // make sure ECONNRESET errors don't cause error events callback(error); callback = null; }); From 3de22ba991676534b366144c02145c015cca6125 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Mon, 20 Mar 2017 12:01:56 -0500 Subject: [PATCH 10/12] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a2be721..5d7b20c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pg", - "version": "6.1.4", + "version": "6.1.5", "description": "PostgreSQL client - pure javascript & libpq with the same API", "keywords": [ "postgres", From c0a381eab26e3e53711ba15e5a2c47f995beeaf9 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Sat, 12 Aug 2017 16:04:29 -0500 Subject: [PATCH 11/12] Fix vulnerability --- lib/result.js | 15 ++++++++------- package.json | 1 + .../integration/client/field-name-escape-tests.js | 10 ++++++++++ 3 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 test/integration/client/field-name-escape-tests.js diff --git a/lib/result.js b/lib/result.js index 463fbdb..2955d92 100644 --- a/lib/result.js +++ b/lib/result.js @@ -7,6 +7,7 @@ */ var types = require('pg-types'); +var escape = require('js-string-escape'); //result object returned from query //in the 'end' event and also @@ -75,13 +76,13 @@ Result.prototype.addRow = function(row) { var inlineParser = function(fieldName, i) { return "\nthis['" + - //fields containing single quotes will break - //the evaluated javascript unless they are escaped - //see https://github.com/brianc/node-postgres/issues/507 - //Addendum: However, we need to make sure to replace all - //occurences of apostrophes, not just the first one. - //See https://github.com/brianc/node-postgres/issues/934 - fieldName.replace(/'/g, "\\'") + + // fields containing single quotes will break + // the evaluated javascript unless they are escaped + // see https://github.com/brianc/node-postgres/issues/507 + // Addendum: However, we need to make sure to replace all + // occurences of apostrophes, not just the first one. + // See https://github.com/brianc/node-postgres/issues/934 + escape(fieldName) + "'] = " + "rowData[" + i + "] == null ? null : parsers[" + i + "](rowData[" + i + "]);"; }; diff --git a/package.json b/package.json index 5d7b20c..9c09ef5 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "main": "./lib", "dependencies": { "buffer-writer": "1.0.1", + "js-string-escape": "1.0.1", "packet-reader": "0.2.0", "pg-connection-string": "0.1.3", "pg-pool": "1.*", diff --git a/test/integration/client/field-name-escape-tests.js b/test/integration/client/field-name-escape-tests.js new file mode 100644 index 0000000..146ad1b --- /dev/null +++ b/test/integration/client/field-name-escape-tests.js @@ -0,0 +1,10 @@ +var pg = require('./test-helper').pg + +var sql = 'SELECT 1 AS "\\\'/*", 2 AS "\\\'*/\n + process.exit(-1)] = null;\n//"' + +var client = new pg.Client() +client.connect() +client.query(sql, function (err, res) { + if (err) throw err + client.end() +}) From b0a2fe45059ba9d2c6279695260dd0a61fee99dc Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Sat, 12 Aug 2017 16:26:37 -0500 Subject: [PATCH 12/12] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9c09ef5..5d9aef0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pg", - "version": "6.1.5", + "version": "6.1.6", "description": "PostgreSQL client - pure javascript & libpq with the same API", "keywords": [ "postgres",