Skip to content

Commit

Permalink
Disable LOCAL INFILE to automatically read from local fs. Always requ…
Browse files Browse the repository at this point in the history
…ire userspace code to read file
  • Loading branch information
Andrey Sidorov authored and Andrey Sidorov committed Oct 13, 2019
1 parent d0e70ac commit 4e448e0
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 21 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ lib-cov
*.gz
.DS_Store
.idea/
.npmrc
mysqldata/

tmp
Expand Down
12 changes: 12 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
2.0.0-alpha1
- MAJOR: new `authPlugins` api replacing
`authSwitchHandler`, added caching_sha2_password
and mysql_native_password as default plugins.
Added tests for mysql 8 and ssl. Mysql 8 server
now supported with default settings. #1021, #906, #991
- MAJOR: LOCAL INFILE does not write to local
fs now and requires `infileStreamFactory` option
- Update to 2019 CA Amazon RDS certificates #1032
- Update SSL Profile for AWS Serverless Aurora #1026
- fix pool ignoring namedPlaceholders config #1022

1.7.0
- Fix crashing when session info packet does not
start with length-coded string #1004, #989
Expand Down
25 changes: 10 additions & 15 deletions lib/commands/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,31 +113,25 @@ class Query extends Command {
return this.doneInsert(rs);
}
if (this._fieldCount === null) {
this._localStream = this._findOrCreateReadStream(rs.infileName);
// start streaming, after last packet expect OK
// http://dev.mysql.com/doc/internals/en/com-query-response.html#local-infile-data
this._streamLocalInfile(connection);
return this.infileOk;
return this._streamLocalInfile(connection, rs.infileName);
}
this._receivedFieldsCount = 0;
this._rows.push([]);
this._fields.push([]);
return this.readField;
}

// some code taken from https://github.com/mysqljs/mysql/pull/668
_findOrCreateReadStream(path) {
_streamLocalInfile(connection, path) {
if (this._streamFactory) {
return this._streamFactory(path);
this._localStream = this._streamFactory(path);
} else {
this._localStreamError = new Error(
`As a result of LOCAL INFILE command server wants to read ${path} file, but as of v2.0 you must provide streamFactory option returning ReadStream.`
);
connection.writePacket(EmptyPacket);
return this.infileOk;
}
return fs.createReadStream(path, {
flag: 'r',
encoding: null,
autoClose: true
});
}

_streamLocalInfile(connection) {
const onConnectionError = () => {
this._unpipeStream();
};
Expand Down Expand Up @@ -176,6 +170,7 @@ class Query extends Command {
this._localStream.on('end', onEnd);
this._localStream.on('error', onError);
connection.once('error', onConnectionError);
return this.infileOk;
}

readField(packet, connection) {
Expand Down
23 changes: 17 additions & 6 deletions test/integration/connection/test-load-infile.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const common = require('../../common');
const connection = common.createConnection();
const assert = require('assert');
const fs = require('fs');

const table = 'load_data_test';
connection.query('SET GLOBAL local_infile = true', assert.ifError);
Expand All @@ -22,12 +23,19 @@ const sql =
`FIELDS TERMINATED BY ? (id, title)`;

let ok;
connection.query(sql, [path, ','], (err, _ok) => {
if (err) {
throw err;
connection.query(
{
sql,
values: [path, ','],
infileStreamFactory: () => fs.createReadStream(path)
},
(err, _ok) => {
if (err) {
throw err;
}
ok = _ok;
}
ok = _ok;
});
);

let rows;
connection.query(`SELECT * FROM ${table}`, (err, _rows) => {
Expand Down Expand Up @@ -82,7 +90,10 @@ process.on('exit', () => {
assert.equal(rows[0].id, 1);
assert.equal(rows[0].title, 'Hello World');

assert.equal(loadErr.code, 'ENOENT');
assert.equal(
loadErr.message,
`As a result of LOCAL INFILE commandgit st server wants to read /does_not_exist.csv file, but as of v2.0 you must provide streamFactory option returning ReadStream.`
);
assert.equal(loadResult.affectedRows, 0);

assert.equal(streamResult.affectedRows, 2);
Expand Down

0 comments on commit 4e448e0

Please sign in to comment.